Version in base suite: 8.1+1+ds1-1~deb13u1 Base version: jtreg8_8.1+1+ds1-1~deb13u1 Target version: jtreg8_8.3+1+ds1-2~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/j/jtreg8/jtreg8_8.1+1+ds1-1~deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/j/jtreg8/jtreg8_8.3+1+ds1-2~deb13u1.dsc /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jdec.bin |binary /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jdis.bin |binary /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/html-report-failed.png |binary /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/html-report-successful.png |binary jtreg8-8.3+1+ds1/CHANGELOG.md | 40 jtreg8-8.3+1+ds1/README.md | 9 jtreg8-8.3+1+ds1/asmtools/.github/workflows/maven.yaml | 47 jtreg8-8.3+1+ds1/asmtools/.gitignore | 24 jtreg8-8.3+1+ds1/asmtools/.hgtags | 7 jtreg8-8.3+1+ds1/asmtools/.jcheck/conf | 37 jtreg8-8.3+1+ds1/asmtools/LICENSE | 347 jtreg8-8.3+1+ds1/asmtools/README.html | 417 + jtreg8-8.3+1+ds1/asmtools/README.md | 23 jtreg8-8.3+1+ds1/asmtools/build/build.properties | 32 jtreg8-8.3+1+ds1/asmtools/build/build.xml | 397 jtreg8-8.3+1+ds1/asmtools/build/productinfo.properties | 31 jtreg8-8.3+1+ds1/asmtools/docs/Class00.jasm | 20 jtreg8-8.3+1+ds1/asmtools/docs/Class00.java | 5 jtreg8-8.3+1+ds1/asmtools/docs/Class00_1.jasm | 21 jtreg8-8.3+1+ds1/asmtools/docs/UsingTools.md | 337 jtreg8-8.3+1+ds1/asmtools/docs/jasm.html | 2257 +++++ jtreg8-8.3+1+ds1/asmtools/docs/jasm.md | 1950 ++++ jtreg8-8.3+1+ds1/asmtools/maven/mvngen.sh | 75 jtreg8-8.3+1+ds1/asmtools/maven/pom.xml.in | 113 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/Main.java | 122 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/FormatConsumer.java | 6 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/HexUtils.java | 86 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Pair.java | 55 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Range.java | 36 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/StringUtils.java | 361 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Triplet.java | 38 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Compiler.java | 42 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerConstants.java | 43 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerLogger.java | 258 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Decoder.java | 43 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/DecompilerLogger.java | 210 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/EMessageKind.java | 31 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Environment.java | 233 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ErrorMessage.java | 19 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/FormatError.java | 46 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ILogger.java | 122 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/NotImplementedException.java | 11 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/SyntaxError.java | 39 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Tool.java | 106 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ToolLogger.java | 188 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/TriFunction.java | 34 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ByteInput.java | 117 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/FileInput.java | 140 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StdinInput.java | 36 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StreamInput.java | 62 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StringInput.java | 39 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/TextInput.java | 51 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ToolInput.java | 67 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ByteOutput.java | 131 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/EscapedPrintStreamOutput.java | 52 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/FSOutput.java | 194 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/NamedToolOutput.java | 81 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/PrintWriterOutput.java | 83 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/StdoutOutput.java | 9 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/TextOutput.java | 154 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ToolOutput.java | 69 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualOutputStreamOutput.java | 115 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualStreamToolOutput.java | 58 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/NamedDualStreamToolOutput.java | 51 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/SingleDualOutputStreamOutput.java | 37 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StderrLog.java | 31 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StringLog.java | 85 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/CFVersion.java | 235 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ClassFileContext.java | 78 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EAttribute.java | 159 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ELocation.java | 46 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EModifier.java | 545 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/StackMap.java | 266 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/uEscWriter.java | 57 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/i18n.properties | 48 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AnnotationData.java | 111 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ArrayAttr.java | 86 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AttrData.java | 113 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/BootstrapMethodData.java | 120 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPTagVisitor.java | 133 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPVisitor.java | 65 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPXAttr.java | 49 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java | 58 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Checker.java | 318 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassData.java | 822 ++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassFileConst.java | 381 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CodeAttr.java | 547 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstCell.java | 134 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstValue.java | 94 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPool.java | 1071 ++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolDataVisitor.java | 69 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolIndexData.java | 69 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVector.java | 98 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVectorAttr.java | 184 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataWriter.java | 38 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DefaultAnnotationAttr.java | 59 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/EnclosingMethodAttr.java | 69 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ExceptionData.java | 70 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldData.java | 82 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldType.java | 60 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Indexer.java | 56 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/InnerClassData.java | 63 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Instr.java | 233 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmEnvironment.java | 229 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTokens.java | 547 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTool.java | 47 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LineNumberData.java | 58 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LoadableDescriptorsAttr.java | 48 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LocalVariableData.java | 146 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Main.java | 337 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MemberData.java | 212 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MethodData.java | 239 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ModuleAttr.java | 297 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NameInfo.java | 63 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NestMembersAttr.java | 43 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/OpcodeTables.java | 555 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAnnotation.java | 1165 ++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAttribute.java | 621 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseBase.java | 80 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseConstPool.java | 716 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseInstruction.java | 487 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Parser.java | 2870 +++++++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/PermittedSubclassesAttr.java | 43 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/RecordData.java | 112 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Scanner.java | 962 ++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceDebugExtensionAttr.java | 100 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceFileAttr.java | 89 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/StackMapData.java | 427 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SwitchTable.java | 175 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TableFormatModel.java | 107 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationData.java | 92 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTargetInfoData.java | 517 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypePathData.java | 80 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypes.java | 302 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/i18n.properties | 277 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/ByteBuffer.java | 133 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcodTokens.java | 275 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Jcoder.java | 774 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderEnvironment.java | 206 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderTool.java | 45 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Main.java | 288 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Scanner.java | 833 ++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/i18n.properties | 66 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/ClassData.java | 1496 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecEnvironment.java | 88 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecTool.java | 52 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/Main.java | 188 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/NestedByteArrayInputStream.java | 62 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/i18n.properties | 37 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationData.java | 154 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationElement.java | 420 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttrData.java | 121 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttributeData.java | 140 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/BootstrapMethodData.java | 210 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassArrayData.java | 137 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassData.java | 775 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/CodeData.java | 959 ++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ConstantPool.java | 1167 ++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Container.java | 163 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Element.java | 42 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/EnclosingMethodData.java | 64 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ExceptionData.java | 37 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/FieldData.java | 231 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Indenter.java | 545 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InnerClassData.java | 161 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InstructionAttr.java | 385 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisEnvironment.java | 61 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisTool.java | 46 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LineNumberData.java | 87 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LoadableDescriptorsData.java | 48 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalData.java | 89 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableData.java | 60 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableTypeData.java | 58 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Main.java | 314 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Measurable.java | 34 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MemberData.java | 357 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MethodData.java | 446 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleContent.java | 425 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleData.java | 247 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestHostData.java | 50 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestMembersData.java | 53 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Options.java | 206 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ParameterAnnotationData.java | 82 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/PermittedSubclassesData.java | 49 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Printable.java | 42 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/RecordData.java | 162 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SignatureData.java | 175 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceDebugExtensionData.java | 62 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceFileData.java | 58 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapData.java | 497 + jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapTable.java | 113 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TextLines.java | 56 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TrapData.java | 54 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TypeAnnotationData.java | 297 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utf8ArrayData.java | 57 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utils.java | 59 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/i18n.properties | 98 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Descriptor.java | 201 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/DescriptorException.java | 29 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Signature.java | 285 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Type.java | 382 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/I18NResourceBundle.java | 168 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/ProductInfo.java | 81 jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/productinfo.properties | 27 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/BootstrapMethodsAttributeTests.java | 83 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/Case7903791.java | 180 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample01.java | 69 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample02.java | 38 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/ConstantValue/ConstantValueAttributeTests.java | 400 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsTests.java | 182 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestHost/NestHostTests.java | 133 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestMembers/NestMembersTests.java | 167 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/PermittedSubclasses/PermittedSubclassesTests.java | 179 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExtensionTests.java | 96 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/StackMapTableTests.java | 163 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData.java | 210 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/InputOutputTests.java | 146 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/SequenceCallsTests.java | 268 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/data/TestedHelloWorld.java | 31 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/MultipleFilesInSingleJasmTest.java | 80 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902696/Tests.java | 112 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902820/Tests.java | 93 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903031/Tests.java | 85 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903405/Tests.java | 88 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903558/Tests.java | 106 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903976/Tests.java | 82 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903987/Tests.java | 94 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/package-info.java | 26 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jcoder/MultipleFilesInSingleJcoderTest.java | 41 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcod.java | 74 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcodTests.java | 44 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/MainTest.java | 110 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/case7902055/Tests.java | 108 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasm.java | 109 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasmTest.java | 55 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/MainTest.java | 180 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Action.java | 121 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/CompileActor.java | 116 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DebugHelper.java | 45 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DecodeActor.java | 113 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EAsmTool.java | 82 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EToolArguments.java | 78 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/FSAction.java | 139 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jasm.java | 48 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jcoder.java | 50 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdec.java | 56 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdis.java | 55 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/attributes/Attribute.java | 132 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutput.java | 181 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutputExtension.java | 92 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/BruteForceHelper.java | 217 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ClassPathClassWork.java | 37 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ThreeStringWriters.java | 55 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndBinResults.java | 41 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndReturn.java | 44 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndTextResults.java | 44 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/package-info.java | 26 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/script/TestScript.java | 105 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ITestRunner.java | 27 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ResultChecker.java | 98 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/TransformLoader.java | 430 + jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/AsmtoolsType.java | 73 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJasmConverter.java | 106 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJcodConverter.java | 100 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Clazz.java | 35 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Converter.java | 60 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jasm.java | 34 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JasmToClassConverter.java | 99 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jcod.java | 35 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JcodToClassConverter.java | 98 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Pipeline.java | 84 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/TestPipeline.java | 158 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/FileUtils.java | 99 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/StringUtils.java | 87 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/structure/ClassFile/ClassFileTests.java | 146 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerNegative.java | 45 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerPositive.java | 54 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtension_source.java | 48 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820Tests.java | 88 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259/BuildString.java | 34 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259Tests.java | 85 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/TestRunner.java | 54 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/data/Utf8Code_source.java | 68 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454Tests.java | 96 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/TestRunner.java | 108 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/CTestClass.java | 31 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.java | 31 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.java | 32 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260Tests.java | 135 jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/package-info.java | 33 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/abc.txt | 1 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1n.jcod | 69 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1p.jcod | 57 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1.jcod | 287 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jasm | 32 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jcod | 83 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t.jcod | 287 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t0p.jcod | 89 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1.jcod | 287 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m10p.jcod | 83 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t.jcod | 287 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t0p.jcod | 89 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1n.jcod | 75 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1p.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1.jcod | 252 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1n.jcod | 51 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1p.jcod | 131 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1.jcod | 692 + jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1t.jcod | 507 + jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1n.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1p.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1p.jcod | 72 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1n.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1p.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m1.jcod | 357 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m10p.jcod | 44 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m11n.jcod | 45 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m1.jcod | 362 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m10p.jcod | 44 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m11p.jcod | 44 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m12n.jcod | 45 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1n.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1p.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1n.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1p.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1n.jcod | 70 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1p.jcod | 70 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1n.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1p.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1n.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1p.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1n.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1p.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1n.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1p.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1n.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1p.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1n.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1p.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1n.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1p.jcod | 76 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1n.jcod | 103 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1p.jcod | 100 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1.jcod | 239 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1n.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1p.jcod | 71 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m1.jcod | 719 + jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m10p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m110p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m111n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m112n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m113n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m114n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m115p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m116n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m117n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m118n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m119n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m11n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m120p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m121n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m122n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m123n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m124n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m125n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m126n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m127n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m128n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m129n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m12n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m130p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m131n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m132n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m133n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m134n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m135n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m136n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m137n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m138n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m139n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m13n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m140p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m141n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m142n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m143n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m144n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m145n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m146n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m147n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m148n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m149n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m14n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m150p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m151n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m152n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m153n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m154n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m155n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m156n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m157n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m158n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m159n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m15p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m160p.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m16n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m17n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m18n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m19n.jcod | 73 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jasm | 119 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jcod | 175 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.t.jasm | 120 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.jasm | 49 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jasm | 174 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jcod | 326 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.t.jasm | 178 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jasm | 108 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jcod | 326 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/Test01.jasm | 12 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.g.jasm | 30 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jasm | 12 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jcod | 54 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test02.jasm | 14 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.g.t.jasm | 28 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jasm | 12 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jcod | 54 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test02.jasm | 99 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.g.t.jasm | 69 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jasm | 24 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jcod | 69 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test02.jasm | 99 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt01.jasm | 20 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt02.jasm | 19 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt03.jasm | 19 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jasm | 759 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jcod | 520 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.t.jasm | 791 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jasm | 612 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jcod | 520 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.t.jasm | 644 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData01.g.jasm | 759 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jasm | 768 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jcod | 510 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/ConstantPoolTestDummy.jasm | 98 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/EnclMethTest.jcod | 115 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/TestInterface01n01.jasm | 24 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/atrcod00402m1n.jcod | 74 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/module-info.jcod | 79 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/nonvoidinit.jasm | 31 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/stackmap00601m1n.jcod | 79 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/voidinit.jasm | 31 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.jasm | 432 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.t.jasm | 425 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902820/InvalidSourceDebugExtension.jcod | 90 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.g.jasm | 926 ++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.jasm | 361 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903405/ifge_overflow.jasm | 1530 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.g.jasm | 36 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.jasm | 20 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.g.jasm | 36 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.jasm | 20 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.g.jasm | 36 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.jasm | 20 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.g.jasm | 36 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.jasm | 21 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test00.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test01.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test02.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test03.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test04.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test05.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test06.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test07.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test08.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test09.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test10.jasm | 17 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903987/Test00.jasm | 49 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/clfacc00610m10p.jasm | 33 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/spinum00101m10p.jasm | 790 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/12.jcod | 128 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/bad.jcod | 69 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.g.jcod | 78 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.jcod | 78 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField00.jasm | 41 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField01.jasm | 42 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField02.jasm | 60 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField03.jasm | 42 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField04.jasm | 48 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile00.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile01.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile02.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile03.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile04.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile05.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile06.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile07.jasm | 41 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile08.jasm | 42 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile09.jasm | 43 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile10.jasm | 43 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile11.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile12.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile13.jasm | 39 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile14.jasm | 40 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile15.jasm | 40 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01.class.jcod | 195 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02.class.jcod | 195 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01.class.jcod | 203 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02.class.jcod | 451 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jasm | 97 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jcoder | 165 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jasm | 222 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jcod | 664 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jasm | 216 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jcod | 544 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jasm | 564 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jcod | 601 + jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jasm | 77 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jcod | 148 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jasm | 51 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jcod | 111 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jasm | 91 jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jcod | 174 jtreg8-8.3+1+ds1/debian/apiguardian/rules | 17 jtreg8-8.3+1+ds1/debian/asmtools/rules | 13 jtreg8-8.3+1+ds1/debian/changelog | 47 jtreg8-8.3+1+ds1/debian/control | 4 jtreg8-8.3+1+ds1/debian/copyright | 12 jtreg8-8.3+1+ds1/debian/gbp-export.sh | 2 jtreg8-8.3+1+ds1/debian/gbp-import.sh | 2 jtreg8-8.3+1+ds1/debian/junit5/generated/JRE.java | 410 + jtreg8-8.3+1+ds1/debian/junit5/junit-jupiter-api/build/generated/sources/jte/main/org/junit/jupiter/api/condition/JRE.java | 299 jtreg8-8.3+1+ds1/debian/junit5/rules | 6 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableImage.java | 191 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableKeyValuePairs.java | 221 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableLabels.java | 218 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableParagraph.java | 150 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutablePreFormattedOutput.java | 151 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableSection.java | 394 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableSubsections.java | 218 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/poms | 30 jtreg8-8.3+1+ds1/debian/opentest4j-reporting/rules | 16 jtreg8-8.3+1+ds1/debian/patches/codetools-7904105-proposed.patch | 42 jtreg8-8.3+1+ds1/debian/patches/codetools-7904106-proposed.patch | 102 jtreg8-8.3+1+ds1/debian/patches/codetools-7904107-proposed.patch | 38 jtreg8-8.3+1+ds1/debian/patches/codetools-7904157-proposed.patch | 18 jtreg8-8.3+1+ds1/debian/patches/fix_junit5_error_message.patch | 21 jtreg8-8.3+1+ds1/debian/patches/junit5-16-maven-build.patch | 101 jtreg8-8.3+1+ds1/debian/patches/junit5-17-backward-compatibility.patch | 69 jtreg8-8.3+1+ds1/debian/patches/opentest4j-reporting-01-gradle-compatibility.patch | 55 jtreg8-8.3+1+ds1/debian/patches/opentest4j-reporting-02-disable-immutables.patch | 158 jtreg8-8.3+1+ds1/debian/patches/series | 6 jtreg8-8.3+1+ds1/debian/rules | 4 jtreg8-8.3+1+ds1/debian/watch | 7 jtreg8-8.3+1+ds1/doc/building.md | 8 jtreg8-8.3+1+ds1/junit5/.github/FUNDING.yml | 8 jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/bug_report.md | 7 jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/config.yml | 8 jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/feature_request.md | 5 jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/question.md | 11 jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/task.md | 12 jtreg8-8.3+1+ds1/junit5/.github/PULL_REQUEST_TEMPLATE.md | 12 jtreg8-8.3+1+ds1/junit5/.github/actions/main-build/action.yml | 7 jtreg8-8.3+1+ds1/junit5/.github/actions/maven-central-user-token/action.yml | 17 jtreg8-8.3+1+ds1/junit5/.github/actions/run-gradle/action.yml | 7 jtreg8-8.3+1+ds1/junit5/.github/actions/setup-test-jdk/action.yml | 2 jtreg8-8.3+1+ds1/junit5/.github/renovate.json5 | 36 jtreg8-8.3+1+ds1/junit5/.github/scripts/checkBuildReproducibility.sh | 30 jtreg8-8.3+1+ds1/junit5/.github/scripts/waitForUrl.sh | 9 jtreg8-8.3+1+ds1/junit5/.github/workflows/close-inactive-issues.yml | 3 jtreg8-8.3+1+ds1/junit5/.github/workflows/codeql-analysis.yml | 48 jtreg8-8.3+1+ds1/junit5/.github/workflows/codeql.yml | 56 jtreg8-8.3+1+ds1/junit5/.github/workflows/combine-prs.yml | 16 jtreg8-8.3+1+ds1/junit5/.github/workflows/cross-version.yml | 41 jtreg8-8.3+1+ds1/junit5/.github/workflows/gradle-dependency-submission.yml | 16 jtreg8-8.3+1+ds1/junit5/.github/workflows/issue-labels.yml | 20 jtreg8-8.3+1+ds1/junit5/.github/workflows/label-opened-issues.yml | 30 jtreg8-8.3+1+ds1/junit5/.github/workflows/main.yml | 56 jtreg8-8.3+1+ds1/junit5/.github/workflows/ossf-scorecard.yml | 62 jtreg8-8.3+1+ds1/junit5/.github/workflows/release.yml | 267 jtreg8-8.3+1+ds1/junit5/.github/workflows/reproducible-build.yml | 11 jtreg8-8.3+1+ds1/junit5/.github/workflows/sanitize-closed-issues.yml | 80 jtreg8-8.3+1+ds1/junit5/.gitignore | 9 jtreg8-8.3+1+ds1/junit5/.idea/codeStyles/Project.xml | 1 jtreg8-8.3+1+ds1/junit5/CONTRIBUTING.md | 19 jtreg8-8.3+1+ds1/junit5/LICENSE-notice.md | 8 jtreg8-8.3+1+ds1/junit5/NOTICE.md | 8 jtreg8-8.3+1+ds1/junit5/README.md | 50 jtreg8-8.3+1+ds1/junit5/RELEASING.md | 30 jtreg8-8.3+1+ds1/junit5/SECURITY.md | 16 jtreg8-8.3+1+ds1/junit5/build.gradle.kts | 30 jtreg8-8.3+1+ds1/junit5/gradle.properties | 20 jtreg8-8.3+1+ds1/junit5/gradle/base/code-generator-model/build.gradle.kts | 6 jtreg8-8.3+1+ds1/junit5/gradle/base/code-generator-model/src/main/resources/jre.yaml | 2 jtreg8-8.3+1+ds1/junit5/gradle/base/dsl-extensions/build.gradle.kts | 3 jtreg8-8.3+1+ds1/junit5/gradle/base/dsl-extensions/src/main/kotlin/junitbuild/extensions/DependencyExtensions.kt | 8 jtreg8-8.3+1+ds1/junit5/gradle/base/dsl-extensions/src/main/kotlin/junitbuild/extensions/ProjectExtensions.kt | 30 jtreg8-8.3+1+ds1/junit5/gradle/base/dsl-extensions/src/main/kotlin/junitbuild/extensions/StringExtensions.kt | 7 jtreg8-8.3+1+ds1/junit5/gradle/base/dsl-extensions/src/main/kotlin/junitbuild/extensions/TaskExtensions.kt | 7 jtreg8-8.3+1+ds1/junit5/gradle/base/dsl-extensions/src/main/kotlin/junitbuild/extensions/VersionExtensions.kt | 3 jtreg8-8.3+1+ds1/junit5/gradle/base/dsl-extensions/src/main/kotlin/junitbuild/extensions/junitbuild.dsl-extensions.gradle.kts | 1 jtreg8-8.3+1+ds1/junit5/gradle/base/gradle.properties | 1 jtreg8-8.3+1+ds1/junit5/gradle/base/settings.gradle.kts | 7 jtreg8-8.3+1+ds1/junit5/gradle/config/checkstyle/checkstyleNohttp.xml | 10 jtreg8-8.3+1+ds1/junit5/gradle/config/checkstyle/suppressions.xml | 2 jtreg8-8.3+1+ds1/junit5/gradle/config/spotless/eclipse-public-license-2.0.java | 4 jtreg8-8.3+1+ds1/junit5/gradle/libs.versions.toml | 96 jtreg8-8.3+1+ds1/junit5/gradle/plugins/antora/build.gradle.kts | 39 jtreg8-8.3+1+ds1/junit5/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts | 74 jtreg8-8.3+1+ds1/junit5/gradle/plugins/build-parameters/build.gradle.kts | 21 jtreg8-8.3+1+ds1/junit5/gradle/plugins/build.gradle.kts | 3 jtreg8-8.3+1+ds1/junit5/gradle/plugins/code-generator/build.gradle.kts | 5 jtreg8-8.3+1+ds1/junit5/gradle/plugins/code-generator/src/main/kotlin/junitbuild.code-generator.gradle.kts | 1 jtreg8-8.3+1+ds1/junit5/gradle/plugins/code-generator/src/main/kotlin/junitbuild/generator/GenerateJreRelatedSourceCode.kt | 2 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/build.gradle.kts | 16 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/ProjectExtensions.kt | 19 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/TaskExtensions.kt | 5 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.checkstyle-conventions.gradle.kts | 15 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.checkstyle-nohttp.gradle.kts | 40 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.dependency-update-check.gradle.kts | 19 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.jacoco-aggregation-conventions.gradle.kts | 2 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.jacoco-conventions.gradle.kts | 2 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.java-library-conventions.gradle.kts | 33 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.java-toolchain-conventions.gradle.kts | 13 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.jmh-conventions.gradle.kts | 7 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.junit4-compatibility.gradle.kts | 2 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.kotlin-library-conventions.gradle.kts | 15 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.osgi-conventions.gradle.kts | 5 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts | 14 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.shadow-conventions.gradle.kts | 3 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.spotless-conventions.gradle.kts | 36 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.temp-maven-repo.gradle.kts | 31 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild.testing-conventions.gradle.kts | 113 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild/exec/RunConsoleLauncher.kt | 2 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild/extensions/Extensions.kt | 7 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild/graalvm/NativeImagePropertiesExtension.kt | 7 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild/java/PatchModuleArgumentProvider.kt | 2 jtreg8-8.3+1+ds1/junit5/gradle/plugins/common/src/main/kotlin/junitbuild/java/UpdateJarAction.kt | 4 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/build.gradle.kts | 23 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild.japicmp.gradle.kts | 85 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild/japicmp/AcceptedViolationSuppressor.kt | 43 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild/japicmp/AcceptedViolationsPostProcessRule.kt | 32 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild/japicmp/BreakingSuperClassChangeRule.kt | 16 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild/japicmp/InternalApiFilter.kt | 51 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild/japicmp/JApiCmpExtension.kt | 14 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild/japicmp/JApiCompatibilityExtensions.kt | 31 jtreg8-8.3+1+ds1/junit5/gradle/plugins/japicmp/src/main/kotlin/junitbuild/japicmp/SourceIncompatibleRule.kt | 13 jtreg8-8.3+1+ds1/junit5/gradle/plugins/publishing/build.gradle.kts | 18 jtreg8-8.3+1+ds1/junit5/gradle/plugins/publishing/src/main/kotlin/junitbuild.maven-central-publishing.gradle.kts | 72 jtreg8-8.3+1+ds1/junit5/gradle/plugins/publishing/src/main/kotlin/junitbuild.temp-maven-repo.gradle.kts | 42 jtreg8-8.3+1+ds1/junit5/gradle/plugins/publishing/src/main/kotlin/junitbuild/release/VerifyBinaryArtifactsAreIdentical.kt | 90 jtreg8-8.3+1+ds1/junit5/gradle/plugins/settings.gradle.kts | 16 jtreg8-8.3+1+ds1/junit5/gradle/scripts/checkBuildReproducibility.sh | 29 jtreg8-8.3+1+ds1/junit5/junit-bom/README.md | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/junit-jupiter-api.gradle.kts | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterAll.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertAll.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertArrayEquals.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertDoesNotThrow.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertEquals.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertFalse.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertInstanceOf.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertIterableEquals.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertLinesMatch.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotEquals.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotNull.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotSame.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNull.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertSame.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrowsExactly.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeout.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeoutPreemptively.java | 13 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTrue.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionFailureBuilder.java | 13 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assumptions.java | 9 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AutoClose.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrderer.java | 5 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrdererContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassTemplate.java | 72 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayName.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGeneration.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java | 258 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicContainer.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicNode.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java | 7 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/IndicativeSentencesGeneration.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MediaType.java | 165 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrderer.java | 5 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrdererContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Named.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/NamedExecutable.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Nested.java | 5 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Order.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepeatedTest.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepetitionInfo.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tag.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tags.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Test.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestClassOrder.java | 5 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestFactory.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInfo.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java | 9 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestMethodOrder.java | 5 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java | 152 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestTemplate.java | 3 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Timeout.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreCondition.java | 59 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreRangeCondition.java | 80 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractOsBasedExecutionCondition.java | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractRepeatableAnnotationCondition.java | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/BooleanExecutionCondition.java | 19 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java | 83 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java | 23 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java | 34 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java | 16 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOsCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java | 83 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java | 23 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java | 37 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java | 19 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOsCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/MethodBasedCondition.java | 13 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/OS.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterAllCallback.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterClassTemplateInvocationCallback.java | 74 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterEachCallback.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterTestExecutionCallback.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AnnotatedElementContext.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeAllCallback.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeClassTemplateInvocationCallback.java | 74 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeEachCallback.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContext.java | 82 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContextProvider.java | 120 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationLifecycleMethod.java | 45 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ConditionEvaluationResult.java | 32 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/DynamicTestInvocationContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutableInvoker.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutionCondition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtendWith.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extension.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionConfigurationException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContext.java | 217 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContextException.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/InvocationInterceptor.java | 25 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/MediaType.java | 121 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterContext.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolutionException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolver.java | 25 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptCallback.java | 60 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptContext.java | 35 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ReflectiveInvocationContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/RegisterExtension.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TemplateInvocationValidationException.java | 35 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactory.java | 26 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactoryContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePostProcessor.java | 25 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreConstructCallback.java | 26 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreDestroyCallback.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstances.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java | 190 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContext.java | 17 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.java | 34 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestWatcher.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/Executable.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingConsumer.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingSupplier.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/CleanupMode.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDir.java | 59 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDirFactory.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Execution.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ExecutionMode.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Isolated.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceAccessMode.java | 3 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLock.java | 80 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLockTarget.java | 49 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocks.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocksProvider.java | 223 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Resources.java | 3 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt | 293 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/module/org.junit.jupiter.api/module-info.java | 7 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte | 158 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/templates/resources/testFixtures/org/junit/jupiter/api/condition/JavaVersionPredicates.java.jte | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/EqualsAndHashCodeAssertions.java | 46 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/TemporaryClasspathExecutor.java | 54 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledInEclipse.java | 28 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledOnOpenJ9.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/ExtensionContextParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java | 122 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/JupiterTestEngine.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java | 55 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java | 53 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/EnumConfigurationParameterConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverter.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java | 20 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java | 157 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/CallbackSupport.java | 59 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java | 274 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassExtensionContext.java | 33 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationExtensionContext.java | 84 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationTestDescriptor.java | 188 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateTestDescriptor.java | 278 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java | 39 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultDynamicTestInvocationContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultTestInstanceFactoryContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java | 107 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicContainerTestDescriptor.java | 9 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicDescendantFilter.java | 26 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicExtensionContext.java | 18 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicNodeTestDescriptor.java | 12 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicTestTestDescriptor.java | 12 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExclusiveResourceCollector.java | 122 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExtensionUtils.java | 9 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Filterable.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineDescriptor.java | 5 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineExtensionContext.java | 19 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptor.java | 92 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java | 194 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java | 124 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodExtensionContext.java | 18 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodSourceSupport.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java | 60 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ResourceLockAware.java | 92 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TemplateExecutor.java | 115 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestClassAware.java | 29 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java | 36 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtils.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java | 122 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateExtensionContext.java | 18 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptor.java | 25 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java | 127 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/UniqueIdPrefixTransformer.java | 46 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Validatable.java | 44 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractAnnotatedDescriptorWrapper.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractOrderingVisitor.java | 209 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassOrderingVisitor.java | 134 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java | 290 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DeclaredMethodSelector.java | 68 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassOrdererContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodOrdererContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolver.java | 39 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodFinder.java | 40 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodOrderingVisitor.java | 134 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSegmentResolver.java | 68 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java | 141 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClass.java | 42 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClass.java | 40 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainer.java | 49 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTests.java | 57 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethod.java | 84 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethod.java | 7 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethod.java | 7 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestableMethod.java | 70 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicates.java | 175 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/AfterEachMethodAdapter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/BeforeEachMethodAdapter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluationException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluator.java | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConstructorInvocation.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultExecutableInvoker.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultParameterContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultTestInstances.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java | 63 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvoker.java | 15 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InvocationInterceptorChain.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java | 17 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/LauncherStoreFacade.java | 57 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/MethodInvocation.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/NamespaceAwareStore.java | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ParameterResolutionUtils.java | 20 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/TestInstancesProvider.java | 13 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/AutoCloseExtension.java | 20 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultPreInterruptContext.java | 41 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultRepetitionInfo.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultTestReporter.java | 47 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DisabledCondition.java | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionContextInternal.java | 38 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistrar.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistry.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/MutableExtensionRegistry.java | 52 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocation.java | 24 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocationFactory.java | 46 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptThreadDumpPrinter.java | 83 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestDisplayNameFormatter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestExtension.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestInvocationContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepetitionExtension.java | 7 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocation.java | 23 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocation.java | 9 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java | 231 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestInfoParameterResolver.java | 7 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestReporterParameterResolver.java | 9 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutConfiguration.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDuration.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDurationParser.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactory.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactory.java | 24 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/JupiterThrowableCollectorFactory.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollector.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java | 7 jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/testFixtures/java/org/junit/jupiter/engine/discovery/JupiterUniqueIdBuilder.java | 36 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/EnableJUnit4MigrationSupport.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/conditions/IgnoreCondition.java | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupport.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupport.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupport.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/TestRuleSupport.java | 13 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/VerifierSupport.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/AbstractTestRuleAdapter.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExpectedExceptionAdapter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExternalResourceAdapter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/GenericBeforeAndAfterAdvice.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/VerifierAdapter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/AbstractTestRuleAnnotatedMember.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMember.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMethod.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/module/org.junit.jupiter.migrationsupport/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/junit-jupiter-params.gradle.kts | 3 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterBenchmarks.java | 67 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java | 62 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AbstractParameterizedClassInvocationLifecycleMethodInvoker.java | 72 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocation.java | 170 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocationMethodInvoker.java | 33 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidationMode.java | 61 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidator.java | 130 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentSetLifecycleMethod.java | 58 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeClassTemplateInvocationFieldInjector.java | 39 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocation.java | 171 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocationMethodInvoker.java | 33 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ClassTemplateConstructorParameterResolver.java | 38 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/DefaultParameterInfo.java | 48 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/EvaluatedArgumentSet.java | 111 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/InstancePostProcessingClassTemplateFieldInjector.java | 41 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/Parameter.java | 65 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterInfo.java | 83 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClass.java | 252 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassContext.java | 181 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassExtension.java | 135 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassInvocationContext.java | 107 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedDeclarationContext.java | 45 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationConstants.java | 130 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContext.java | 94 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContextProvider.java | 86 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatter.java | 327 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationParameterResolver.java | 63 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java | 190 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestContext.java | 85 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java | 124 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestInvocationContext.java | 40 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java | 276 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodParameterResolver.java | 37 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java | 292 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestParameterResolver.java | 126 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java | 75 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolutionCache.java | 41 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java | 801 + jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/AggregateWith.java | 12 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentAccessException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAccessor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregationException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java | 39 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessor.java | 30 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/SimpleArgumentsAggregator.java | 48 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/AnnotationBasedArgumentConverter.java | 12 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConversionException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java | 48 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ConvertWith.java | 14 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java | 71 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverter.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeConversionPattern.java | 23 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/SimpleArgumentConverter.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/TypedArgumentConverter.java | 18 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProvider.java | 38 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/Arguments.java | 8 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java | 53 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java | 14 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSources.java | 10 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsUtils.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvArgumentsProvider.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileArgumentsProvider.java | 17 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSource.java | 30 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSources.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParserFactory.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParsingException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSource.java | 26 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSources.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptyArgumentsProvider.java | 25 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptySource.java | 16 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java | 49 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java | 73 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSources.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldArgumentsProvider.java | 19 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSource.java | 48 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSources.java | 15 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java | 40 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java | 56 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSources.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullAndEmptySource.java | 17 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullArgumentsProvider.java | 13 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullEnum.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullSource.java | 14 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueArgumentsProvider.java | 6 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSource.java | 13 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSources.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumer.java | 2 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java | 11 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/FieldContext.java | 50 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclaration.java | 55 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclarations.java | 83 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterInfo.java | 88 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessor.kt | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/module/org.junit.jupiter.params/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/testFixtures/java/org/junit/jupiter/params/provider/RecordArguments.java | 26 jtreg8-8.3+1+ds1/junit5/junit-jupiter/junit-jupiter.gradle.kts | 4 jtreg8-8.3+1+ds1/junit5/junit-jupiter/src/module/org.junit.jupiter/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/junit-platform-commons.gradle.kts | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/JUnitException.java | 11 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/PreconditionViolationException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/annotation/Testable.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/Try.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/package-info.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/DefaultResource.java | 69 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/Resource.java | 82 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/ResourceFilter.java | 48 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/package-info.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LogRecordListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/Logger.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LoggerFactory.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/AnnotationSupport.java | 74 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ClassSupport.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/DefaultResource.java | 70 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/HierarchyTraversalMode.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ModifierSupport.java | 29 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java | 167 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java | 52 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ResourceSupport.java | 219 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/SearchOption.java | 13 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java | 12 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/package-info.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClassFilter.java | 87 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClasspathScanner.java | 154 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/package-info.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/BlacklistedExceptions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFilter.java | 78 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassLoaderUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassNamePatternFilterUtils.java | 57 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java | 55 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java | 349 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScannerLoader.java | 46 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CollectionUtils.java | 30 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/DefaultClasspathScanner.java | 355 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/FunctionUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/KotlinReflectionUtils.java | 96 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/LruCache.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java | 9 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageUtils.java | 15 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PreconditionViolationException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/Preconditions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java | 451 - jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java | 52 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ServiceLoaderUtils.java | 55 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/StringUtils.java | 15 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ToStringBuilder.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/UnrecoverableExceptions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java | 22 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ServiceLoaderUtils.java | 56 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java | 7 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/ConcurrencyTestingUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/IdeUtils.java | 27 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/PreconditionAssertions.java | 45 jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/TestClassLoader.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-console-standalone/junit-platform-console-standalone.gradle.kts | 16 jtreg8-8.3+1+ds1/junit5/junit-platform-console/junit-platform-console.gradle.kts | 10 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/ConsoleLauncher.java | 20 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BannerOptionMixin.java | 27 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BaseCommand.java | 111 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandFacade.java | 56 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandResult.java | 63 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ConsoleTestExecutor.java | 236 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomClassLoaderCloseStrategy.java | 68 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomContextClassLoaderExecutor.java | 55 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoverTestsCommand.java | 50 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoveryRequestCreator.java | 182 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ExecuteTestsCommand.java | 113 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ListTestEnginesCommand.java | 52 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/MainCommand.java | 160 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ManifestVersionProvider.java | 35 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/OutputStreamConfig.java | 35 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/StandardStreamsHandler.java | 102 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/package-info.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/AnsiColorOptionMixin.java | 13 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BannerOptionMixin.java | 27 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BaseCommand.java | 109 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ClasspathEntriesConverter.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandFacade.java | 56 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandResult.java | 62 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ConsoleUtils.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Details.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/DiscoverTestsCommand.java | 46 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ExecuteTestsCommand.java | 109 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ListTestEnginesCommand.java | 51 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java | 159 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ManifestVersionProvider.java | 35 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/OutputStreamConfig.java | 34 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/SelectorConverter.java | 26 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptions.java | 27 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptionsMixin.java | 30 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java | 32 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptionsMixin.java | 159 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Theme.java | 140 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/package-info.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/ColorPalette.java | 133 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/DetailsPrintingListener.java | 34 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/FlatPrintingListener.java | 126 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Style.java | 40 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TestFeedPrintingListener.java | 133 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Theme.java | 140 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreeNode.java | 99 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrinter.java | 184 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrintingListener.java | 96 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/VerboseTreePrintingListener.java | 234 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/package-info.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ColorPalette.java | 128 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ConsoleTestExecutor.java | 192 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutor.java | 61 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DetailsPrintingListener.java | 27 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java | 148 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/FlatPrintingListener.java | 115 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/Style.java | 40 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TestFeedPrintingListener.java | 130 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreeNode.java | 92 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrinter.java | 175 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrintingListener.java | 87 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/VerboseTreePrintingListener.java | 225 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/package-info.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java17/org/junit/platform/console/options/ConsoleUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java9/org/junit/platform/console/ConsoleLauncherToolProvider.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/module/org.junit.platform.console/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeTestDescriptorVisitor.java | 41 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ConfigurationParameters.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DefaultDiscoveryIssue.java | 114 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryIssue.java | 168 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelector.java | 18 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelectorIdentifier.java | 30 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryListener.java | 25 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryRequest.java | 36 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineExecutionListener.java | 38 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ExecutionRequest.java | 129 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/Filter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/FilterResult.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/OutputDirectoryCreator.java | 45 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/SelectorResolutionResult.java | 12 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java | 58 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestExecutionResult.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestSource.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestTag.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueIdFormat.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/AbstractClassNameFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassNameFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassSelector.java | 14 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java | 80 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathRootSelector.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DirectorySelector.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParser.java | 28 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParsers.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java | 131 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludeClassNameFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludePackageNameFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FilePosition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FileSelector.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludeClassNameFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludePackageNameFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IterationSelector.java | 36 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/MethodSelector.java | 46 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ModuleSelector.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedClassSelector.java | 8 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedMethodSelector.java | 21 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageNameFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageSelector.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UniqueIdSelector.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UriSelector.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/FileEntry.java | 95 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProvider.java | 46 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProviderAdapter.java | 40 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/ReportEntry.java | 8 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/config/PrefixedConfigurationParameters.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptor.java | 23 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClassSource.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSource.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/CompositeTestSource.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DefaultUriSource.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DirectorySource.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/EngineDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FilePosition.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java | 33 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSystemSource.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/MethodSource.java | 10 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/PackageSource.java | 8 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ResourceUtils.java | 48 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/UriSource.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ClassContainerSelectorResolver.java | 7 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/DiscoveryIssueReporter.java | 188 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolution.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java | 155 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java | 75 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java | 48 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/SelectorResolver.java | 12 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/filter/ClasspathScanningSupport.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/CompositeLock.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfiguration.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategy.java | 20 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/EngineExecutionContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ExclusiveResource.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestEngine.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorService.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/LockManager.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/Node.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeExecutionAdvisor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTask.java | 11 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTaskContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalker.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NopLock.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/OpenTest4JAwareThrowableCollector.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfiguration.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfigurationStrategy.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ResourceLock.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SameThreadHierarchicalTestExecutorService.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleLock.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ThrowableCollector.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/Namespace.java | 105 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java | 58 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreException.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/module/org.junit.platform.engine/module-info.java | 7 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoEngineExecutionContext.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalContainerDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalEngineDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestEngine.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/FaultyTestEngines.java | 63 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestDescriptorStub.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineSpy.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineStub.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingDiscoveryListener.java | 37 jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingExecutionListener.java | 21 jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/UniqueId.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/module/org.junit.platform.jfr/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/AbstractMethodFilter.java | 64 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineDiscoveryResult.java | 12 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/ExcludeMethodFilter.java | 58 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/IncludeMethodFilter.java | 58 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/Launcher.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java | 90 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryRequest.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherInterceptor.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSession.java | 20 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSessionListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/MethodFilter.java | 107 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/PostDiscoveryFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TagFilter.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestExecutionListener.java | 17 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java | 12 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestPlan.java | 54 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentChecker.java | 110 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckingLauncherInterceptor.java | 40 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeEngineExecutionListener.java | 10 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeTestExecutionListener.java | 10 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultDiscoveryRequest.java | 16 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncher.java | 25 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherConfig.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherSession.java | 26 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingEngineExecutionListener.java | 7 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncher.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncherDiscoveryRequest.java | 69 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueCollector.java | 161 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueException.java | 32 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueNotifier.java | 143 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryErrorDescriptor.java | 51 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryOrchestrator.java | 141 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidator.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineExecutionOrchestrator.java | 89 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineFilterer.java | 15 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ExecutionListenerAdapter.java | 8 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreator.java | 71 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InterceptingLauncher.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InternalTestPlan.java | 9 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/IterationOrder.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfig.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java | 67 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryResult.java | 106 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherFactory.java | 40 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherListenerRegistry.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherPhase.java | 51 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ListenerRegistry.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/OutcomeDelayingEngineExecutionListener.java | 7 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderRegistry.java | 45 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderTestEngineRegistry.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/SessionPerRequestLauncher.java | 13 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java | 38 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/TestEngineFormatter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LegacyReportingUtils.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LoggingListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/MutableTestExecutionSummary.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java | 60 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/SummaryGeneratingListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/TestExecutionSummary.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListener.java | 10 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListener.java | 22 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListener.java | 9 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LauncherDiscoveryListeners.java | 11 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListener.java | 8 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/LauncherSessionListeners.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/DequeStack.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operator.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operators.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResult.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResults.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseStatus.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Parser.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ShuntingYard.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Stack.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpression.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpressions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Token.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TokenWith.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Tokenizer.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/ConfigurationParametersFactoryForTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/LauncherFactoryForTestingPurposesOnly.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/NamespacedHierarchicalStoreProviders.java | 27 jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/OutputDirectoryCreators.java | 32 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/junit-platform-reporting.gradle.kts | 13 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/LegacyReportingUtils.java | 11 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListener.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportData.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportWriter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/GitInfoCollector.java | 209 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitContributor.java | 78 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitFactory.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/LegacyReportingName.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.java | 102 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/Type.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/UniqueId.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor | 1 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/resources/org/junit/platform/reporting/open/xml/catalog.xml | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/module/org.junit.platform.reporting/module-info.java | 7 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/open/xml/OpenTestReportGenerationSystemPropertyOverride.java | 43 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/testutil/FileUtils.java | 31 jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension | 1 jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformRunnerListener.java | 8 jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformTestTree.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/module/org.junit.platform.runner/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/AfterSuite.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/BeforeSuite.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameters.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/DisableParentConfigurationParameters.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeClassNamePatterns.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeEngines.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludePackages.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeTags.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeClassNamePatterns.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeEngines.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludePackages.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeTags.java | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Select.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasses.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResource.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResources.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectDirectories.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFile.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFiles.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethod.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethods.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectModules.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectPackages.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectUris.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Selects.java | 6 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Suite.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SuiteDisplayName.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/UseTechnicalNames.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/module/org.junit.platform.suite.api/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/AdditionalDiscoverySelectors.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java | 191 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/module/org.junit.platform.suite.commons/module-info.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/ClassSelectorResolver.java | 37 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/DiscoverySelectorResolver.java | 14 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsPotentialTestContainer.java | 42 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsSuiteClass.java | 47 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/LifecycleMethodUtils.java | 115 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/NoTestsDiscoveredException.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteEngineDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteLauncher.java | 12 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java | 128 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestEngine.java | 7 jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/module/org.junit.platform.suite.engine/module-info.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-suite/junit-platform-suite.gradle.kts | 4 jtreg8-8.3+1+ds1/junit5/junit-platform-suite/src/module/org.junit.platform.suite/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Assertions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineDiscoveryResults.java | 58 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineExecutionResults.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineTestKit.java | 203 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Event.java | 28 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventConditions.java | 76 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventStatistics.java | 16 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventType.java | 14 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Events.java | 14 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Execution.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/ExecutionRecorder.java | 14 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Executions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TerminationInfo.java | 2 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TestExecutionResultConditions.java | 5 jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/module/org.junit.platform.testkit/module-info.java | 3 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/junit-vintage-engine.gradle.kts | 10 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/Constants.java | 77 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/JUnit4VersionCheck.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/VintageTestEngine.java | 18 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/DescriptionUtils.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/OrFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerDecorator.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerRequest.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java | 52 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/TestSourceProvider.java | 8 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageEngineDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageTestDescriptor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java | 23 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/FilterableIgnoringRunnerDecorator.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IgnoringRunnerDecorator.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClass.java | 6 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestMethod.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/MethodSelectorResolver.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/UniqueIdFilter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/VintageDiscoverer.java | 4 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/EventType.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunnerExecutor.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/TestRun.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/VintageExecutor.java | 190 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdReader.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdStringifier.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/module/org.junit.vintage.engine/module-info.java | 9 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4ParameterizedTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4VersionCheckTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineBasicTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineDiscoveryTests.java | 4 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java | 25 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineTestSuite.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageUniqueIdBuilder.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/DescriptionUtilsTests.java | 9 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/OrFilterTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/TestSourceProviderTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/VintageTestDescriptorTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClassTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessorTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/VintageDiscovererTests.java | 4 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/ParallelExecutionIntegrationTests.java | 204 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdReaderTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdStringifierTests.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/resources/junit-platform.properties | 1 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/groovy/org/junit/vintage/engine/samples/spock/SpockTestCaseWithUnrolledAndRegularFeatureMethods.groovy | 11 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/PlainOldJavaClassWithoutAnyTestsTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/AbstractJUnit3TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3ParallelSuiteWithSubsuites.java | 3 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSingleTestCaseWithSingleTestWhichFails.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSubsuites.java | 3 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/PlainJUnit3TestCaseWithSingleTestWhichFails.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJUnit4TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJunit4TestCaseWithConstructorParameter.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/Categories.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/CompletelyDynamicTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConcreteJUnit4TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConfigurableRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/DynamicRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EmptyIgnoredTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedJUnit4TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedWithParameterizedChildrenJUnit4TestCase.java | 4 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ExceptionThrowingRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCaseWithNotFilterableRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredParameterizedTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelClassesTestCase.java | 67 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelMethodsTestCase.java | 77 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParameterizedTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithFilterableChildRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithIgnoredJUnit4TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithErrorInBeforeClass.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithExceptionThrowingRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithIgnoredJUnit4TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit3SuiteWithSingleTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithErrorInBeforeClass.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithPlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithTwoTestCases.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithAssumptionFailureInBeforeClass.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithDistinguishableOverloadedMethod.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorCollectorStoringMultipleFailures.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInAfterClass.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInBeforeClass.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithExceptionThrowingRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithIndistinguishableOverloadedMethod.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithNotFilterableRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithDuplicateChangingChildDescriptions.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/MalformedJUnit4TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/NotFilterableRunner.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTimingTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithAfterParamFailureTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithBeforeParamFailureTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithFiveTestMethods.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithLifecycleMethods.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleInheritedTestWhichFails.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichFails.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithTwoTestMethods.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerThatOnlyReportsFailures.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerWithCustomUniqueIdsAndDisplayNames.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/SingleFailingTheoryTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/TestCaseRunWithJUnitPlatformRunner.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/jupiter-tests.gradle.kts | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreConditionTests.java.jte | 53 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreIntegrationTests.java.jte | 27 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreConditionTests.java.jte | 53 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreIntegrationTests.java.jte | 27 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertEqualsTests.groovy | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertNotEqualsTests.groovy | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/PrimitiveAndWrapperTypeHelpers.groovy | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/DefaultPackageTestCase.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/example/B_TestCase.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/JupiterTestSuite.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertAllAssertionsTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertArrayEqualsAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertDoesNotThrowAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertEqualsAssertionsTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertFalseAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertInstanceOfAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertIterableEqualsAssertionsTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertLinesMatchAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotEqualsAssertionsTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotNullAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotSameAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNullAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertSameAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsExactlyAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutPreemptivelyAssertionsTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTrueAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertionTestUtils.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssumptionsTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationInheritanceTestCase.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java | 269 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DynamicTestTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/EnigmaThrowable.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/FailAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesGenerationInheritanceTestCase.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesNestedTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassScenarioOneTestCase.java | 18 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassTestCase.java | 30 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java | 19 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java | 19 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java | 33 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesTopLevelTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IterableFactory.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/MediaTypeTests.java | 156 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java | 20 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/ConditionEvaluationResultTests.java | 127 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java | 207 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeIntegrationTests.java | 155 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionClassLoaderTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java | 268 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeIntegrationTests.java | 217 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionClassLoaderTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsConditionTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/JRETests.java | 126 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/StaticConditionMethods.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java | 20 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/DeprecatedMediaTypeTests.java | 131 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExecutableInvokerIntegrationTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExtensionComposabilityTests.java | 23 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/KitchenSinkExtension.java | 65 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/MediaTypeInteroperabilityTests.java | 38 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/LockTests.java | 48 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java | 671 + jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLocksProviderTests.java | 315 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssertionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssumptionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AbstractJupiterTestEngineTests.java | 61 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AtypicalJvmMethodNameTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeAllAndAfterAllComposedAnnotationTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeEachAndAfterEachComposedAnnotationTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ClassTemplateInvocationTests.java | 1600 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultExecutionModeTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultMethodTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DisabledTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DynamicNodeGenerationTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ExceptionHandlingTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/FailedAssumptionsTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java | 63 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineBasicTests.java | 51 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineTests.java | 96 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/LifecycleMethodOverridingTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java | 35 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedTestClassesTests.java | 211 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithInheritanceTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithSeparateInheritanceTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NonVoidTestableMethodIntegrationTests.java | 42 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/OverloadedTestMethodTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/RecordTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ReportingTests.java | 95 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/SealedClassTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StandardTestClassTests.java | 11 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedBeforeAllAndAfterAllMethodsTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedTestCase.java | 26 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestClassInheritanceTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleConfigurationTests.java | 16 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleKotlinTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java | 133 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestMethodOverridingTests.java | 107 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestTemplateInvocationTests.java | 153 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelComposedNested.java | 24 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelNestedTestCase.java | 22 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNonGenericTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNumberTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/BridgeMethodTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithBridgeMethods.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithoutBridgeMethods.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberTestGroup.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/PackagePrivateParent.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java | 22 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java | 8 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java | 41 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java | 436 - jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionsUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java | 39 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LauncherStoreFacadeTest.java | 98 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtilsTests.java | 174 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/NamespaceTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ResourceAutoClosingTests.java | 132 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java | 35 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java | 21 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java | 72 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class1WithTestCases.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class2WithTestCases.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithStaticInnerTestCases.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithoutTestCases.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java | 127 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoveryTests.java | 410 - jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClassTests.java | 54 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClassTests.java | 58 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainerTests.java | 71 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTestsTests.java | 214 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethodTests.java | 162 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethodTests.java | 108 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethodTests.java | 27 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicatesTests.java | 498 + jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultExecutableInvokerTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultTestInstancesTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DynamicTestIntegrationTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreConcurrencyTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java | 8 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java | 28 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/UniqueIdParsingForArrayParameterIntegrationTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotation.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotationParameterResolver.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomType.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomTypeParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/DoubleParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/LongParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfListsTypeBasedParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfStringsParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NullIntegerParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NumberParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveArrayParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveIntegerParameterResolver.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/AutoCloseTests.java | 11 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterAllTests.java | 8 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterEachTests.java | 12 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterTestExecutionCallbackTests.java | 9 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/CloseablePathTests.java | 150 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ConfigLoaderExtension.java | 28 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/DefaultTestReporterTests.java | 156 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EnigmaException.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EventuallyInterruptibleInvocation.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExecutionConditionTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionContextExecutionTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java | 12 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java | 89 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/InvocationInterceptorTests.java | 110 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/LifecycleMethodExecutionExceptionHandlerTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java | 182 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java | 256 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedProgrammaticExtensionRegistrationTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ParameterResolverTests.java | 19 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/PreInterruptCallbackTests.java | 259 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java | 31 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/RepeatedTestTests.java | 39 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocationTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocationTests.java | 9 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ServiceLoaderExtension.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java | 140 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryMetaAnnotationTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java | 135 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java | 154 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPreconditionTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestExecutionExceptionHandlerTests.java | 3 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInfoParameterResolverTests.java | 37 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java | 147 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorAndPreDestroyCallbackTests.java | 8 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorTests.java | 129 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreConstructCallbackTests.java | 179 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackUtilityMethodTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java | 6 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationParserTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactoryTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java | 23 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactoryTests.java | 19 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AlwaysDisabledCondition.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AnotherAlwaysDisabledCondition.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/SystemPropertyCondition.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/subpackage/SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase.java | 7 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/JupiterMigrationSupportTestSuite.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreAnnotationIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreConditionTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/AbstractTestRuleAdapterTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupportWithBothRuleTypesTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupportTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForDifferentDeclaredReturnTypesRulesTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMixedMethodAndFieldRulesTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleFieldRulesTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleMethodRulesTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForTemporaryFolderFieldTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportWithInheritanceTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceWithoutAdapterTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/FailAfterAllHelper.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/LauncherBasedEnableRuleMigrationSupportTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/VerifierSupportForMixedMethodAndFieldRulesTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierFieldTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierMethodTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterInfoIntegrationTests.java | 108 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedClassIntegrationTests.java | 2258 +++++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterTests.java | 396 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestContextTests.java | 89 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java | 170 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java | 469 + jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java | 80 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java | 384 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestSuite.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/AggregatorIntegrationTests.java | 47 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessorTests.java | 18 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java | 328 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverterTests.java | 27 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java | 60 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProviderTests.java | 15 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ArgumentsTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java | 27 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvFileArgumentsProviderTests.java | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java | 164 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumSourceTests.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/FieldArgumentsProviderTests.java | 14 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java | 9 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MockCsvAnnotationBuilder.java | 2 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ValueArgumentsProviderTests.java | 5 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java | 46 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/DeprecatedParameterInfoIntegrationTests.java | 114 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertTimeoutAssertionsTests.kt | 56 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertionsTests.kt | 89 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinDynamicTests.kt | 58 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinFailAssertionsTests.kt | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/ArbitraryNamingKotlinTestCase.kt | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerClassKotlinTestCase.kt | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerMethodKotlinTestCase.kt | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinDefaultImplsTestCase.kt | 23 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceImplementationTestCase.kt | 14 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceTestCase.kt | 21 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedClassKotlinIntegrationTests.kt | 58 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedInvocationNameFormatterIntegrationTests.kt | 79 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestKotlinSequenceIntegrationTests.kt | 54 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestNameFormatterIntegrationTests.kt | 77 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessorKotlinTests.kt | 20 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/DisplayNameTests.kt | 8 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension | 1 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/junit-platform.properties | 4 jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/log4j2-test.xml | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/platform-tests.gradle.kts | 55 jtreg8-8.3+1+ds1/junit5/platform-tests/src/jmh/java/org/junit/jupiter/jmh/AssertionBenchmarks.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/OutputFiles.java | 16 jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessResult.java | 24 jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessStarter.java | 120 jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedOutput.java | 24 jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedProcess.java | 68 jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/package-info.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/DefaultPackageTestCase.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/api/condition/OSTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/Heavyweight.java | 9 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/HeavyweightTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/AbstractEqualsAndHashCodeTests.java | 42 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/JUnitPlatformTestSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/TestEngineTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/annotation/TestableAnnotationTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/function/TryTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/AnnotationSupportTests.java | 86 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ClassSupportTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ModifierSupportTests.java | 61 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/PreconditionAssertions.java | 34 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java | 184 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceInteroperabilityTests.java | 30 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceSupportTests.java | 225 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/ConversionSupportTests.java | 348 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java | 21 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java | 24 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassLoaderUtilsTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassNamePatternFilterUtilsTests.java | 153 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java | 625 - jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java | 9 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CollectionUtilsTests.java | 65 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/DefaultClasspathScannerTests.java | 631 + jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ExceptionUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/FunctionUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/LruCacheTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ModuleUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PackageUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PreconditionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java | 258 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsWithGenericTypeHierarchiesTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/SerializationUtils.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/StringUtilsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ToStringBuilderTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AExecutionConditionClass.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/ATestExecutionListenerClass.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AVanillaEmpty.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BExecutionConditionClass.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BTestExecutionListenerClass.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BVanillaEmpty.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/CustomType.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleDetailsTests.java | 13 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherIntegrationTests.java | 78 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapper.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapperResult.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CommandLineOptionsParsingTests.java | 762 + jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleTestExecutorTests.java | 127 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleUtilsTests.java | 29 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CustomContextClassLoaderExecutorTests.java | 96 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/DiscoveryRequestCreatorTests.java | 430 + jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ExecuteTestsCommandTests.java | 113 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/StdStreamTestCase.java | 34 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ThemeTests.java | 37 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/CommandLineOptionsParsingTests.java | 640 - jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ConsoleUtilsTests.java | 28 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ExecuteTestsCommandTests.java | 114 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ThemeTests.java | 36 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/ColorPaletteTests.java | 207 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/FlatPrintingListenerTests.java | 191 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TestFeedPrintingListenerTests.java | 116 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreeNodeTests.java | 98 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreePrinterTests.java | 118 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/VerboseTreePrintingListenerTests.java | 109 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTest.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTest.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/SecondTest.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test1.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Tests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ThirdTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java | 207 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ConsoleTestExecutorTests.java | 127 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutorTests.java | 76 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/DiscoveryRequestCreatorTests.java | 368 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/FlatPrintingListenerTests.java | 175 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TestFeedPrintingListenerTests.java | 115 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java | 98 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreePrinterTests.java | 117 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/VerboseTreeListenerTests.java | 96 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/CompositeTestDescriptorVisitorTests.java | 54 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/DiscoveryIssueTests.java | 127 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/FilterCompositionTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestDescriptorTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestTagTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdFormatTests.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdTests.java | 14 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassNameFilterTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassSelectorTests.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathResourceSelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathRootSelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DirectorySelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java | 52 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FilePositionTests.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FileSelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/IterationSelectorTests.java | 20 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/MethodSelectorTests.java | 11 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ModuleSelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedClassSelectorTests.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedMethodSelectorTests.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageNameFilterTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageSelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UniqueIdSelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UriSelectorTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/config/PrefixedConfigurationParametersTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptorTests.java | 9 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestSourceTests.java | 5 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClassSourceTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSourceTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/CompositeTestSourceTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DefaultUriSourceTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoClassTestDescriptor.java | 32 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoMethodTestDescriptor.java | 44 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FilePositionTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java | 24 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/MethodSourceTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/PackageSourceTests.java | 13 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorOrderChildrenTests.java | 150 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorTests.java | 94 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolverTests.java | 82 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java | 140 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/CompositeLockTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinDeadLockTests.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorServiceTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorTests.java | 8 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/LockManagerTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/MemoryLeakTests.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalkerIntegrationTests.java | 8 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionIntegrationTests.java | 15 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockSupport.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java | 5 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleLockTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutorTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ThrowableCollectorTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespaceTests.java | 36 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java | 5 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingDiscoveryListenerIntegrationTests.java | 49 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingExecutionListenerIntegrationTests.java | 18 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/DiscoveryFilterStub.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/FilterStub.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptedTestEngine.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptorInjectedLauncherSessionListener.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/MethodFilterTests.java | 174 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/PostDiscoveryFilterStub.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagFilterTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagIntegrationTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherDiscoveryListener.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor1.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor2.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherSessionListener.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java | 59 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPostDiscoveryTagFilter.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckerTests.java | 87 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeEngineExecutionListenerTests.java | 30 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java | 22 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java | 435 + jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DiscoveryIssueCollectorTests.java | 88 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidatorTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java | 14 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreatorTests.java | 83 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/InternalTestPlanTests.java | 118 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigurationParametersTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java | 23 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryResultTests.java | 111 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherFactoryTests.java | 247 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherSessionTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ListenerRegistryTests.java | 8 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StoreSharingTests.java | 63 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptorTests.java | 36 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/AnotherUnusedTestExecutionListener.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/LoggingListenerTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/NoopTestExecutionListener.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/OutputDirTests.java | 67 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java | 9 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListenerIntegrationTests.java | 117 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UnusedTestExecutionListener.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListenerTests.java | 52 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbstractLauncherDiscoveryListenerTests.java | 47 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListenerTests.java | 12 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListenerTests.java | 14 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListenerTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserErrorTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TagExpressionsTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenizerTests.java | 5 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/IncrementingClock.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java | 10 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportAssertions.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java | 9 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java | 21 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/JUnitContributorTests.java | 67 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java | 230 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java | 38 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/BeforeAndAfterSuiteTests.java | 31 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java | 313 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteTestDescriptorTests.java | 26 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ConfigurationSensitiveTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/DynamicTestsTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyDynamicTestsTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyTestTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ErroneousTestCase.java | 30 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/JUnit4TestsTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/MultipleTestsTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/SingleTestTestCase.java | 9 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/StatefulTestCase.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/TaggedTestTestCase.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/AbstractSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java | 27 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ConfigurationSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/CyclicSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/DynamicSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyCyclicSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestWithFailIfNoTestFalseSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseWithFailIfNoTestFalseSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ErroneousTestSuite.java | 20 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/InheritedSuite.java | 14 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/LifecycleMethodsSuites.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultiEngineSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultipleSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/NestedSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectByIdentifierSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectClassesSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectMethodsSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteDisplayNameSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteWithErroneousTestSuite.java | 19 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ThreePartCyclicSuite.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java | 27 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineDiscoveryResultsIntegrationTests.java | 104 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineTestKitTests.java | 42 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EventsTests.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/ExecutionsIntegrationTests.java | 3 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/NestedContainerEventConditionTests.java | 12 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/TestExecutionResultConditionsTests.java | 11 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/junit-platform.properties | 1 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/build.gradle | 1 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/sub-project/sub-project.gradle | 1 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/build.gradle.kts | 1 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/sub-project/sub-project.gradle.kts | 1 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/maven/pom.xml | 1 jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/log4j2-test.xml | 10 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/platform-tooling-support-tests.gradle.kts | 175 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/build.xml | 71 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/main/java/com/example/project/Calculator.java | 19 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/test/java/com/example/project/CalculatorTests.java | 41 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts | 27 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/settings.gradle.kts | 38 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/main/java/com/example/project/Calculator.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java | 55 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/ClassLevelAnnotationTests.java | 5 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java | 18 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java | 19 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/resources/junit-platform.properties | 1 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/build.gradle.kts | 13 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/gradle.properties | 1 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/settings.gradle.kts | 4 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/src/test/kotlin/com/example/project/ExtensionFunctionsTests.kt | 4 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/build.gradle.kts | 27 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/gradle.properties | 1 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/settings.gradle.kts | 4 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/src/test/java/FooTests.java | 5 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/build.gradle.kts | 42 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/settings.gradle.kts | 1 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/main/java/com/example/project/Calculator.java | 19 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/test/java/com/example/project/CalculatorTests.java | 41 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt | 5 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-console.expected.txt | 3 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-reporting.expected.txt | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/pom.xml | 8 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/src/test/java/JUnitPlatformCommonsTests.java | 4 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.gradle.kts | 43 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.xml | 72 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/gradle.properties | 1 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/pom.xml | 94 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/settings.gradle.kts | 5 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/main/java/com/example/project/Calculator.java | 19 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java | 53 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorTests.java | 47 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/resources/junit-platform.properties | 4 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/pom.xml | 94 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/main/java/com/example/project/Calculator.java | 19 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/test/java/com/example/project/CalculatorTests.java | 41 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/pom.xml | 5 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/src/test/java/com/example/project/DummyTests.java | 7 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/pom.xml | 73 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/JupiterIntegrationTests.java | 54 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/ModuleUtilsTests.java | 64 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/pom.xml | 82 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/JupiterIntegrationTests.java | 50 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/ModuleUtilsTests.java | 64 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/build.gradle.kts | 28 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/gradle.properties | 1 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/settings.gradle.kts | 4 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/src/test/java/ReflectionTestCase.java | 8 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/expected-err.txt | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/other/OtherwiseNotReferencedClass.java | 14 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterIntegration.java | 5 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterParamsIntegration.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/SuiteIntegration.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/VintageIntegration.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/build.gradle.kts | 13 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/gradle.properties | 1 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/pom.xml | 9 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/settings.gradle.kts | 4 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/archUnit/java/platform/tooling/support/tests/ArchUnitTests.java | 190 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Helper.java | 90 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/MavenRepo.java | 16 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ProcessStarters.java | 81 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Request.java | 183 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ThirdPartyJars.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/HelperTests.java | 6 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/AntStarterTests.java | 49 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java | 157 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/FilePrefix.java | 25 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java | 49 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleKotlinExtensionsTests.java | 37 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleMissingEngineTests.java | 60 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleModuleFileTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleStarterTests.java | 110 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarContainsManifestFirstTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarDescribeModuleTests.java | 59 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JavaVersionsTests.java | 55 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/LocalMavenRepo.java | 83 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManagedResource.java | 122 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManifestTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenEnvVars.java | 31 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenPomFileTests.java | 2 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenRepoProxy.java | 75 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenStarterTests.java | 95 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenSurefireCompatibilityTests.java | 45 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ModularUserGuideTests.java | 124 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MultiReleaseJarTests.java | 68 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/OutputAttachingExtension.java | 100 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/PackageCyclesDetectionTests.java | 52 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/Projects.java | 20 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ReflectionCompatibilityTests.java | 42 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java | 384 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ToolProviderTests.java | 31 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/UnalignedClasspathTests.java | 74 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageGradleIntegrationTests.java | 55 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageMavenIntegrationTests.java | 56 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/XmlAssertions.java | 198 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/junit-platform.properties | 3 jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/AntStarterTests_snapshots/open-test-report.xml.snapshot | 426 + jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/GradleStarterTests_snapshots/open-test-report.xml.snapshot | 426 + jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/MavenStarterTests_snapshots/open-test-report.xml.snapshot | 426 + jtreg8-8.3+1+ds1/junit5/settings.gradle.kts | 9 jtreg8-8.3+1+ds1/make/Makefile | 12 jtreg8-8.3+1+ds1/make/build-support/asmtools/version-numbers | 4 jtreg8-8.3+1+ds1/make/build-support/version-numbers | 12 jtreg8-8.3+1+ds1/opentest4j-reporting/.gitignore | 7 jtreg8-8.3+1+ds1/opentest4j-reporting/README.adoc | 292 jtreg8-8.3+1+ds1/opentest4j-reporting/SECURITY.md | 15 jtreg8-8.3+1+ds1/opentest4j-reporting/build.gradle.kts | 16 jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/build.gradle.kts | 14 jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/settings.gradle.kts | 9 jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/UpdateJarAction.kt | 44 jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-basics.gradle.kts | 17 jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-conventions.gradle.kts | 110 jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts | 36 jtreg8-8.3+1+ds1/opentest4j-reporting/cli/build.gradle.kts | 39 jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ConvertCommand.java | 16 jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/HtmlReportCommand.java | 78 jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ReportingCli.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ValidateCommand.java | 27 jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/resources/log4j2.xml | 2 jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/module/java/org.opentest4j.reporting.cli/module-info.java | 34 jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/build.gradle.kts | 11 jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/component-diagram.puml | 27 jtreg8-8.3+1+ds1/opentest4j-reporting/events/build.gradle.kts | 17 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Appendable.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/AttributeValueEscapingWriter.java | 152 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/ChildElement.java | 7 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Context.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DefaultDocumentWriter.java | 187 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DocumentWriter.java | 26 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Element.java | 23 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/EscapingXMLStreamWriter.java | 241 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Factory.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/NamespaceRegistry.java | 7 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/SingleElementXMLStreamWriter.java | 190 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Attachments.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CoreFactory.java | 35 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CpuCores.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Data.java | 33 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/DirectorySource.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/File.java | 93 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FilePosition.java | 26 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FileSource.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/HostName.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Infrastructure.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Metadata.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/OperatingSystem.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Output.java | 88 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Reason.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Result.java | 26 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Sources.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tag.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tags.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UriSource.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UserName.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Branch.java | 45 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Commit.java | 45 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/GitFactory.java | 74 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Repository.java | 60 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Status.java | 61 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClassSource.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClasspathResourceSource.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/FileEncoding.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/HeapSize.java | 19 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaFactory.java | 9 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaVersion.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/MethodSource.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/PackageSource.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/Throwable.java | 19 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Event.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Events.java | 29 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Finished.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Reported.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/RootFactory.java | 9 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Started.java | 8 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/module/java/org.opentest4j.reporting.events/module-info.java | 32 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterSample.java | 3 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterStreamingSample.java | 53 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/ArchitectureTests.java | 2 jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/events/api/DocumentWriterTest.java | 63 jtreg8-8.3+1+ds1/opentest4j-reporting/gradle.properties | 6 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.gitignore | 27 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.prettierrc | 1 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.tool-versions | 1 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/build.gradle.kts | 75 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/eslint.config.js | 20 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/index.html | 19 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/package-lock.json | 4093 ++++++++++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/package.json | 35 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/public/init.js | 467 + jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/App.vue | 40 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/ExecutionIcon.vue | 17 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/Selection.ts | 11 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestExecution.ts | 136 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatus.ts | 45 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatusIcon.vue | 54 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/icon.ts | 4 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/CodeBlock.vue | 50 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsHeader.vue | 15 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsSections.vue | 66 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DurationLabel.vue | 38 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/ExecutionDetails.vue | 19 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedBlock.vue | 78 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedSection.vue | 38 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/TestNodeDetails.vue | 68 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/keys.ts | 3 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/DarkModeSwitch.vue | 30 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/ExecutionSummary.vue | 47 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/StatusBar.vue | 20 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ExecutionTree.vue | 26 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/SideBar.vue | 39 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TestNodeTree.vue | 30 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBar.vue | 77 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBarIcon.vue | 15 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeNode.vue | 76 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeState.ts | 95 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/global.d.ts | 42 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/main.ts | 49 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/style.css | 3 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/vite-env.d.ts | 1 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tailwind.config.js | 5 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.app.json | 24 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.json | 7 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.node.json | 22 jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/vite.config.ts | 19 jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/build.gradle.kts | 116 jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/module-info.java | 6 jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/KitchenSinkTests.java | 75 jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/SampleContributor.java | 18 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/build.gradle.kts | 5 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/events.xml | 4 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/hierarchy.xml | 4 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Namespace.java | 103 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/QualifiedName.java | 13 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Schemas.java | 61 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.1.0.xsd | 97 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.2.0.xsd | 132 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core.xsd | 97 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.1.0.xsd | 35 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.2.0.xsd | 35 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events.xsd | 35 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/git-0.2.0.xsd | 69 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.1.0.xsd | 27 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.2.0.xsd | 27 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy.xsd | 27 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.1.0.xsd | 71 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.2.0.xsd | 71 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java.xsd | 71 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/module/java/org.opentest4j.reporting.schema/module-info.java | 26 jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/test/java/org/opentest4j/reporting/schema/SchemaTests.java | 50 jtreg8-8.3+1+ds1/opentest4j-reporting/settings.gradle.kts | 40 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/build.gradle.kts | 82 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/Converter.java | 42 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverter.java | 252 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/CoreContributor.java | 317 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriter.java | 330 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/GitContributor.java | 99 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/HtmlReportWriter.java | 45 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/JavaContributor.java | 124 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/util/DomUtils.java | 262 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidator.java | 255 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Location.java | 37 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Severity.java | 40 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationMessage.java | 37 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationResult.java | 58 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Validator.java | 41 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor | 3 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/module/java/org.opentest4j.reporting.tooling.core/module-info.java | 43 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverterTests.java | 184 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterBrowserTests.java | 91 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterTests.java | 105 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/PlaywrightTracePublisher.java | 44 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/util/DomUtilsTest.java | 51 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidatorTests.java | 112 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/build.gradle.kts | 19 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Block.java | 37 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Contributor.java | 90 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Image.java | 52 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/KeyValuePairs.java | 50 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Labels.java | 50 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Paragraph.java | 48 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/PreFormattedOutput.java | 48 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Section.java | 80 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Subsections.java | 50 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/package-info.java | 12 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/module/java/org.opentest4j.reporting.tooling.spi/module-info.java | 26 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/build.gradle.kts | 18 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/Converter.java | 35 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/DefaultConverter.java | 240 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/DefaultValidator.java | 244 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Location.java | 84 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Severity.java | 33 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationMessage.java | 84 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationResult.java | 57 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Validator.java | 34 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/converter/DefaultConverterTests.java | 155 jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/validator/DefaultValidatorTests.java | 110 jtreg8-8.3+1+ds1/src/share/bin/jtreg.sh | 2 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/AgentServer.java | 7 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/GetJDKProperties.java | 33 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JDK_Version.java | 3 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JUnitRunner.java | 6 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainActionHelper.java | 36 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainMethodHelper.java | 273 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainWrapper.java | 27 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/JDK.java | 49 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/RegressionTestFinder.java | 8 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/TestProperties.java | 31 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/Agent.java | 4 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/CompileAction.java | 85 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/DriverAction.java | 6 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/MainAction.java | 14 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/RegressionScript.java | 6 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/report/TestStats.java | 2 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java | 69 jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/tool/Tool.java | 2 jtreg8-8.3+1+ds1/src/share/doc/javatest/regtest/faq.md | 6 jtreg8-8.3+1+ds1/src/share/doc/javatest/regtest/tag-spec.html | 16 jtreg8-8.3+1+ds1/test/agentout/AgentOut.gmk | 10 jtreg8-8.3+1+ds1/test/applicationMainMethod/ApplicationMainMethod.gmk | 40 jtreg8-8.3+1+ds1/test/applicationMainMethod/ReferNonExistentClassTest.java | 54 jtreg8-8.3+1+ds1/test/compactsourcefile/Compact.java | 31 jtreg8-8.3+1+ds1/test/compactsourcefile/CompactArgs.java | 31 jtreg8-8.3+1+ds1/test/compactsourcefile/CompactSourceFileTest.gmk | 80 jtreg8-8.3+1+ds1/test/compactsourcefile/CompactStatic.java | 31 jtreg8-8.3+1+ds1/test/compactsourcefile/CompactStaticArgs.java | 31 jtreg8-8.3+1+ds1/test/compactsourcefile/InstanceMain.java | 33 jtreg8-8.3+1+ds1/test/compactsourcefile/MainBase.java | 28 jtreg8-8.3+1+ds1/test/compactsourcefile/MainBaseTest.java | 30 jtreg8-8.3+1+ds1/test/compactsourcefile/MainTrait.java | 28 jtreg8-8.3+1+ds1/test/compactsourcefile/MainTraitTest.java | 30 jtreg8-8.3+1+ds1/test/compactsourcefile/TEST.ROOT | 1 jtreg8-8.3+1+ds1/test/compactsourcefile/disabled/InstanceMainNotExpectedToLaunch.java | 34 jtreg8-8.3+1+ds1/test/compactsourcefile/disabled/TEST.properties | 1 jtreg8-8.3+1+ds1/test/jasm/Hello.jasm | 30 jtreg8-8.3+1+ds1/test/jasm/Jasm.gmk | 55 jtreg8-8.3+1+ds1/test/jasm/JasmUsageTest.java | 40 jtreg8-8.3+1+ds1/test/junitDiscoveryFailure/InvalidJUnitTest.java | 39 jtreg8-8.3+1+ds1/test/junitDiscoveryFailure/junit-discovery-failure.gmk | 61 jtreg8-8.3+1+ds1/test/keywords/badTest/KeyMoreThanOnce.java | 35 jtreg8-8.3+1+ds1/test/keywords/badTest/TEST.ROOT | 1 jtreg8-8.3+1+ds1/test/keywords/testKeywords.gmk | 13 jtreg8-8.3+1+ds1/test/nativepath/NativeAccessEnabled.java | 37 jtreg8-8.3+1+ds1/test/nativepath/TestNativePath.gmk | 61 jtreg8-8.3+1+ds1/test/policy/PolicyTest.gmk | 5 jtreg8-8.3+1+ds1/test/tag-spec/TestTagSpec.gmk | 3 jtreg8-8.3+1+ds1/test/xmlCrashInfo/CrashTestStderr.java | 27 jtreg8-8.3+1+ds1/test/xmlCrashInfo/CrashTestStdout.java | 31 jtreg8-8.3+1+ds1/test/xmlCrashInfo/TEST.ROOT | 1 jtreg8-8.3+1+ds1/test/xmlCrashInfo/XMLCrashInfoTest.gmk | 29 2545 files changed, 156909 insertions(+), 18933 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp8q84x7yo/jtreg8_8.1+1+ds1-1~deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp8q84x7yo/jtreg8_8.3+1+ds1-2~deb13u1.dsc: no acceptable signature found diff -Nru jtreg8-8.1+1+ds1/CHANGELOG.md jtreg8-8.3+1+ds1/CHANGELOG.md --- jtreg8-8.1+1+ds1/CHANGELOG.md 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/CHANGELOG.md 2026-06-21 20:26:05.000000000 +0000 @@ -1,8 +1,46 @@ -## [Unreleased](https://git.openjdk.org/jtreg/compare/jtreg-8+2...master) +## [Unreleased](https://git.openjdk.org/jtreg/compare/jtreg-8.3+1...master) + +_nothing noteworthy, yet_ + +## [8.3](https://git.openjdk.org/jtreg/compare/jtreg-8.2.1+1...jtreg-8.3+1) + +* Support [Compact Source Files and Instance Main Methods](https://openjdk.org/jeps/512) in main tests [CODETOOLS-7904141](https://bugs.openjdk.org/browse/CODETOOLS-7904141) + +* Add `--enable-native-access=ALL-UNNAMED` for actions tagged with `/native` [CODETOOLS-7904172](https://bugs.openjdk.org/browse/CODETOOLS-7904172) + +* Enhanced support in driver mode for tests using `@enablePreview` [CODETOOLS-7904149](https://bugs.openjdk.org/browse/CODETOOLS-7904149) + +* XML reports now include crash log data [CODETOOLS-7904153](https://bugs.openjdk.org/browse/CODETOOLS-7904153) + +## [8.2.1](https://git.openjdk.org/jtreg/compare/jtreg-8.2+1...jtreg-8.2.1+1) + +* Fixup release without any changes compared to [8.2](#82) + +## [8.2](https://git.openjdk.org/jtreg/compare/jtreg-8.1+1...jtreg-8.2+1) + +* Improving handling of JASM files: + * Use 45.3 (representing Java 1.1) as the default class file version, if the JASM file(s) don't have any specific class file version in them. + [CODETOOLS-7904133](https://bugs.openjdk.org/browse/CODETOOLS-7904133) + * Prevent JASM-related log messages on stdout [CODETOOLS-7904121](https://bugs.openjdk.org/browse/CODETOOLS-7904121) + +* Update bundled dependencies: + * AsmTools 9.1 [CODETOOLS-7904130](https://bugs.openjdk.org/browse/CODETOOLS-7904130) + * JUnit 5.14.2 [CODETOOLS-7904129](https://bugs.openjdk.org/browse/CODETOOLS-7904129) + +## [8.1](https://git.openjdk.org/jtreg/compare/jtreg-8+2...jtreg-8.1+1) + +* Improve time(out)-related logging: + * [CODETOOLS-7903816](https://bugs.openjdk.org/browse/CODETOOLS-7903816) + * [CODETOOLS-7903894](https://bugs.openjdk.org/browse/CODETOOLS-7903894) + * [CODETOOLS-7904067](https://bugs.openjdk.org/browse/CODETOOLS-7904067) + * [CODETOOLS-7904088](https://bugs.openjdk.org/browse/CODETOOLS-7904088) * `XAUTHORITY` environment variable is now preserved when launching tests on Unix-like platforms. [CODETOOLS-7904016](https://bugs.openjdk.org/browse/CODETOOLS-7904016) +* Update bundled dependencies: + * JUnit 5.13.4 [CODETOOLS-7904070](https://bugs.openjdk.org/browse/CODETOOLS-7904070) + ## [8](https://git.openjdk.org/jtreg/compare/jtreg-7.5.2+1...jtreg-8+2) * Require JDK 17 to build `jtreg` tool. [CODETOOLS-7904000](https://bugs.openjdk.org/browse/CODETOOLS-7904000) diff -Nru jtreg8-8.1+1+ds1/README.md jtreg8-8.3+1+ds1/README.md --- jtreg8-8.1+1+ds1/README.md 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/README.md 2026-06-21 20:26:05.000000000 +0000 @@ -12,14 +12,11 @@ * For details on running JDK tests using the JDK _make test_ framework, see [Using "make test" (the run-test framework)][make-test]. +* For details on running jtreg tests using the IntelliJ IDE, see + [plugins/idea/README.md](plugins/idea/README.md) + [faq]: https://openjdk.org/jtreg/faq.html [tagspec]: https://openjdk.org/jtreg/tag-spec.html [make-test]: https://github.com/openjdk/jdk/blob/master/doc/testing.md ## Using IntelliJ IDEA - -The `jtreg` repo also contains a plugin for the IntelliJ IDEA IDE. -This is a convenience plugin which adds `jtreg` capabilities to the IDE. -With this plugin, OpenJDK developers can write, run, and debug `jtreg` tests -without leaving their IDE environment. For more details, see the file -[plugins/idea/README.md](plugins/idea/README.md) in this repo. diff -Nru jtreg8-8.1+1+ds1/asmtools/.github/workflows/maven.yaml jtreg8-8.3+1+ds1/asmtools/.github/workflows/maven.yaml --- jtreg8-8.1+1+ds1/asmtools/.github/workflows/maven.yaml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/.github/workflows/maven.yaml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,47 @@ +name: Java CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + workflow_dispatch: + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest] + java-version: [ 17, 25 ] + fail-fast: false + + name: ${{ matrix.os }} - Java ${{ matrix.java-version }} - Maven + steps: + - name: Checkout asmtools repo + uses: actions/checkout@v2 + + - name: Set up JDK ${{ matrix.java-version }} + uses: actions/setup-java@v2 + with: + java-version: ${{ matrix.java-version }} + distribution: 'adopt' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.4 + with: + maven-version: 3.8.4 + + - name: Build asmtools with Maven + run: | + set -x + pwd + ls + cd maven ; + bash mvngen.sh ; + mvn "--batch-mode" "--update-snapshots" "clean" "install" + mvn "--batch-mode" "--update-snapshots" "test" + + diff -Nru jtreg8-8.1+1+ds1/asmtools/.gitignore jtreg8-8.3+1+ds1/asmtools/.gitignore --- jtreg8-8.1+1+ds1/asmtools/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/.gitignore 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +# Compiled class file +*.class + +# Log file +*.log + +# Package Files +*.jar +*.zip +*.tar.gz +*.tar + +# virtual machine crash logs +hs_err_pid* + +# Misc: Intellij Idea,Mac OS +/.idea/ +/maven/.idea/ +*.iml +.DS_Store + +maven/target +maven/src +maven/pom.xml diff -Nru jtreg8-8.1+1+ds1/asmtools/.hgtags jtreg8-8.3+1+ds1/asmtools/.hgtags --- jtreg8-8.1+1+ds1/asmtools/.hgtags 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/.hgtags 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,7 @@ +85d58e2683bfe2f70defd6ec10d377d84766ddd8 initial-openjdk +f201bb903e32f09e054f5fafc180508b9db67d00 6.0 +c52c3f68bfba5ca97378e9e9df5fc1268ac9e481 7.0 +f788f629bb40b3f3dd6d2cd25f3c9072568792de 7.0-b02 +2931522b78a4a4842396ad61300853911caf4169 7.0-b04 +b63cf0206a26c9cef5831aec217ed88a5ba09f5a 7.0-b05 +5d0dc302199d510f0fb44763fbca8118d12f8ad8 7.0-b06 diff -Nru jtreg8-8.1+1+ds1/asmtools/.jcheck/conf jtreg8-8.3+1+ds1/asmtools/.jcheck/conf --- jtreg8-8.1+1+ds1/asmtools/.jcheck/conf 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/.jcheck/conf 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +; +; Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +; +; This code is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License version 2 only, as +; published by the Free Software Foundation. +; +; This code is distributed in the hope that it will be useful, but WITHOUT +; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; version 2 for more details (a copy is included in the LICENSE file that +; accompanied this code). +; +; You should have received a copy of the GNU General Public License version +; 2 along with this work; if not, write to the Free Software Foundation, +; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +; +; Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +; or visit www.oracle.com if you need additional information or have any +; questions. +; + +[general] +project=code-tools +repository=asmtools +jbs=codetools + +[checks] +error=author,committer,whitespace,executable,symlink + +[census] +version=0 +domain=openjdk.org + +[checks "whitespace"] +files=.*\.java$|.*\.c$|.*\.h$|.*\.cpp$|.*\.hpp$ diff -Nru jtreg8-8.1+1+ds1/asmtools/LICENSE jtreg8-8.3+1+ds1/asmtools/LICENSE --- jtreg8-8.1+1+ds1/asmtools/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/LICENSE 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,347 @@ +The GNU General Public License (GPL) + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you +can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for +a fee, you must give the recipients all the rights that you have. You must +make sure that they, too, receive or can get the source code. And you must +show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program proprietary. +To prevent this, we have made it clear that any patent must be licensed for +everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included +without limitation in the term "modification".) Each licensee is addressed as +"you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is +not restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as +you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the +Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may +at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus +forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all of +these conditions: + + a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole or + in part contains or is derived from the Program or any part thereof, to be + licensed as a whole at no charge to all third parties under the terms of + this License. + + c) If the modified program normally reads commands interactively when run, + you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms +of this License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on +the Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and +2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above + on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only + for noncommercial distribution and only if you received the program in + object code or executable form with such an offer, in accord with + Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code +distributed need not include anything that is normally distributed (in either +source or binary form) with the major components (compiler, kernel, and so on) +of the operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source +code from the same place counts as distribution of the source code, even though +third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. +However, nothing else grants you permission to modify or distribute the Program +or its derivative works. These actions are prohibited by law if you do not +accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor to +copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance by +third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly through +you, then the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In +such case, this License incorporates the limitation as if written in the body +of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the +General Public License from time to time. Such new versions will be similar in +spirit to the present version, but may differ in detail to address new problems +or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any later +version", you have the option of following the terms and conditions either of +that version or of any later version published by the Free Software Foundation. +If the Program does not specify a version number of this License, you may +choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE +PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, +YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE +PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + One line to give the program's name and a brief idea of what it does. + + Copyright (C) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it +starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes + with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free + software, and you are welcome to redistribute it under certain conditions; + type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + 'Gnomovision' (which makes passes at compilers) written by James Hacker. + + signature of Ty Coon, 1 April 1989 + + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General Public +License instead of this License. + + +"CLASSPATH" EXCEPTION TO THE GPL + +Certain source files distributed by Oracle America and/or its affiliates are +subject to the following clarification and special exception to the GPL, but +only where Oracle has expressly included in the particular source file's header +the words "Oracle designates this particular file as subject to the "Classpath" +exception as provided by Oracle in the LICENSE file that accompanied this code." + + Linking this library statically or dynamically with other modules is making + a combined work based on this library. Thus, the terms and conditions of + the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules, + and to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent module, + the terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. If + you modify this library, you may extend this exception to your version of + the library, but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. diff -Nru jtreg8-8.1+1+ds1/asmtools/README.html jtreg8-8.3+1+ds1/asmtools/README.html --- jtreg8-8.1+1+ds1/asmtools/README.html 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/README.html 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,417 @@ + + + + + + README - AsmTools - Version 9.1 + + + + + + + + + + + + + + + + +
 
+
+

Release Notes

+

AsmTools 9.1

+ +

January 2026

+
+
 
+


+[Skip TOC]

+

Table of Contents

+
+
Introduction
+
New in This Release
+
System Requirements
+
Release Contents
+
Installation
+
Using AsmTools
+
Known Bugs and Issues
+
Obtaining Sources
+
Building from Sources
+
Contribute
+
+ +

Introduction

+

+AsmTools is a software package containing a collection of tools that you can use to encode and decode a Java class file, without using a Javac compiler. +You can use AsmTools to create class files which can not normally be produced by a compiler. These class files can be used during the +development process to test the compliance of a Virtual Machine (VM) to its specification.

+

+These release notes contain information about the ASM Tools version 9.1.
+See the ( +CodeTools project) +AsmTools OpenJDK project page for more information about AsmTools. +

+ + + + +

New in This Release

+

New Features

+

+

+ + + + + + + + + + + + + + + + +
Bug ID Description
+ CODETOOLS-7904123 + + Switch the Asmtools build system to use JDK 17 (LTS) in alignment with jtreg +
+ CODETOOLS-7903806 + + Enhance jasm/jdis to support value classes and objects +
+

+

+ +

Fixed Bugs

+

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug ID Description
+ CODETOOLS-7902055 + + Preserve module name in jdec output +
+ CODETOOLS-7904095 + + jdis,jasm: tools that read or write reference types may corrupt Constant Pool entries +
+ CODETOOLS-7904065 + + Classfile version < 45 synthetic methods should not set ACC_SYNTHETIC +
+ CODETOOLS-7904032 + + jasm: Incorrectly processes empty SourceDebugExtension attribute +
+ CODETOOLS-7904019 + + jdis: Incorrectly processes lookupswitch, wide, and tableswitch instructions with an incorrect structure +
+ CODETOOLS-7904014 + + jasm: the jasm incorrectly parses the PermittedSubclasses/NestMembers attribute +
+ CODETOOLS-7902696 + + jdis: the tool does't catch circular references in bsm args +
+ +

+

System Requirements

+

+Using ASM Tools requires a properly configured, certified ava Platform, Standard Edition version 17 or later +

+ + +

Installation

+To install the AsmTools, simply unzip the  asmtools-9.1.zip +distribution file in the directory of your choice. Optionally, you may +wish to define an environment variable (ASMTOOLS_HOME) to point to this +location for your convenience. + + +

Release Contents

+

+This section lists the components under the base subdirectory structure +(asmtools-9.1/) +that is created when you unzip the AsmTools distribution archive during +installation. +

+

Important Component Descriptions and Locations

+ + + + + + + + + + + + + + + +
ComponentDescription
README.htmlThe AsmTools release notes (this document).
lib/asmtools.jarThe AsmTools library.
+
+ + + +

Using AsmTools

+

AsmTools have the following synopsis:

+
+
java -jar ${ASMTOOLS_HOME}/asmtools.jar TOOL FILE
[TOOL="jasm" | "jdis" | "jcoder" | "jdec"]
[FILE=FILENAME.jasm (for jasm command) | FILENAME.jcod (for jcod command) | FILENAME.class for jdis, jdec command]

+
+

Examples:

+
+
+  % java -jar ${ASMTOOLS_HOME}/asmtools.jar jasm -d . FILENAME.jasm
+  (Produces FILENAME.class in the current directory.)
+  
+ % java -jar ${ASMTOOLS_HOME}/asmtools.jar jdis FILENAME.class + (Prints FILENAME.jasm to stdout.) +
+ % java -jar ${ASMTOOLS_HOME}/asmtools.jar jcoder -d . FILENAME.jcod + (Produces FILENAME.class in the current directory.) +
+ % java -jar ${ASMTOOLS_HOME}/asmtools.jar jdec -d . FILENAME.class + (Produces FILENAME.jcod in the current directory.) +
+
+ +Tool usage is covered in the "Using AsmTools". +
+

Operating Modes

+

There are no operating modes.

+

[Top]

+

+

Known Bugs and Issues

+

+Many attributes (in the class file, as specified by the + +Java VM Specification, Chapter 4) + + are covered in the JASM syntax, but not all. +

+

[Top]

+

+

Contribute

+The AsmTools open source project was created in order to develop a community that will improve it, further the development of Java assembly tools, and use Java assemblers to develop test suites. We encourage you to browse, download, contribute, and get involved. +

+ +

[Top]

+

+

Obtaining the Sources

+

+The sources for ASM Tools 9.1 and later is available via the community +OpenJDK project. The sources are stored +and accessed through a Mercurial repository, which the public may access in a +read-only fashion. Committing to changes to the sources is accomplished by +first contributing through a proxy developer to establish ones self, which can +then lead to rights to contribute directly. More information can be found on +the OpenJDK Projects landing page. +

+ +

+ The general form for obtaining a copy of the current source tree is:

+
+% git clone https://github.com/openjdk/asmtools
+
+This places a copy of the entire source tree in the asmtools directory. From +that directory, you can then view and build the sources, as described in the next +section. Note that this copy is of the development version of the sources, +you may need to extract a different revision if you want a copy from a specific +period of time. + +

[Top]

+

+

Building the Sources

+

+Building the sources requires Ant version 1.8 or later (1.10.13 is current at the +time of writing), and the built-in build is compatible with using an IDE. +The sources are designed for Java 17 and if you invoke ant with this +runtime, your chance of encountering an abnormal conditions due to your runtime +or compiler (or javadoc) version. +

+ +

+General requirements: +

+ + +

+The general steps to take a build from source from the command line: +

+
    +
  1. Obtain Sources +
  2. Make your current directory <topdir>/build/ +
  3. Invoke ant:
    % ant +
  4. Output appears in a directory above (one above <topdir>), + such as: ../../asmtools-9.1-build/ +
+ +

+A common variation of the build command to force ant to use a particular +installation of Java on your machine: +

+
+# JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home ANTHOME=/usr/share/ant ant
+
+This example for common *nix shells (zsh, bash, sh), alter it as needed for your +command environment. You can test your invocation of ant by running it with +the -diagnostics flag, where it will indicate which Java it is +using. + +

+The build file itself is build/build.xml, this is the file you can +specify in your IDE for building. +

+ + +


+

+ +
+

Copyright © 2008, 2026, Oracle and/or its affiliates. All rights reserved.

+ Use is subject to license terms.The majority of the Assember Tools project is released under the GNU + General Public License Version 2 (GPLv2)

+ + diff -Nru jtreg8-8.1+1+ds1/asmtools/README.md jtreg8-8.3+1+ds1/asmtools/README.md --- jtreg8-8.1+1+ds1/asmtools/README.md 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/README.md 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,23 @@ +# OpenJDK AsmTools + +The AsmTools open source project is used to develop tools for the production of proper and improper Java `.class` files. AsmTools are being opened in order to facilitate a community of Java .class file production for various testing and other OpenJDK development applications. + +Tool usage is covered in the Using AsmTools documentation. + +AsmTools consist of a set of (Java class file) assembler/disassemblers: + ++ **Jasm/Jdis** - an assembler language that provides a Java-like declaration of member signatures, while providing Java VM specification compliant mnemonics for byte-code instructions. Jasm also provides high-level syntax for constructs often found within classfile attributes. Jasm encoded tests are useful for sequencing byte codes in a way that Javac compiled code might not normally sequence byte-codes. + ++ **JCod/JDec** - an assembler language that provides byte-code containers of class-file constructs. JCod encoded tests are useful for testing the well-formedness of class-files, as well as creating collections within a class-file construct that might be size-bounded by a normal Java compiler. JCod can also be used to 'fuzz' class files in a methodical way that respects class-file constructs. + +AsmTools are completely reflexive - Java binary (.class) files may be disassembled into textual representations, which in turn can be assembled back to the same binary file. + +AsmTools are developed to support the latest class file formats, in lock-step with JDK development. + +Other open source Java assembler tools and binary classfile frameworks exist. They can be used for the purpose of synthesizing classfiles, however: +- they typically are designed to enforce the limits imposed by the VM specification of the class file format. They are not designed to produce classes that violate those limits. +- other assembler tools may not necessarily follow strict Java mnemonics as defined in the Java VM spec. +- other assembler tools may not stay in lock-step with the current generation of the JDK and VM specifications. +- class file libraries are harder to use for simple manipulations of any given class file. Typically, one has to create a program in that framework to parse and modify a class for a specific change to a given class. + +The AsmTools open source project is part of the [Code Tools Project](http://openjdk.java.net/projects/code-tools/ "Code Tools Project"). It exists to promote a community that will improve it, further its development, and use it to develop test suites. We encourage you to browse, download, contribute, and get involved. diff -Nru jtreg8-8.1+1+ds1/asmtools/build/build.properties jtreg8-8.3+1+ds1/asmtools/build/build.properties --- jtreg8-8.1+1+ds1/asmtools/build/build.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/build/build.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,32 @@ +# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +# Compile in verbose mode +javac.verbose=false +# Compile in debug mode +javac.debug=true +# Compile with deprecation flag +javac.deprecation=false +javac.release.version=17 +# path to output directory +BUILD_DIR = ../../asmtools-${PRODUCT_VERSION}-build diff -Nru jtreg8-8.1+1+ds1/asmtools/build/build.xml jtreg8-8.3+1+ds1/asmtools/build/build.xml --- jtreg8-8.1+1+ds1/asmtools/build/build.xml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/build/build.xml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Usage: + ant <TARGET> -D<OPTIONS> + + where TARGET is: + all cleans, tests, and builds if no issues are found. + build (default): builds all binaries, doc and distributions. + clean: removes all generated files and directories. + cleanAndBuild: cleans, then builds the project. + help: prints a usage message (this message). + + Other values for TARGET are: + devbuild: produces binaries and javadocs. + javadoc: produces javadocs. + test: runs tests. + cleanAndTest: cleans test artifacts, then tests the project. + clean-test: cleans tests artifacts. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ...${line.separator}${line.separator} + Current Java version is ${ant.java.version} + The build should be started by Java 17 or above + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SOURCE="git:${git.revision}" + VERSION="${PRODUCT_VERSION}_${PRODUCT_BUILDNUMBER}" + VERSION_DATE="${build.date}" + MILESTONE="${PRODUCT_MILESTONE}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/asmtools/build/productinfo.properties jtreg8-8.3+1+ds1/asmtools/build/productinfo.properties --- jtreg8-8.1+1+ds1/asmtools/build/productinfo.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/build/productinfo.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +# Path to JDK will be used to compile sources +# Product info +PRODUCT_NAME =asmtools +PRODUCT_JAR_NAME =asmtools.jar +PRODUCT_VERSION =9.1 +PRODUCT_MILESTONE =ea +PRODUCT_BUILDNUMBER =01 +PRODUCT_NAME_LONG =Java Assembler Tools diff -Nru jtreg8-8.1+1+ds1/asmtools/docs/Class00.jasm jtreg8-8.3+1+ds1/asmtools/docs/Class00.jasm --- jtreg8-8.1+1+ds1/asmtools/docs/Class00.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/docs/Class00.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ +package org/openjdk/asmtools/source00; + +public super class Class00 version 67:0 +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + public static Method main:"([Ljava/lang/String;)V" + stack 0 locals 1 + { + return; + } + + SourceFile "Class00.java"; +} // end Class org/openjdk/asmtools/source00/Class00 compiled from "Class00.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/docs/Class00.java jtreg8-8.3+1+ds1/asmtools/docs/Class00.java --- jtreg8-8.1+1+ds1/asmtools/docs/Class00.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/docs/Class00.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,5 @@ +package org.openjdk.asmtools.source00; +public class Class00 { + public static void main(String argv[]) { + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/docs/Class00_1.jasm jtreg8-8.3+1+ds1/asmtools/docs/Class00_1.jasm --- jtreg8-8.1+1+ds1/asmtools/docs/Class00_1.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/docs/Class00_1.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,21 @@ +file Cls01 +package org/openjdk/asmtools/source00; + +public super class Class00 version 67:0 +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + public static Method main:"([Ljava/lang/String;)V" + stack 0 locals 1 + { + return; + } + + SourceFile "Class00.java"; +} // end Class org/openjdk/asmtools/source00/Class00 compiled from "Class00.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/docs/UsingTools.md jtreg8-8.3+1+ds1/asmtools/docs/UsingTools.md --- jtreg8-8.1+1+ds1/asmtools/docs/UsingTools.md 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/docs/UsingTools.md 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,337 @@ +## Chapter 1 +### Java Assembler Tools (AsmTools) User’s Guide + +--- + +### Using the AsmTools + +This chapter describes general principles and techniques for using the AsmTools. + +If no command-line options are provided, or they are invalid, the tools display +error messages and usage information. To get the help message, launch AsmTools +without parameters: + +```bash +java -jar asmtools.jar +``` + +The help system describes how to use all the AsmTools components and contains +the following topics described in this chapter. + +- [Assemblers and Disassemblers](#BADGCIGA) +- [JASM vs JCOD](chapter2.html#BADGCIGB) +- [Tool Usage](#BADCEIIF) + - [ASMTools (Launcher)](BADCEABC) + - [JASM](#BADEFIIJ) + - [JDIS](#BADCBFCE) + - [JCODER](#BADIFAIE) + - [JDEC](#BADHJAHI) + +--- + + +### Assemblers and Dissassemblers + +Assembly and disassembly are reflexive operations. One tool’s output can be fed +into another to reproduce the same file. + +```bash +java -jar asmtools.jar jdec Foo.class # produces Foo.jcod +java -jar asmtools.jar jcoder Foo.jcod # produces Foo.class + +java -jar asmtools.jar jdis Foo.class # produces Foo.jasm +java -jar asmtools.jar jasm Foo.jasm # produces Foo.class +``` + +For a given `foo.class`, the result of disassembly followed by reassembly is the +same `foo.class`. + +--- + + +### JASM vs JCOD + +Which format to use depends on the task you are trying to do. +We can describe some generalizations of when you might wish to use the `JASM` format versus the `JCOD` format. + +#### JASM + +The biggest difference between the two formats is that `JASM` specifically focuses on representing byte-code instructions in the VM format +(while providing minimal description of the structure of the rest of the class file). +Generally, `JASM` is more convenient for semantic changes, like change to instruction flow. + +Typical JASM use cases: + +- Producing invalid classes in which two methods have the same signature +- Producing invalid class references that use illegal types +- Generating invalid classes with missing or removed instructions +- Inserting instrumentation or profiling instructions into methods +- Creating classes in which language keywords are used as identifiers +- Verifying that two classes produced by different compilers are equivalent + +#### JCOD + +`JCOD` provides good support for describing the structure of a class file +(as well as writing incorrect bytes outside of this structure), +and provides no support for specifying byte-code instructions (simply raw bytes for instructions). +`JCOD` is typically used for VMs to test Well-formedness of class files (e.g. extra or missing bytes), +boundary issues, constant-pool coherence, constant-pool index coherence, attribute well-formedness, etc. + +Typical JCOD use cases: + +- Examining specific parts of a class file, such as: + - the constant pool (for dependency analysis) + - constant values + - inheritance chains (superclasses) + - interface implementation and resolution +- Producing malformed or structurally invalid class files for JVM testing +- Validating class-file well-formedness rules +- Testing boundary conditions and structural constraints +- Verifying attribute structure and consistency + +--- + + +### Tool Usage + +AsmTools consists of the following utilities: + +- [jasm](#BADEFIIJ) – Generates class files from `JASM` +- [jdis](#BADCBFCE) – Disassembles class files into `JASM` +- [jcoder](#BADIFAIE) – Generates class files from `JCOD` +- [jdec](#BADHJAHI) – Disassembles class files into `JCOD` + +Each utility can be invoked as: + +```bash +java -jar asmtools.jar UTILITY [options] File1 ... +``` +or +```bash +java -cp asmtools.jar com.sun.asmtools.UTILITY.Main [options] File1 ... +``` +Each utility supports own set of options. + +--- +**Note**: See the following sections for the options associated with each tool. + +--- + + +### ASMTools (Launcher) + +The `asmtools.jar` launcher provides a single entry point to run one of the AsmTools utilities (`jasm`, `jdis`, `jcoder`, or `jdec`) +and to display global help/version information. + +**Usage**: +```text +java -jar asmtools.jar run jasm, jdis, jcoder, or jdec tool +or: java -jar asmtools.jar -?|-h|-help print Help (this message) and exit +or: java -jar asmtools.jar -version print version information and exit + +use -dls switch to return the ancient dual stream logging +``` + +--- + + +### JASM + +`JASM` assembles a `.jasm` source file, written according to the [JASM Specification](JASM_SPEC), into a `.class` file +for use with a Java Virtual Machine. + +**Usage**: +```text +java -jar asmtools.jar jasm [options] |- +``` +or +```text +java -cp asmtools.jar org.openjdk.asmtools.jasm.Main [options] |- +``` + +**Note**: if `-` is provided, `` is used as the input stream. + +#### Options: + +```text + -d Specify where to place generated class files, otherwise + -w Specify where to place generated class files, without considering the classpath, otherwise + -nowrite Do not write generated class files + -nowarn Do not print warnings + -strict Consider warnings as errors + -cv Set operating class file version if not specified in the source file (by default 45.3) + -fixcv Override class file version in source file(s) + -fixcv Update class file version to major.minor if file's version is below the threshold() + -t Print debug, trace information + -v Print additional information + -version Print the jasm version +``` +#### Notes: +1. **Class-file generation behavior** + +
The `-nowrite` option always suppresses generation of the `.class` file.
+ Without `-nowrite`, warnings prevent class-file generation only when `-strict` is specified; otherwise, the class file is written. +

+ +2. **Class‑file version selection (`-cv` vs `-fixcv`)** + +
In typical usage, a `.jasm` file explicitly specifies the class‑file version in + its header, for example: + + ```text + public super class Foo version 55:0 {} + ``` + + If the version is not specified in the source file, `JASM` defaults to **45.3**. + + The `-cv` option provides a *fallback* version and is used *only if the source + file does not declare a version*. If a version is present in the `.jasm` file, + it takes precedence over `-cv`. + + To force the class‑file version regardless of whether the source declares one, + use `-fixcv`. This option overrides the version unconditionally. + + The `-cv` and `-fixcv` options were added primarily to support batch updates of + large sets of `.jasm` files. In general, it is preferable to specify the correct + class‑file version directly in the `.jasm` source. + +--- + + +### JDIS + +`JDIS` is a disassembler that accepts a `.class` file specified by filename, translates it into plain-text jasm source, +and writes the result to standard output or, when `-d ` is specified, to a generated `.jasm` file in the given directory. + +**Usage**: +```text +java -jar asmtools.jar jdis [options] |- +``` +or +```text +java -cp asmtools.jar org.openjdk.asmtools.jdis.Main [options] |- +``` + +**Note**: if `-` is provided, `` is used as the input stream. + +#### Options: + +```text + -d Specify where to place generated class files, otherwise + -w Specify where to place generated class files, without considering the classpath, otherwise + -g Generate a detailed output format. + -gg Generate a detailed output format. This includes displaying + the pair of this_class and super_class. + -nc Don't print comments + -table Print specific attributes in a table format resembling the style of the 'javap' command. + -hx Generate floating-point constants in hexadecimal format. + -pc Print instruction offsets when the output is not detailed with the options -g or -gg. + -sysinfo Show system info (path, size, date, SHA-256 hash) of class being processed + -lnt: + Print the LineNumberTable attribute in a Code attribute: + table - print the LineNumberTable attribute as a table + numbers - print numbers of source lines in inlined comments + lines - print Java source lines if a class file with LineNumberTable attribute and Java source file are in the same folder + all - print both line numbers and Java source lines in inlined comments, and LineNumberTable attribute as a table + The '-lnt' without parameters functions the same way as '-lnt:all' + -lvt: + Print LocalVariableTable,LocalVariableTypeTable attributes in a Code attribute: + vars - print LocalVariableTable attribute + types - print LocalVariableTypeTable attribute + all - print both LocalVariableTable and LocalVariableTypeTable attributes + The '-lvt' without parameters functions the same way as '-lvt:all' + -drop: + Discard some attributes or their groups where: + source - SourceFile attribute + classes - this_class, super_class pair + all - SourceFile attribute, this_class and super_class pair + The '-drop' without parameters functions the same way as '-drop:all' + -best-effort Print as much information as possible despite errors; suppresses the -v option. + -version Print the program version + -t Print debug, trace information + -v Print additional information +``` +#### Notes: +1. **Line Number and Source Line Generation (-lnt option)** + +
The `-lnt[:numbers|lines|table|all]` option controls how `LineNumberTable` information is printed. + Depending on the mode, it can print line numbers as inline comments, include Java source lines above the corresponding instructions, + display the LineNumberTable attribute as a table, or combine all of these. + Specifying `-lnt` without parameters is equivalent to `-lnt:all`. + Printing source lines in comments requires both the `LineNumberTable` and `SourceFile` attributes to be present, + and the corresponding *Java source file must be located in the current working directory*. + +Refer to the [JASM Assembler](JASM_SPEC) documentation for information on the structure of the resultant `.jasm` file. + + +--- + + +### JCODER + +`JCODER` is a low-level assembler that accepts text conforming to the [Jcoder Specification.](JCODER_SPEC) and +produces a `.class` file for use by a Java Virtual Machine. + +Its primary purpose is to generate specialized tests for validating JVM implementations. + +**Usage**: +```text +java -jar asmtools.jar jcoder [options] |- +``` +or +```text +java -cp asmtools.jar org.openjdk.asmtools.jcoder.Main [options] |- +``` + +**Note**: if `-` is provided, `` is used as the input stream. + +#### Options: +```text + -d Specify where to place generated class files, otherwise + -w Specify where to place generated class files, without considering the classpath, otherwise + -nowrite Do not write generated class files + -ignore Ignore non-fatal error(s) that suppress writing class files + -fixcv Override class file version in source file(s) + -fixcv Update class file version to major:minor if file's version is below the threshold() + -t Print debug, trace information + -v Print additional information + -version Print the program version +``` + +--- + + +### JDEC + +`JDEC` is a low-level disassembler that accepts a `.class` file specified by filename, translates it into plain-text `jcov` source, +and writes the result to standard output or, when `-d ` is specified, to a generated `.jcov` file in the given directory. + +**Usage**: +```text +java -jar asmtools.jar jdec [options] |- +``` +or +```text +java -cp asmtools.jar org.openjdk.asmtools.jdec.Main [options] |- +``` + +**Note**: if `-` is provided, `` is used as the input stream. + +#### Options: + +```text + -d Specify where to place generated class files, otherwise + -w Specify where to place generated class files, without considering the classpath, otherwise + -g Generate a detailed output format + -v Print additional information + -version Print the program version +``` + +Refer to the [Jcoder Low-Level Assembler](JCODER_SPEC) documentation for information on the structure of the resultant `.jcod` +file. + +--- +*Java Assembler Tools (AsmTools) User’s Guide* + +--- +Copyright © 2012, 2025, Oracle and/or its affiliates. All rights reserved. diff -Nru jtreg8-8.1+1+ds1/asmtools/docs/jasm.html jtreg8-8.3+1+ds1/asmtools/docs/jasm.html --- jtreg8-8.1+1+ds1/asmtools/docs/jasm.html 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/docs/jasm.html 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,2257 @@ + + + + + + + + JASM Syntax + + + + + + + + + + + + + + + + + + + + + + + + +
APPENDIX  + + + + + + A
+
+

+

JASM Syntax
+

+ +

This chapter describes JASM syntax, and how to encode class files +using this +syntax. Jasm is a java +assembler that accepts text in the JASM +format and produces a .class file for use +with a Java Virtual Machine. Jasm's +primary +use +is +as +a +tool for producing specialized tests for testing a JVM +implementation
+

+

+This chapter describes JASM syntax in the following sections: +

+ +

+ + +
+

General Syntax

+

+JASM syntax can come in one of two variations: short-form or +verbose-form.  Short form uses Java-style names to refer to items +in a constant-pool.  Verbose form uses explicit constant-pool +indexes to refer to items in the constant pool.  The normal output +from JDIS produces jasm files in the short-form.  Using the -g +option for JDIS (ie.  jdis -g file.class) produces JASM source in +the verbose-form.
+

+

The source text file can be free form (newlines are considered +blanks) +and may contain Java-style commenting. +The first line of a JASM file represents the name of the resulting +file in the destination directory. This name does not affect the +content of +the resulting file. This line has two forms: +

+

+

+
file FILENAME 
+or +
class CLASSNAME 
+In the latter case, extension .class will be added to +form FILENAME. Jasm's -d option allows you to define the +destination +directory. A list of structured dataWriter items follows the class name. The +length (in bytes) of each item +is determined by its representation.
+

+
+
+

Description formats

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TERM1|TERM2 TERM1 or TERM2 (not both)
[TERM] TERM is optional
TERM... TERM repeated 1 or more times
[TERM...] TERM repeated 0 or more times
"sequence of" all the following terms are mandatory, in the order given.
"set of" any of following terms, or none of them, +may appear in any order. However, repetitions are not allowed.
"list of" any of following terms, or none of them, +may appear in any sequence. If more than one term appear, they are +separated by commas (',')
+

+
+

Lexical Structure

+

The source text file can be free form (newlines, tabs, and blank +spaces are equivalent). Additionally, the source may contain standard +Java +and C++ comments.

+

STRING, NUMBER, and IDENT +are treated the same as in +the Java Language Specification. One difference is that LETTERs include +also `/', `<', `>', `(', and `)' .

+
+
STRING:
+
" [ STRING_CHARACTER... ] "
+
NUMBER:
+
DIGIT...
+
IDENT:
+
LETTER [ LETTER_OR_DIGIT ...]
+
ACCESS (depends on the context): +set of
+
abstract final interface native private protected public +static super synchronized transient volatile deprecated synthetic +bridge varargs
+
+

Not all access bits make sense for all declarations: for example, +the +"super" and "interface" access flags are applied to classes only.

+

If an access bit is used improperly, +the assembler prints a warning, but places the bit in the access +set.

+

Note that deprecated and synthetic +keywords +are not translated to access flags in the Java sense. +For these jasm generates a corresponding Deprecated +or Synthetic attributes instead of access bits. The synthetic +access flag is used to mark compiler generated +members not +seen in the source (for example, a field reference to an anonymous +outer class).

+
+
TAG: one of
+
int float long double Asciz String class Field Method +NameAndType InterfaceMethod MethodType MethodHandle InvokeDynamic Dynamic +
+
+Local names represent labels, rangePC-labels and local variables. Their +scope is constrained by method parenthesis. +
+
LOCAL_NAME:
+
IDENT
+
+

 

+
+
CONSTANT_INDEX:
+
#NUMBER
+
+

Each CONSTANT_INDEX represents a reference into the constant pool +at the specified location.

+
+
+

General Class Structure

+
+
INTERFACES:list of
+
CONSTANT_CELL(class|@interface|interface)
+
TOP_LEVEL_COMPONENT: one of
+
CONSTANT_DECLARATION FIELD_DECLARATION METHOD_DECLARATION +INNER_CLASS_DECLARATIONS
+
CLASS: sequence of
+
ANNOTATIONS CLASS_ACCESS CONSTANT_CELL(class|@interface|interface) [extends +CONSTANT_CELL(class)] +[implements INTERFACES] [version INTEGER:INTEGER] { +[TOP_LEVEL_COMPONENT...] }
+
CLASS_ACCESS: +list +of
+
[public][final][super][interface][abstract][synthetic][annotation][enum]
+
+

+The extends CONSTANT_CELL(class) clause places the +"super" element of the +class file. The implements INTERFACES clause places the +table of interfaces. +Since the assembler does not distinguish interfaces and ordinary +classes +(the only difference is one access bit), the table of interfaces of an +interface class must be declared with implements keyword, +and not extends, as in Java language. +

+

+Note:The last two rules allow TOP_LEVEL_COMPONENT +to appear in any order and number. For example, you can split constant +pool table into several parts, mixing constants and method +declarations. +

+
+

General Module Structure

+
+
MODULE: sequence of
+
ANNOTATIONS [MODULE_FLAGS] moduleContent CONSTANT_CELL(moduleContent) [version INTEGER:INTEGER] {[TOP_LEVEL_MODULE_PROPERTIES...]}
+
TOP_LEVEL_MODULE_PROPERTIES: one of
+
MODULE_REQUIRES MODULE_EXPORTS MODULE_OPENS MODULE_USES MODULE_PROVIDES
+
MODULE_FLAGS:set + of
+
[open]
+
+
+ +

General Source File Structure

+
+
PACKAGE_DECLARATION:
+
package IDENT;
+
+Package declaration can appear only once in source file. +
+
CLASS_FILE: sequence of
+
PACKAGE_DECLARATION CLASS...
+
+
+
MODULE_FILE:
+
MODULE...
+
+
+
SOURCE_FILE:
+
MODULE_FILE|CLASS_FILE
+
+
+ +

The Constant Pool and Constant Elements

+

+A CONSTANT_CELL refers to an element in the constant +pool. +It may refer to the element either by its index or its value: +

+
+
CONSTANT_CELL:
+
CONSTANT_INDEX
+ TAGGED_CONSTANT_VALUE
+
+Generic rule for TAGGED_CONSTANT_VALUE is: +
+
TAGGED_CONSTANT_VALUE:
+
[TAG] CONSTANT_VALUE
+
+

+A TAG may be omitted when the context only allows one kind of a tag. +For example, the argument of an anewarray instruction +should be a CONSTANT_CELL which represents a class, so +instead of +

+
    anewarray class java/lang/Object

+one may write: +
    anewarray java/lang/Object
+It is possible to write another tag, e.g.: +
    anewarray String java/lang/Object
+However, the resulting program will be incorrect. +

+

Another example of an implicit tag (eg. a context which implies tag) +is the header of a class declaration. You may write: +

+
    aClass {
}
+which is equivalent to: +
    class aClass {
}
+Below, the tag implied by context will be included in the rules, e.g.: +
    CONSTANT_VALUE(int).
+

+The exact notation of CONSTANT_VALUE depends on the +(explicit or implicit) TAG. +

+
+
TAGGED_CONSTANT_VALUE:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int INTEGER  
long [INTEGER|LONG]  
float [FLOAT|INTEGER]  
float bits INTEGER  
double [FLOAT|DOUBLE|INTEGER|LONG]  
double [bits INTEGER | bits LONG]  
Asciz EXTERNAL_NAME  
class CONSTANT_NAME  
String CONSTANT_NAME  
NameAndType NAME_AND_TYPE  
Field CONSTANT_FIELD  
Method CONSTANT_FIELD  
ReferenceIndex [Method|InterfaceMethod]  
MethodHandle [INVOKESUBTAG|INVOKESUBTAG_INDEX] : CONSTANT_FIELD | [FIELDREF|METHODREF|INTERFACEMETHODREF]
MethodType CONSTANT_NAME
InvokeDynamic + INVOKESUBTAG : CONSTANT_FIELD : NAME_AND_TYPE [INVOKEDYNAMIC_STATIC_ARGS]
moduleContent CONSTANT_NAME  
package CONSTANT_NAME  
+
+
+
+

Note
+When the JASM parser encounters an InvokeDynamic constant, it creates +an entry in +the BootstrapMethods attribute (the BootstrapMethods +attribute is produced if it +has not already been created). The entry contains a reference to the MethodHandle +item +in the constant pool, and, optionally, a sequence of references to +additional static +arguments (ldc-type constants) to the bootstrap +method

+
+

+INVOKESUBTAGs for MethodHandle and (const) InvokeDynamic are defined as +follows and can be presented as either an index or a tag: +

+
+
INVOKESUBTAG:             [INVOKESUBTAG_INDEX]
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
REF_GETFIELD [1]
REF_GETSTATIC [2]
REF_PUTFIELD [3]
REF_PUTSTATIC [4]
REF_INVOKEVIRTUAL [5]
REF_INVOKESTATIC [6]
REF_INVOKESPECIAL [7]
REF_NEWINVOKESPECIAL [8]
REF_INVOKEINTERFACE [9]
+
+
+

+Static arguments for an InvokeDynamic constant are defined as follows: +

+
+
INVOKEDYNAMIC_STATIC_ARGUMENTS:
+
INVOKEDYNAMIC_STATIC_ARG ',' ...
+
INVOKEDYNAMIC_STATIC_ARG: (one of)
+
INVOKEDYNAMIC_STATIC_ARG_CONSTANT_VALUE
+
+
+
INVOKEDYNAMIC_STATIC_ARG_CONSTANT_VALUE: + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int INTEGER
long [INTEGER|LONG]
float [FLOAT|INTEGER]
double [FLOAT|DOUBLE|INTEGER|LONG]
class CONSTANT_NAME
String CONSTANT_NAME
MethodHandle INVOKESUBTAG:CONSTANT_FIELD
MethodType CONSTANT_NAME
+
+
+

+INTEGER, LONG, FLOAT, and DOUBLE +correspond to IntegerLiteral +and FloatingPointLiteral as described in +The +Java +Language +Specification. If a double-word constant (LONG +or DOUBLE) is represented with a single-word value (INTEGER +or FLOAT, respectively), single-word value +is simply promoted to double-word, as described in +The +Java +Language +Specification. If floating-point constant (FLOAT +or DOUBLE) is represented with an integral value +(INTEGER or LONG, respectively), +the result depends on whether the integral number is preceded with the +keyword +"bits". If "bits" is not used, the result is a floating-point number +closest in value to the decimal number. If the keyword "bits" is used, +the floating-point constant takes bits of the integral value without +conversion. +

+

+Thus, +

+
   float 2;
+

means the same as

+ float 2.0f; +

and the same as

+ float bits 0x40000000; +

while

+ float bits 2; +

actually means the same as

+ float bits 0x00000002; +

and the same as

+ float 2.8026e-45f +
+

+

 

+
+
CONSTANT_NAME:
+
CONSTANT_INDEX
+EXTERNAL_NAME
+
EXTERNAL_NAME:
+
IDENT STRING
+
+

+External names are names of class, method, field, or type, which stay +in resulting .class file, and may be represented both by +IDENT or by STRING (which is useful when +name contains non-letter characters). +

+
+
NAME_AND_TYPE:
+
CONSTANT_INDEX
+ CONSTANT_NAME:CONSTANT_NAME
+
+

+In this second example, the first CONSTANT_NAME denotes +the name of a field and second denotes its type. +

+
+
CONSTANT_FIELD:
+
CONSTANT_INDEX
+ [CONSTANT_NAME.]NAME_AND_TYPE
+
+

+In this third example, CONSTANT_NAME denotes to the class +of a field. If CONSTANT_NAME is omitted, the current +class is +assumed. +

+
+

Constant Declarations

+

+Constant declarations are demonstrated in the examples below: +

+

const #1=int 1234
, #2=String "a string"
, #3=Method get:I
;
+
+
CONSTANT_DECLARATION:
+
const CONSTANT_DECLARATORS ;
+
CONSTANT_DECLARATORS: list of
+
CONSTANT_DECLARATOR
+
CONSTANT_DECLARATOR:
+
CONSTANT_INDEX = TAGGED_CONSTANT_VALUE
+
+
+ +

Field Variables

+
+
FIELD_DECLARATION:
+
ANNOTATIONS FIELD_ACCESS Field +FIELD_DECLARATORS ;
+
FIELD_DECLARATORS: list of
+
FIELD_DECLARATOR
+
FIELD_DECLARATOR:
+
EXTERNAL_NAME:CONSTANT_NAME [:SIGNATURE] [ = TAGGED_CONSTANT_VALUE ]
+
FIELD_ACCESS: +list +of
+
[public|private|protected][final][static][volatile][transient][synthetic][enum]
+
+Example: +
	public static Field 
field1:I = int 1234,
field2:"Ljava/lang/String;",
field3:"Ljava/util/List;":"Ljava/util/List<+Ljava/lang/String;>"
;

+

Access bits (public and static) are applied both to field1 and +field2. +The EXTERNAL_NAME denotes the name of the field, CONSTANT_NAME +denotes its type, TAGGED_CONSTANT_VALUE +denotes initial value. +

+
+ +

Method Declarations

+
+
METHOD_DECLARATION: sequence of
+
ANNOTATIONS METHOD_ACCESS Method
+EXTERNAL_NAME:CONSTANT_NAME
+[THROWS]
+STACK_SIZE
+[LOCAL_VAR_SIZE]
+{ INSTRUCTION_STATEMENT...
  ANNOTATIONS }
+
+

+The EXTERNAL_NAME denotes the name of the method, CONSTANT_NAME +denotes its type. +

+
+
METHOD_ACCESS: +list +of
+
[public|private|protected][static][final][synthetic][bridge][varargs][native][abstract][strict][synthetic]
+
+
+
THROWS:
+
throws EXCEPTIONS
+
EXCEPTIONS: list of
+
CONSTANT_CELL(class)
+
+

+The meaning of the THROWS clause is the same as in Java +Language Specification - it forms Exceptions attribute of a method. +Jasm itself does not use this attribute in any way. +

+
+
STACK_SIZE:
+
stack NUMBER
+
+

+The NUMBER denotes maximum operand stack size of the +method. +

+
+
LOCAL_VAR_SIZE:
+
locals NUMBER
+
+

+The NUMBER denotes number of local variables of the +method. If omitted, it is calculated by assembler according to the +signature of +the method and local variable declarations. +

+
+ +

Instructions

+
+

VM Instructions

+
+
INSTRUCTION_STATEMENT:
+
[NUMBER] [LABEL:] INSTRUCTION|PSEUDO_INSTRUCTION ; +
+
+

Jasm allows for a NUMBER +(which is ignored) at the beginning of each line. This is allowed in +order to remain consistent with the jdis disassembler. Jdis puts line +numbers in disassembled code that may be reassembled using Jasm +without any additional modifications.

+
+
INSTRUCTION:
+
OPCODE [ARGUMENTS]
+
ARGUMENTS: list of
+
ARGUMENT
+
ARGUMENT:
+
NUMBER LABEL LOCAL_VARIABLE TRAP_IDENT CONSTANT_CELL +SWITCHTABLE TYPE
+
LABEL:
+
NUMBER IDENT
+
LOCAL_VARIABLE:
+
NUMBER IDENT
+
TRAP_IDENT:
+
IDENT
+
TYPE:
+
NUMBER boolean byte char int float long double class +
+
SWITCHTABLE:
+
{ [NUMBER:LABEL...] [default:LABEL] }
+
+

SWITCHTABLE example: Java_text

+
     switch (x) {
case 11:
x=1;
break;
case 12:
x=2;
break;
default:
x=3;
}
+
+

will be coded in assembler as follows:

+
     tableswitch  {
11: L24;
12: L29;
default: L34
}
L24: iconst_1;
istore_1;
goto L36;
L29: iconst_2 ;
istore_1;
goto L36;
L34: iconst_3;
istore_1;
L36: ....
+
+

OPCODE is any mnemocode from the instruction set. +If mnemocode needs an ARGUMENT, it cannot be omitted. +Moreover, the kind (and number) of the argument(s) must match the kind +(and number) required by the mnemocode:

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
aload, astore, fload, fstore, +iload, istore, lload, lstore, +dload, dstore, ver, endvar: LOCAL_VARIABLE
iinc: LOCAL_VARIABLE, NUMBER
sipush, bipush, bytecode: NUMBER
tableswitch, lookupswitch: SWITCHTABLE
newarray: TYPE
jsr, goto, +ifeq, ifge, ifgt, ifle, iflt, ifne, +if_icmpeq, if_icmpne, if_icmpge, +if_icmpgt, if_icmple, if_icmplt, +if_acmpeq, if_acmpne, ifnull, ifnonnull, +try, endtry: LABEL
jsr_w, goto_w: LABEL
ldc_w, ldc2_w, ldc: CONSTANT_CELL
new, anewarray, instanceof, checkcast, CONSTANT_CELL(class)
multianewarrayNUMBER, CONSTANT_CELL(class) +
putstatic, getstatic, putfield, getfield: CONSTANT_CELL(Field)
invokevirtual, invokenonvirtual, invokestatic: CONSTANT_CELL(Method)
invokeinterface: NUMBER, CONSTANT_CELL(Method)
invokedynamic: CONSTANT_CELL(InvokeDynamic)
 aaload,  +aastore,  aconst_null,  aload_0,  aload_1,  +aload_2,  aload_3,  aload_w ,  areturn,  +arraylength,  astore_0,  astore_1,  astore_2,  +astore_3,  astore_w,  athrow,  baload,  +bastore,  caload,  castore,  d2f,  d2i,  +d2l,  dadd,  daload,  dastore,  dcmpg,  +dcmpl,  dconst_0,  dconst_1,  ddiv,  dead,  +dload_0,  dload_1,  dload_2,  dload_3,  dload_w +,  dmul,  dneg,  drem,  dreturn,  +dstore_0,  dstore_1,  dstore_2,  dstore_3,  +dstore_w,  dsub,  dup,  dup2,  dup2_x1,  +dup2_x2,  dup_x1,  dup_x2,  f2d,  f2i,  +f2l,  fadd,  faload,  fastore,  fcmpg,  +fcmpl,  fconst_0,  fconst_1,  fconst_2,  +fdiv,  fload_0,  fload_1,  fload_2,  fload_3,  +fload_w,  fmul,  fneg,  frem,  freturn ,  +fstore_0,  fstore_1,  fstore_2,  fstore_3,  +fstore_w,  fsub ,  i2b,  i2c,  i2d,  +i2f,  i2l,  i2s,  iadd,  iaload,  iand,  +iastore,  iconst_0,  iconst_1,  iconst_2,  +iconst_3,  iconst_4,  iconst_5,  iconst_m1,  +idiv,  iinc_w,  iload_0,  iload_1,  iload_2,  +iload_3,  iload_w,  imul,  ineg,  int2byte,  +int2char,  int2short,  ior,  irem,  ireturn,  +ishl,  ishr,  istore_0,  istore_1,  istore_2,  +istore_3,  istore_w,  isub,  iushr,  ixor,  +l2d,  l2f,  l2i,  label,  ladd,  laload,  +land,  lastore,  lcmp,  lconst_0,  lconst_1,  +ldiv,  lload_0,  lload_1,  lload_2,  lload_3,  +lload_w,  lmul,  lneg,  lor,  lrem,  +lreturn,  lshl,  lshr,  lstore_0,  lstore_1,  +lstore_2,  lstore_3,  lstore_w,  lsub,  +lushr,  lxor,  monitorenter,  monitorexit,  +nonpriv,  nop,  pop,  pop2,  priv,  ret,  +return,  ret_w,  saload,  sastore,  +swap,   wide
+
<No Arguments>
+

+ +

InvokeDynamic Instructions

+

InvokeDynamic instructions are instructions that allow +dynamic binding of methods to a call site. These instructions in JASM +form are rather complex, and the JASM assembler does some of the +necessary work to create a BootstrapMethods attribute for +entries of binding methods.

+
+
+class Test
+      version 51:0
+{
+    Method m:"()V"
+      stack 0 locals 1
+    {
+       invokedynamic InvokeDynamic REF_invokeSpecial:bsmName:"()V"   // information about bootstrap method
+                                                    :methName:"(I)I" // dynamic call-site name ("methName") plus the argument and return types of the call ("(I)I")
+                                                     int 1, long 2l; // optional sequence of additional static arguments to the bootstrap method (ldc-type constants)
+    }
+} // end Class Test
+
+

This JASM code has an invokedynamic instruction of the +form: invokedynamic InvokeDynamic (CONSTANT_CELL(INVOKEDYNAMIC)) +where the INVOKEDYNAMIC constant is represented as specified
+
+(i.e. invokedynamic InvokeDynamic INVOKESUBTAG : CONSTANT_FIELD +(bootstrapmethod signature) : NAME_AND_TYPE (CallSite) [Arguments +(Optional)] ).

+

The JASM assembler creates the appropriate constant entries and +entries into the BootstrapMethods attribute in a resulting class file.

+

You can also create InvokeDynamic constants and BootstrapMethods +explicitly:

+
+
	#22; //class Test3
version 51:0
{

const #1 = InvokeDynamic 0:#11; // REF_invokeSpecial:Test3.bsmName:"()V":name:"(I)I" int 1, long 2l
const #2 = Asciz "Test3";
const #3 = long 2l;
const #5 = class #6; // java/lang/Object
const #6 = Asciz "java/lang/Object";
const #7 = Asciz "name";
const #8 = int 1;
const #9 = Asciz "SourceFile";
const #10 = Asciz "Test3.jasm";
const #11 = NameAndType #7:#21; // name:"(I)I"
const #12 = Asciz "()V";
const #13 = Method #22.#17; // Test3.bsmName:"()V"
const #14 = Asciz "Code";
const #15 = Asciz "m";
const #16 = Asciz "BootstrapMethods";
const #17 = NameAndType #20:#12; // bsmName:"()V"
const #18 = Asciz "LineNumberTable";
const #19 = MethodHandle 7:#13; // REF_invokeSpecial:Test3.bsmName:"()V"
const #20 = Asciz "bsmName";
const #21 = Asciz "(I)I";
const #22 = class #2; // Test3
const #23 = class #6; // java/lang/Object



Method #15:#12
stack 0 locals 1
{
0: invokedynamic InvokeDynamic #1; // InvokeDynamic REF_invokeSpecial:Test3.bsmName:"()V":name:"(I)I" int 1, long 2l;
}

BootstrapMethod #19 #8 #3;

} // end Class Test3
+
+

In this example, const #1 = InvokeDynamic 0:#11; is +the +InvokeDynamic constant that refers to BootstrapMethod at index '0' in +the BootstrapMethods Attribute (BootstrapMethod #19 #8 +#3; which refers to the MethodHandle at const #19, +plus 2 other static args (at const #8 and const #3).

+
+ +

Pseudo Instructions

+
+

Pseudo instructions are 'assembler +directives', and not really instructions (in the VM sense) They +typically come in two forms: Code-generating Pseudo-Instructions, +and Attribute-Generating Pseudo-Instructions.

+ +

Code-Generating Pseudo-Instructions

+The bytecode directive +instructs the assembler to put a collection of raw bytes into the code +attribute of a methodK
+
+
+
bytecode NUMBERS
+
NUMBERS is list of NUMBERs (divided by COMMA).
+Insert bytes in place of the instruction. May have any number +of numeric arguments, each of them to be converted into a byte and +inserted in method's code.
+
+ +

Attribute-Generating Pseudo-Instructions

+

The rest of pseudo_instructions do not produce any bytecodes, and +are +used to form tables: local variable table, exception table,
+Stack Maps, and Stack Map Frames. Line Number Tables can not be +specified, but they are constructed +by the assembler itself.

+
+

Local Variable Table Attribute Generation

+
+
var LOCAL_VARIABLE
+
Starts local variable range
+
endvar LOCAL_VARIABLE
+
Ends local variable range. LOCAL_VARIABLE means name or index +of local variable table entry.
+
+

Example:

+
    static void main (String[] args) {
Tester inst = new Tester();
inst.callSub();
}

+

will be coded in assembler as +follows:

+
+
+
+
static Method #8:#9	 // main:"([Ljava/lang/String;)V"
stack 2 locals 2
{
4 var 0; // args:"[Ljava/lang/String;"
0: new #1; // class Tester;
3: dup;
4: invokespecial #2; // Method "<init>":"()V";
7: astore_1;
6 var 1; // inst:"LTester;"
8: aload_1;
9: invokevirtual #3; // Method callSub:"()V";
7 12: return;
endvar 0, 1;

}
+
+
+
+

Exception Table Attribute Generation

+

To generate exception table, three pseudo-instructions are used. +

+
+
+
try TRAP_IDENT
+
Starts rangePC range
+
endtry TRAP_IDENT
+
Ends rangePC range
+
catch TRAP_IDENT CONSTANT_CELL(class) +
+
Starts exception handler.
+
+
+

TRAP_IDENT represents the +name or number of an exception table entry. CONSTANT_CELL +in "catch" pseudo_instruction means +catch +type. Each exception table entry contains 4 values:start-pc, end-pc, +catch-pc, catch-type. In jasm, each entry is denoted with some (local) +identifier, as an example: TRAP_IDENT.

+

To set start-pc, place "try TRAP_IDENT" +before the instruction with the desirable program counter. +Similarly, use "endtry TRAP_IDENT" for +end-pc and "catch TRAP_IDENT, catch-type" for catch-pc and catch-type +(which is usually a constant pool reference). +Try, endtry, and catch pseudoinstructions may be placed in any order. +The order of entries in exception table is significant (see JVM +specification). However, the only way to control this order is to +place catch-clauses in appropriate +textual order: assembler adds an entry in the exception table each +time it encounters a catch-clause.

+

Example:

+
     try {
try {
throw new Exception("EXC");
} catch (NullPointerException e){
throw e;
} catch (Exception e){
throw e;
}
} catch (Throwable e){
throw e;
}
+

will be coded in assembler as follows:

+
+

try R1, R2; // single "try" or "endtry" can start several regions
new class java/lang/Exception;
dup;
ldc String "EXC";
invokespecial java/lang/Exception.<init>:"(Ljava/lang/String;)V";
athrow;
endtry R1;
catch R1 java/lang/NullPointerException; // only one "catch" per entry allowed
astore_1;
aload_1;
athrow;
catch R1 java/lang/Exception; // same region (R1) can appear in different catches
astore_1;
aload_1;
athrow;
endtry R2;
catch R2 java/lang/Throwable;
astore_1;
aload_1;
athrow;
+
+
+

StackMap Table Attribute Generation

+

Stack Maps are denoted by the pseudo-op opcode stack_map, +and they can be identified by three basic items:

+
+
StackMapStatement = stack_map (stackMap_Item_MapType +|stackMap_Item_Object +| +stackMap_Item_NewObject) + +
+
+ stackMap_Item_MapType = +(bogus | int | float | double | long | null | this | CP) + + + + +
+
+ stackMap_Item_Object = CONSTANT_CELL_CLASS +
+ stackMap_Item_NewObject = at +LABEL +

All stack_map directives are collected +by the assembler, and are used to create a StackMap Table attribute.

+ Example 1 (MapType): +
+
public Method "<init>":"()V"
    stack 1 locals 1
{
       aload_0;
       invokespecial    Method java/lang/Object."<init>":"()V";
        return;
        stack_frame_type full;
        stack_map bogus;
        ...
}
+
+ Example 2 (Object):
+
+ public Method +"<init>":"()V"
+    stack 2 locals 1
+{
+        ...
+     +   + stack_map +class +java/lang/Object;
+        nop;
+        return;
+}
+

+ Example 3 (NewObject):
+
+ public Method +"<init>":"()V"
+    stack 2 locals 1
+{
+        ...
+    +     stack_map at L5;
+        nop;
+        return;
+}
+
+

+

StackFrameType Table Attribute Generation

+

StackFrameTypes are similar assembler directives as StackMap. +These directives can appear anywhere in +the code, and the assembler will collect them to produce a +StackFrameType attribute.

+
+
StackFrameStatement = stack_frame_type +frame_type
+
+ frame_type = ( +same +| +stack1 +| +stack1_ex +| +chop1 +| +chop2 +| +chop3 | same_ex | append | full )
+
+ Example 1 (full stack frame type):
+
public Method "<init>":"()V"
    stack 1 locals 1
{
       aload_0;
       invokespecial    Method java/lang/Object."<init>":"()V";
        return;
        stack_frame_type full;
        stack_map bogus;
        ...
}
+ Example 2 (append, chop2, and same stack frame types):
+
public Method foo:"(Z)V"
stack 2 locals 5
{
        ...
iload_2;
iconst_2;
if_icmpge L30;
L27: stack_frame_type append;
locals_map int, int;
iconst_2;
istore 4;
L30: stack_frame_type chop2;
goto L9;
L33: stack_frame_type same;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Chop2 attribute test";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
        ...
}
+

LocalsMap Table

+

Locals Maps are typically associated with a stack_frame_type, +and +are +accumulated +per +stack +frame. They typically follow a stack_frame_type +directive.

+
+
LocalsMapStatement = locals_map +locals_type (, locals_type +)*
+
+ locals_type = +stackMap_Item_MapType +| +CONSTANT_CELL_CLASS
+
+ Example (a locals map specifying 2 ints): +
public Method foo:"(Z)V"
stack 2 locals 5
{
        ...
iload_2;
iconst_2;
if_icmpge L30;
L27: stack_frame_type append;
locals_map int, int;
iconst_2;
istore 4;
L30: stack_frame_type chop2;
goto L9;
L33: stack_frame_type same;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Chop2 attribute test";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
        ...
}
+
+
+
+

Inner Class Declarations

+
+
INNER_CLASS_DECLARATIONS: list of
+
INNER_CLASS_DECLARATION
+
INNER_CLASS_DECLARATION:
+
INNER_CLASS_ACCESS InnerClass +[INNER_CLASS_NAME=]? +INNER_CLASS_INFO +[of OUTER_CLASS_INFO]? ;
+
INNER_CLASS_NAME:
+
IDENT | CPX_name
+
INNER_CLASS_INFO:
+
CONSTANT_CELL(class) 
+
OUTER_CLASS_INFO:
+
CONSTANT_CELL(class)
+
INNER_CLASS_ACCESS: list of
+
[public|protected|private][static][final][interface][abstract][synthetic][annotation][enum]
+
+Example: +
    InnerClass InCl=class test$InCl of class test;
+

 

+
+

Annotation Declarations

+ +

Member Annotations

+

+Member annotations are a subset of the basic annotations support +provided in JDK 5.0 (1.5). These are annotations that +ornament Packages, Classes, and Members either visibly (accessible at +runtime) or invisibly (not accessible at +runtime). In JASM, visible annotations are denoted by the token @, +while +invisible +annotations +are +denoted +by the token @-. +

+

Synopsis

+
+
ANNOTATIONS:
+
+
[ANNOTATION_DECLARATION]+;
+
ANNOTATION_DECLARATION:
+
@+|@- ANNOTATION_NAME +[ANNOTATION_VALUE_DECLARATIONS]
+
+

+The '@+' token identifies a +Runtime Visible Annotation, where the '@-' +token identifies a Runtime Invisible Annotation. +

+
+
ANNOTATION_NAME:
+
IDENT
+
ANNOTATION_VALUE_DECLARATIONS: list +of (comma separated)
+
+
ANNOTATION_VALUE_DECLARATION
+
ANNOTATION_VALUE_DECLARATION:
+
[ANNOTATION_VALUE_IDENT=] [ANNOTATION_VALUE]
+
ANNOTATION_VALUE_IDENT:
+
IDENT
+
ANNOTATION_VALUE:
+
ANNOTATION_VALUE_PRIMITIVE | Array of +ANNOTATION_VALUE_PRIMITIVE
+
ANNOTATION_VALUE_PRIMITIVE:
+
PRIMITIVE_TYPE | STRING | CLASS | ENUM | +ANNOTATION_DECLARATION
+
+
+
CLASS:
+
class CONSTANT_CELL(class)
+
+
+
ENUM:
+
enum CONSTANT_CELL(class) CONSTANT_CELL(string) (where +string is Enum type name)
+
+
+
PRIMITIVE_TYPE:
+
BOOLEAN | BYTE | CHAR | SHORT | INTEGER | LONG | FLOAT | +DOUBLE
+
+Note +
+    Types (Boolean, Byte, Char, and Short) are +normalized into Integer's within the constant pool.
+    Annotation values with these types may be identified +with a keyword in front of an integer value.
+
+     eg.       boolean +true (or: boolean 1)
+                 +byte 20
+                 +char 97
+                 +short 2130
+
+    Other primitive types are parsed according to normal +prefix and suffix +conventions
+    +(eg. Double = xxx.xd, Float = xxx.xf, Long = xxxL).  +
+    Strings are identified and delimited by '"' +(quotation marks).
+
+   +Keywords 'class' and 'enum' identify those annotation +types explicitly. Values within classes and enums may
+   either be identifiers (strings) or Constant Pool IDs.
+
+   Annotations specified as the value of an Annotation field +are identified by the JASM annotation keywords '@+' and '@-'.
+
+   +Arrays are delimited by '{' and '}' marks, with individual elements +delimited by ',' (comma).
+

Examples

+
Example 1 (Class Annotation, Visible)
+
@+ClassPreamble { 
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe",
reviewers = {
"Alice",
"Bob",
"Cindy"}
}
+
super public class MyClass
version 50:0
{
 ...
+
+
+
Example 2 (Field Annotation, +Invisible)
+
+
@-FieldPreamble {
 author = "Mustafa",
date = "3/17/2009",
currentRevision = 4
}
Field foo:I;
+...
+
+
+Example 3 (Field Annotation, +All subtypes)
+
+

@+FieldPreamble {
boolAnnot = boolean 1, // Boolean
charBear = char 97, // Char
sharkByte = byte 17, // Byte
shortCircuit = short 4386, // Short
integerHead = 42, // Int
longJohnSilver = 55l, // Long
floatBoat = 1.0f, // Float
doubleDip = 10.0d, // Double
stringBeans = "foo", // String
severity = enum FieldPreamble$Severity IMPORTANT, // Enum
classAnnot = class FieldPreamble$FooBall, // Class
tm = @+Trademark { description = "embedded", owner = "ktl"} // Annotation
}
Field foo:I;
+...
+
+
Example 4 (Module Annotation, Visible)
+
@+java/lang/Deprecated { 
since = "9",
forRemoval = boolean true
}
+
moduleContent my.moduleContent
version 53:0
{
 ...
+
+
+

+Note:
+ JASM does not enforce the annotation value declarations like a +compiler would.  It only checks to see that an annotation +structure is well-formed.
+

+

Type Annotations

+

+Member annotations are a subset of the basic annotations support +provided in JDK 7.0 (1.7). These are annotations that +ornament Packages, Classes, and Members either visibly (accessible at +runtime) or invisibly (not accessible at +runtime). In JASM, visible annotations are denoted by the token @T+, +while +invisible +annotations +are +denoted +by the token @T-.

+

Synopsis

+
TYPE_ANNOTATION_DECLARATION: +
+
@T+|@T- ANNOTATION_NAME +[TYPE_ANNOTATION_VALUE_DECLARATIONS]
+

+
+
TYPE_ANNOTATION_VALUE_DECLARATIONS: +list +of +(comma +separated)
+
+
TYPE_ANNOTATION_VALUE_DECLARATION
+

+
+
TYPE_ANNOTATION_VALUE_DECLARATION: +
+
{ { +ANNOTATION_VALUE_DECLARATION+ + } TARGET PATH }
+

+
+

+
+
TARGET:
+
{ TARGET_TYPE TARGET_INFO }
+
+

+
+

+
+
TARGET_TYPE:
+

+
+
          + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TARGET_TYPE:TARGET_INFO_TYPE:
CLASS_TYPE_PARAMETER  + TYPEPARAM +
METHOD_TYPE_PARAMETER + + + + + + +   + TYPEPARAM +
CLASS_EXTENDS  + SUPERTYPE +
CLASS_TYPE_PARAMETER_BOUND  + TYPEPARAM_BOUND +
METHOD_TYPE_PARAMETER_BOUND + TYPEPARAM_BOUND +
FIELD  + EMPTY +
METHOD_RETURN  + EMPTY|
+
METHOD_RECEIVER + EMPTY +
METHOD_FORMAL_PARAMETERMETHODPARAM
THROWSEXCEPTION
LOCAL_VARIABLELOCALVAR
RESOURCE_VARIABLELOCALVAR
EXCEPTION_PARAMCATCH
INSTANCEOFOFFSET
NEWOFFSET
CONSTRUCTOR_REFERE +CE_RECEIVER
+
OFFSET
METHOD_REFERENCE_RECEIVEROFFSET  + +
CAST
+
TYPEARG
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+
TYPEARG
METHOD_INVOCATION_TYPE_ARGUMENTTYPEARG
CONSTRUCTOR_REFERENCE_TYPE_ARGUMENTTYPEARG
METHOD_REFERENCE_TYPE_ARGUMENTTYPEARG
+


+
+
TARGET_INFO_TYPE:
+
TYPEPARAM | SUPERTYPE | +TYPEPARAM_BOUND +| EMPTY | METHODPARAM | EXCEPTION | LOCALVAR | CATCH | OFFSET +|  TYPEARG
+

+

+
+
TYPEPARAM:
+
+
paramIndex(INTEGER) +
+
+

+
+

+
+
+
SUPERTYPE:
+
+
typeIndex(INTEGER)typeIndex(INTEGER) +
+
+

+
+

+
+
+
TYPEPARAM_BOUND:
+
+
paramIndex(INTEGER) + + + + + + boundIndex(INTEGER) +
+
+

+
+

+
+
EMPTY: +
+
 
+
+
+

+
+

+ METHODPARAM:
+
+
index(
+
paramIndex(INTEGER) +

+
EXCEPTION:
+
+
typeIndex(INTEGER)  +
+
+

+
+

+
LOCALVAR:
+
{ LVENTRY }+numEntries +
+
+

+
+
LVENTRY:
+
+
startpc(INTEGER) + + + + + + length(INTEGER) + + + + + + index(INTEGER)
+
+

+
+
CATCH:
+
+

+
+
catch(INTEGER)
+ +
+

+
+

+
+

+
+
OFFSET: + + + + + +
+
+
offset(INTEGER) +
+

+
+
+
TYPEARG:
+
+
offset(INTEGER) + typeIndex(INTEGER)
+
+

+
+

+
+

+
+PATH: list +of (space separated)
+
{ + PATH_ENTRY+ + }
+

+
+

+
+
PATH_ENTRY: +
+
+
{ PATH_KIND PATH_INDEX }
+
+
+

+

+
+
PATH_KIND:
+
ARRAY | INNER_TYPE | WILDCARD +| TYPE_ARGUMENT
+

+

+
+
PATH_INDEX:
+
+
INTEGER +
+
+

+

+
+

+

+
+

+
+

+
+

+ + +

Parameter Names and Parameter Annotations

+

Parameter annotations are another subset of the basic annotations +support provided in JDK 5.0 (1.5). These are annotations that +ornament Parameters to methods either visibly (accessible at runtime) +or invisibly (not accessible at +runtime). In JASM, visible parameter annotations are denoted by the +token @+, while invisible parameter annotations are denoted +by the token @-.
+

+

Parameter names come from an attribute introduced in JDK 8.0 +(1.8).  These are fixed parameter names that are used to ornament +parameters on methods.  In Jasm, parameter names are identified by +the token # followed by { } braclets
+

+

Synopsis

+
+
METHOD DECLARATION:
+
+
MODIFIERS Method METHOD_NAME:"METHOD_SIGNATURE" +[STACK_DECL] [LOCALS_DECL] [PARAMETERS_DECL] {[CODE]}
+

+
+
PARAMETERS_DECL:
+
+
[PARAMETER_DECL]N (where N < number of params +in method, each N is a unique param number)
+

+
+
PARAMETER_DECL:
+
+
PARAM_NUM : [PARAM_NAME_DECL] [ANNOTATION_DECLARATIONS]
+
+
+
PARAM_NAME_DECL:
+
+
#{ name PARAM_ACCESS}
+

+
+
PARAM_ACCESS: list of
+
[final][synthetic][mandated]
+
+

Examples

+
Example 1 (Parameter Annotation)
+Java Code
+
public class MyClass2 {

...

public int doSomething(
@VisParamPreamble ( author = "gummy" ) @InVisParamPreamble ( author = "bears" ) int barber,
boolean of,
@VisParamPreamble ( author = "sour" ) @InVisParamPreamble ( author = "worms" ) int seville,
@InVisParamPreamble1 ( reviewers = {"Dilbert", "Garfield"} ) boolean pastrami) {
...
}
...
}
+
+JASM Code
+
+Note:  The first +two parameters are named ('P0'- 'P3').  Since this is a compiler +controlled option, there is no way to specify parameter naming in Java +source.
+
super public class MyClass2
version 50:0
{
...

public Method doSomething:"(IZIZ)I"
stack 2 locals 5

0: #{P0 mandated} @+VisParamPreamble { author = "gummy" } @-InVisParamPreamble { author = "bears" }
1: #{P1 final synthetic mandated}
  2: #{P2 mandated} @+VisParamPreamble { author = "sour" } @-InVisParamPreamble { author = "worms" }
3: #{P3 mandated} @-InVisParamPreamble1 { reviewers = { "Dilbert", "Garfield"} }
{
...
}

} // end Class MyClass2
+
+
+ +

Default Annotations

+

  Default annotations are another subset of the basic +annotations +support provided in JDK 5.0 (1.5). These are annotations that +ornament Annotations either visibly (accessible at runtime) +or invisibly (not accessible at +runtime). Default annotations specify a default value for a given +annotation field.
+

+

Synopsis

+
+
ANNOTATION INTERFACE DECLARATION:
+
+
@interface ANNOTATION_NAME { ANNOTATION_FIELD_DECL+ +}
+
+

+
+
ANNOTATION_FIELD_DECL:
+
+
ANNOT_FIELD_TYPE ANNOTATION_NAME +[ANNOTATION_DEFAULT_VALUE_DECL];
+
+

+
+
ANNOTATION_DEFAULT_VALUE_DECL:
+
+
default ANNOTATION_VALUE (where value must be of the type +ANNOT_FIELD_TYPE)
+
+
+

Examples

+
Example 1 (Default Annotation)
+Java Code
+
import java.lang.annotation.*; 
@Retention(RetentionPolicy.RUNTIME)
+
@interface Meth2Preamble {
   String author() default "John Steinbeck";
}
+
+JASM Code
+
interface  Meth2Preamble
    implements java/lang/annotation/Annotation
    version 50:0
+
{
 public abstract Method author:"()Ljava/lang/String;" default { "John Steinbeck" } ;
} // end Class Meth2Preamble
+
+
+ +

Module properties

+ +

Requires

+
+
MODULE_REQUIRES: sequence of
+
requires REQUIRES_FLAGS CONSTANT_CELL(moduleContent);
+
REQUIRES_FLAGS: set of
+
[transitive] [static]
+
+Example: +
        requires transitive static foo.bar;
+ +

Exports

+
+
MODULE_EXPORTS: sequence of
+
exports CONSTANT_CELL(package) [to EXPORT_TO_MODULES];
+
EXPORT_TO_MODULES: list of
+
CONSTANT_CELL(moduleContent)
+
+Example: +
        exports com/foo/bar to 
foo2.bar2,
foo3.bar3; +
+
        exports org/foo/bar;
+ +

Opens

+
+
MODULE_OPENS: sequence of
+
opens CONSTANT_CELL(package) [to OPENS_TO_MODULES];
+
OPENS_TO_MODULES: list of
+
CONSTANT_CELL(moduleContent)
+
+Example: +
        opens com/foo/bar to 
foo2.bar2,
foo3.bar3; +
+
        opens org/foo/bar;
+ +

Uses

+
+
MODULE_USES: sequence of
+
uses CONSTANT_CELL(class);
+
+Example: +
        uses com/foo/bar;
+
+ +

Provides

+
+
MODULE_PROVIDES: sequence of
+
provides CONSTANT_CELL(class) [with MODULE_PROVIDES_WITH_CLASSES];
+
MODULE_PROVIDES_WITH_CLASSES: list of
+
CONSTANT_CELL(class)
+
+Example: +
        provides com/foo/bar with 
foo2.bar2,
foo3.bar3;
+
        provides com/foo/bar;
+
+

PicoJava Instructions

+These instructions takes 2 bytes: prefix (254 for non-privileged +variant and 255 for privileged) and the opcode itself. +These instructions can be coded in assembler in 2 ways: +as single mnemocode identical to the description or +using "priv" and "nonpriv" instructions followed with an integer +representing the opcode. +


+

+ +
+
+
+ + + + + + + + +
+

Java Assembler Tools (AsmTools) User's Guide

+
+

000-0000-00

+
+

Table Of Contents Previous ChapterNext ChapterBook Index

+
+
+ +
+
+Copyright © 2012, 2017, Oracle and/or its affiliates. All rights reserved. +
+ + diff -Nru jtreg8-8.1+1+ds1/asmtools/docs/jasm.md jtreg8-8.3+1+ds1/asmtools/docs/jasm.md --- jtreg8-8.1+1+ds1/asmtools/docs/jasm.md 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/docs/jasm.md 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,1950 @@ + +# JASM Syntax + +This chapter describes _JASM syntax_, and how to encode class files using this syntax. _Jasm_ is a java +assembler that accepts text in the JASM format and produces a `.class` file for use with a Java Virtual Machine. +_Jasm_'s primary use is as a tool for producing specialized tests for testing a JVM implementation. + +This chapter describes JASM syntax in the following sections: + +- [General Class Structure](#general-class-structure) +- [General Module Structure](#general-module-structure) +- [General Source File Structure](#general-source-file-structure) +- [The Constant Pool and Constant Elements](#the-constant-pool-and-constant-elements) +- [Constant Declarations](#constant-declarations) +- [Field Variables](#field-variables) +- [Method Declarations](#method-declarations) +- [Instructions](#instructions) + - [Pseudo Instructions](#pseudo-instructions) +- [Inner Class Declarations](#inner-class-declarations) +- [Annotation Declarations](#annotation-declarations) + - [Member Annotations](#member-annotations) + - [Synopsis](#synopsis) + - [Examples](#examples) + - [Type Annotations](#type-annotations) + - [Synopsis](#synopsis-1) + - [Parameter Names and Parameter Annotations](#parameter-names-and-parameter-annotations) + - [Synopsis](#synopsis-2) + - [Examples](#examples-1) + - [Default Annotations](#default-annotations) + - [Synopsis](#synopsis-3) + - [Examples](#examples-2) +- [Module properties](#module-properties) + - [Requires](#requires) + - [Exports](#exports) + - [Opens](#opens) + - [Uses](#uses) + - [Provides](#provides) +- [PicoJava Instructions](#picojava-instructions) + +--- + +## JASM Syntax Overview + +JASM syntax comes in two forms: short-form and verbose-form: + +1. **Short-form:** Uses Java-style names to refer to items in the constant-pool. +2. **Verbose-form:** Uses constant-pool indexes to explicitly refer to items. +By default, the **JDIS** tool outputs short-form JASM files. To generate verbose-form output, use the `-g` option, like this: + +``` shell +java -jar asmtools.jar jdis -g +``` + +## File Naming in JASM + +A JASM file can start with a line specifying the name of the output file. This does not affect the file’s content but determines the file name. The first line can be one of these: + +- `file FILENAME;` +- `classfile CLASSNAME;` (adds `.class` to the name). + +You can define the destination directory using these options: + +- `-d`: Specifies the root directory for the output, following the class package structure. +- `-w`: Specifies the exact directory for the output file. + +If neither option is used, JASM outputs to ``. + +## Class Structure in JASM + +A JASM file defines class or interface items as follows: + +1. **Optional Package Declaration:** + +```java +package package_name; +``` + +2. **Class or Interface Declaration**: + +```java +[CLASS_MODIFIERS] class|interface CLASSNAME [extends SUPERCLASSNAME] { [CLASS_BODY] } +``` + +- The `CLASSNAME` determines the resulting file name. +- If `this_class` is defined in CLASS_BODY, the name does not affect the file's content but only its name. + +If both `file FILENAME;` ( or `classfile CLASSNAME;`) and `class CLASSNAME { [CLASS_BODY] }` are present, the file(classfile) declaration takes priority. + +### Example Command and Output + +Here is an example of compiling a JASM file: + +**Input Command:** + +```shell +java -jar asmtools.jar jasm -d . FILE.jasm +``` + +**JASM File Content:** + +```java +class FILENAME.data { +this_class CLASSNAME; +super_class SUPERCLASSNAME; +} +``` + +**Output:** + +A binary file FILENAME.data is created. Decompiling this file (`java -jar asmtools.jar jdis FILENAME.data`) produces: + +```java +super class CLASSNAME extends SUPERCLASSNAME version 45:0 { +} +``` + +--- + +## Description formats + +| | | +| ------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| TERM1\|TERM2 | TERM1 or TERM2 (not both) | +| [ TERM ] | TERM is optional | +| TERM... | TERM repeated 1 or more times | +| [TERM...] | TERM repeated 0 or more times | +| "sequence of" | all the following terms are mandatory, in the order given. | +| "set of" | any of following terms, or none of them, may appear in any order. However, repetitions are not llowed. | +| "list of" | any of following terms, or none of them, may appear in any sequence. If more than one term appear, they are separated by commas (',') | + +--- +## Lexical Structure + + +# TODO + +> ------------------------------------------------------------------------ +> +> +> The source text file can be free form (newlines, tabs, and blank +> spaces are equivalent). Additionally, the source may contain standard +> Java and C++ comments. +> +> `STRING`, `NUMBER`, and `IDENT` are treated the same as in the Java +> Language Specification. One difference is that LETTERs include also +> \`/', \`<', \`>', \`(', and \`)' . +> +> _**`STRING`**_: +> `" [ STRING_CHARACTER... ] "` +> +> _**`NUMBER`**_: +> `DIGIT...` +> +> _**`IDENT`**_: +> `LETTER [ LETTER_OR_DIGIT ...]` +> +> _**`ACCESS`**_ (depends on the context): set of +> `abstract final interface native private protected public static super synchronized transient volatile deprecated synthetic bridge varargs` +> +> Not all access bits make sense for all declarations: for example, the +> "super" and "interface" access flags are applied to classes only. +> +> If an access bit is used improperly, the assembler prints a warning, +> but places the bit in the access set. +> +> Note that `deprecated` and `synthetic` keywords are not translated to +> access flags in the Java sense. For these jasm generates a +> corresponding `Deprecated` or `Synthetic` attributes instead of access +> bits. The `synthetic` access flag is used to mark compiler generated +> members not seen in the source (for example, a field reference to an +> anonymous outer class). +> +> _**`TAG`**_: one of +> `int float long double Asciz String class Field Method NameAndType InterfaceMethod MethodType MethodHandle InvokeDynamic Dynamic` +> +> Local names represent labels, rangePC-labels and local variables. +> Their scope is constrained by method parenthesis. +> +> _**`LOCAL_NAME`**_: +> `IDENT` +> +> +> +> _**`CONSTANT_INDEX`**_: +> `#NUMBER` +> +> Each CONSTANT\_INDEX represents a reference into the constant pool at +> the specified location. + +------------------------------------------------------------------------ + + + +# General Class Structure + +_**`INTERFACES`**_:list of +`CONSTANT_CELL(class|@interface|interface)` + +_**`TOP_LEVEL_COMPONENT`**_: one of +`CONSTANT_DECLARATION FIELD_DECLARATION METHOD_DECLARATION INNER_CLASS_DECLARATIONS` + +_**`CLASS`**_: sequence of +`ANNOTATIONS CLASS_ACCESS CONSTANT_CELL(class|@interface|interface) [extends CONSTANT_CELL(class)] [implements INTERFACES] [version INTEGER:INTEGER] { [TOP_LEVEL_COMPONENT...] }` + +`CLASS_ACCESS``: list of` +`[public]``[final]``[super]``[interface]``[abstract]``[synthetic]``[annotation]``[enum]` + +The `extends CONSTANT_CELL(class)` clause places the "super" element of +the class file. The `implements INTERFACES` clause places the table of +interfaces. Since the assembler does not distinguish interfaces and +ordinary classes (the only difference is one access bit), the table of +interfaces of an interface class must be declared with `implements` +keyword, and not `extends`, as in Java language. + +**Note:**The last two rules allow `TOP_LEVEL_COMPONENT` to appear in any +order and number. For example, you can split constant pool table into +several parts, mixing constants and method declarations. + +------------------------------------------------------------------------ + + + +# General Module Structure + +_**`MODULE`**_: sequence of +`ANNOTATIONS [MODULE_FLAGS] moduleContent CONSTANT_CELL(moduleContent) [version INTEGER:INTEGER] {[TOP_LEVEL_MODULE_PROPERTIES...]}` + +_**`TOP_LEVEL_MODULE_PROPERTIES`**_: one of +`MODULE_REQUIRES` `MODULE_EXPORTS` `MODULE_OPENS` `MODULE_USES` +`MODULE_PROVIDES` + +`MODULE_FLAGS``:set of` +`[open]` + +------------------------------------------------------------------------ + + + +# General Source File Structure + +_**`PACKAGE_DECLARATION`**_: +`package IDENT;` + +Package declaration can appear only once in source file. + +_**`CLASS_FILE`**_: sequence of +`PACKAGE_DECLARATION CLASS...` + + + +_**`MODULE_FILE`**_: +`MODULE...` + + + +_**`SOURCE_FILE`**_: +`MODULE_FILE|CLASS_FILE` + +------------------------------------------------------------------------ + + + +# The Constant Pool and Constant Elements + +A `CONSTANT_CELL` refers to an element in the constant pool. It may +refer to the element either by its index or its value: + +_**`CONSTANT_CELL`**_: +`CONSTANT_INDEX` +`TAGGED_CONSTANT_VALUE` + +Generic rule for TAGGED\_CONSTANT\_VALUE is: + +_**`TAGGED_CONSTANT_VALUE`**_: +`[TAG] CONSTANT_VALUE` + +A TAG may be omitted when the context only allows one kind of a tag. For +example, the argument of an `anewarray` instruction should be a +`CONSTANT_CELL` which represents a class, so instead of + + anewarray class java/lang/Object + +one may write: + + anewarray java/lang/Object + +It is possible to write another tag, e.g.: + + anewarray String java/lang/Object + +However, the resulting program will be incorrect. + +Another example of an implicit tag (eg. a context which implies tag) is +the header of a class declaration. You may write: + + aClass { + } + +which is equivalent to: + + class aClass { + } + +Below, the tag implied by context will be included in the rules, e.g.: + + CONSTANT_VALUE(int). + +The exact notation of `CONSTANT_VALUE` depends on the (explicit or +implicit) `TAG.` + +_**`TAGGED_CONSTANT_VALUE`**_: + +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +>
int INTEGER
long [INTEGER|LONG]
float [FLOAT|INTEGER]
float bits INTEGER
double [FLOAT|DOUBLE|INTEGER|LONG]
double [bits INTEGER | bits LONG]
Asciz EXTERNAL_NAME
class CONSTANT_NAME
String CONSTANT_NAME
NameAndType NAME_AND_TYPE
Field CONSTANT_FIELD
Method CONSTANT_FIELD
ReferenceIndex [Method|InterfaceMethod]
MethodHandle [INVOKESUBTAG|INVOKESUBTAG_INDEX] : CONSTANT_FIELD | [FIELDREF|METHODREF|INTERFACEMETHODREF]
MethodType CONSTANT_NAME
id="invokedynamicconstant"> InvokeDynamic INVOKESUBTAG : CONSTANT_FIELD : NAME_AND_TYPE [INVOKEDYNAMIC_STATIC_ARGS]
moduleContent CONSTANT_NAME
package CONSTANT_NAME
+ +> _Note_ +> When the JASM parser encounters an InvokeDynamic constant, it creates +> an entry in the _BootstrapMethods_ attribute (the _BootstrapMethods_ +> attribute is produced if it has not already been created). The entry +> contains a reference to the _MethodHandle_ item in the constant pool, +> and, optionally, a sequence of references to additional static +> arguments (_ldc_-type constants) to the _bootstrap method_ + +INVOKESUBTAGs for MethodHandle and (const) InvokeDynamic are defined as +follows and can be presented as either an index or a tag: + +_**`INVOKESUBTAG: [INVOKESUBTAG_INDEX]`**_ + +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +>
REF_GETFIELD [1]
REF_GETSTATIC [2]
REF_PUTFIELD [3]
REF_PUTSTATIC [4]
REF_INVOKEVIRTUAL [5]
REF_INVOKESTATIC [6]
REF_INVOKESPECIAL [7]
REF_NEWINVOKESPECIAL [8]
REF_INVOKEINTERFACE [9]
+ +Static arguments for an InvokeDynamic constant are defined as follows: + +_**`INVOKEDYNAMIC_STATIC_ARGUMENTS`**_: +`INVOKEDYNAMIC_STATIC_ARG ',' ...` + +_**`INVOKEDYNAMIC_STATIC_ARG`**_: (one of) +`INVOKEDYNAMIC_STATIC_ARG_CONSTANT_VALUE` + +_**`INVOKEDYNAMIC_STATIC_ARG_CONSTANT_VALUE`**_: + +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +>
int INTEGER
long [INTEGER|LONG]
float [FLOAT|INTEGER]
double [FLOAT|DOUBLE|INTEGER|LONG]
class CONSTANT_NAME
String CONSTANT_NAME
MethodHandle INVOKESUBTAG:CONSTANT_FIELD
MethodType CONSTANT_NAME
+ +`INTEGER`, `LONG`, `FLOAT`, and `DOUBLE` correspond to `IntegerLiteral` +and `FloatingPointLiteral` as described in [The Java Language +Specification](https://docs.oracle.com/javase/specs/jls/se8/html/index.html). +If a double-word constant (`LONG` or `DOUBLE`) is represented with a +single-word value (`INTEGER` or `FLOAT`, respectively), single-word +value is simply promoted to double-word, as described in [The Java +Language +Specification](https://docs.oracle.com/javase/specs/jls/se8/html/index.html). +If floating-point constant (`FLOAT` or `DOUBLE`) is represented with an +integral value (`INTEGER` or `LONG`, respectively), the result depends +on whether the integral number is preceded with the keyword "bits". If +"bits" is not used, the result is a floating-point number closest in +value to the decimal number. If the keyword "bits" is used, the +floating-point constant takes bits of the integral value without +conversion. + +Thus, + + float 2; + means the same as + float 2.0f; + and the same as + float bits 0x40000000; + while + float bits 2; + actually means the same as + float bits 0x00000002; + and the same as + float 2.8026e-45f + +_**`CONSTANT_NAME`**_: +`CONSTANT_INDEX` +`EXTERNAL_NAME` + +_**`EXTERNAL_NAME`**_: +`IDENT STRING` + +External names are names of class, method, field, or type, which stay in +resulting .class file, and may be represented both by `IDENT` or by +`STRING` (which is useful when name contains non-letter characters). + +_**`NAME_AND_TYPE`**_: +`CONSTANT_INDEX` +`CONSTANT_NAME:CONSTANT_NAME` + +In this second example, the first `CONSTANT_NAME` denotes the name of a +field and second denotes its type. + +_**`CONSTANT_FIELD`**_: +`CONSTANT_INDEX` +`[CONSTANT_NAME.]NAME_AND_TYPE` + +In this third example, `CONSTANT_NAME` denotes to the class of a field. +If `CONSTANT_NAME` is omitted, the current class is assumed. + +------------------------------------------------------------------------ + + + +# Constant Declarations + +Constant declarations are demonstrated in the examples below: + + const #1=int 1234 + , #2=String "a string" + , #3=Method get:I + ; + +_**`CONSTANT_DECLARATION`**_: +`const CONSTANT_DECLARATORS ;` + +_**`CONSTANT_DECLARATORS`**_: list of +`CONSTANT_DECLARATOR` + +_**`CONSTANT_DECLARATOR`**_: +`CONSTANT_INDEX = TAGGED_CONSTANT_VALUE` + +------------------------------------------------------------------------ + + + +# Field Variables + +_**`FIELD_DECLARATION`**_: +`ANNOTATIONS ``FIELD_ACCESS Field FIELD_DECLARATORS ;` + +_**`FIELD_DECLARATORS`**_: list of +`FIELD_DECLARATOR` + +_**`FIELD_DECLARATOR`**_: +`EXTERNAL_NAME:CONSTANT_NAME [:SIGNATURE] [ = TAGGED_CONSTANT_VALUE ]` + +`FIELD_ACCESS``: list of` +`[public|private|protected]``[final]``[static]``[volatile]``[transient]``[synthetic]``[enum]` + +Example: + + public static Field + field1:I = int 1234, + field2:"Ljava/lang/String;", + field3:"Ljava/util/List;":"Ljava/util/List<+Ljava/lang/String;>" + ; + +Access bits (public and static) are applied both to field1 and field2. +The `EXTERNAL_NAME` denotes the name of the field, `CONSTANT_NAME` +denotes its type, `TAGGED_CONSTANT_VALUE` denotes initial value. + +------------------------------------------------------------------------ + + + +# Method Declarations + +_**`METHOD_DECLARATION`**_: sequence of +`ANNOTATIONS ``METHOD_ACCESS Method` +`EXTERNAL_NAME:CONSTANT_NAME` +`[THROWS]` +`STACK_SIZE` +`[LOCAL_VAR_SIZE]` +`{ INSTRUCTION_STATEMENT...` +`ANNOTATIONS }` + +The `EXTERNAL_NAME` denotes the name of the method, `CONSTANT_NAME` +denotes its type. + +`METHOD_ACCESS``: list of` +`[public|private|protected]``[static][final]``[synthetic]``[bridge]``[varargs]``[native][abstract]``[strict]``[synthetic]` + + + +_**`THROWS`**_: +`throws EXCEPTIONS` + +_**`EXCEPTIONS`**_: list of +`CONSTANT_CELL(class)` + +The meaning of the `THROWS` clause is the same as in Java Language +Specification - it forms Exceptions attribute of a method. Jasm itself +does not use this attribute in any way. + +_**`STACK_SIZE`**_: +`stack NUMBER` + +The `NUMBER` denotes maximum operand stack size of the method. + +_**`LOCAL_VAR_SIZE`**_: +`locals NUMBER` + +The `NUMBER` denotes number of local variables of the method. If +omitted, it is calculated by assembler according to the signature of the +method and local variable declarations. + +------------------------------------------------------------------------ + + + +# Instructions + +> +> +> ## VM Instructions +> +> _**`INSTRUCTION_STATEMENT`**_: +> `[NUMBER] [LABEL:] INSTRUCTION|PSEUDO_INSTRUCTION ;` +> +> Jasm allows for a `NUMBER` (which is ignored) at the beginning of each +> line. This is allowed in order to remain consistent with the jdis +> disassembler. Jdis puts line numbers in disassembled code that may be +> reassembled using Jasm without any additional modifications. +> +> _**`INSTRUCTION`**_: +> `OPCODE [ARGUMENTS]` +> +> _**`ARGUMENTS`**_: list of +> `ARGUMENT` +> +> _**`ARGUMENT`**_: +> `NUMBER LABEL LOCAL_VARIABLE TRAP_IDENT CONSTANT_CELL SWITCHTABLE TYPE` +> +> _**`LABEL`**_: +> `NUMBER IDENT` +> +> _**`LOCAL_VARIABLE`**_: +> `NUMBER IDENT` +> +> _**`TRAP_IDENT`**_: +> `IDENT` +> +> _**`TYPE`**_: +> `NUMBER boolean byte char int float long double class` +> +> _**`SWITCHTABLE`**_: +> `{ [NUMBER:LABEL...] [default:LABEL] }` +> +> SWITCHTABLE example: Java\_text +> +> switch (x) { +> case 11: +> x=1; +> break; +> case 12: +> x=2; +> break; +> default: +> x=3; +> } +> +> +> +> will be coded in assembler as follows: +> +> tableswitch { +> 11: L24; +> 12: L29; +> default: L34 +> } +> L24: iconst_1; +> istore_1; +> goto L36; +> L29: iconst_2 ; +> istore_1; +> goto L36; +> L34: iconst_3; +> istore_1; +> L36: .... +> +> +> +> OPCODE is any mnemocode from the instruction set. If mnemocode needs +> an ARGUMENT, it cannot be omitted. Moreover, the kind (and number) of +> the argument(s) must match the kind (and number) required by the +> mnemocode: +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +> +>
aload, astore, fload, fstore, iload, istore, lload, lstore, dload, +> dstore, ver, endvar:LOCAL_VARIABLE
iinc:LOCAL_VARIABLE, NUMBER
sipush, bipush, bytecode:NUMBER
tableswitch, lookupswitch:SWITCHTABLE
newarray:TYPE
jsr, goto, ifeq, ifge, ifgt, ifle, iflt, ifne, if_icmpeq, if_icmpne, +> if_icmpge, if_icmpgt, if_icmple, if_icmplt, if_acmpeq, if_acmpne, +> ifnull, ifnonnull, try, endtry:LABEL
jsr_w, goto_w:LABEL
ldc_w, ldc2_w, ldc:CONSTANT_CELL
new, anewarray, instanceof, checkcast,CONSTANT_CELL(class)
multianewarray style="vertical-align: top">NUMBER, CONSTANT_CELL(class)
putstatic, getstatic, putfield, getfield:CONSTANT_CELL(Field)
invokevirtual, invokenonvirtual, invokestatic:CONSTANT_CELL(Method)
invokeinterface:NUMBER, CONSTANT_CELL(Method)
invokedynamic:CONSTANT_CELL(InvokeDynamic)
aaload, aastore, aconst_null, +> aload_0, aload_1, aload_2, aload_3, aload_w , areturn, +> arraylength, astore_0, astore_1, astore_2, astore_3, astore_w, +> athrow, baload, bastore, caload, castore, d2f, d2i, d2l, dadd, +> daload, dastore, dcmpg, dcmpl, dconst_0, dconst_1, ddiv, dead, +> dload_0, dload_1, dload_2, dload_3, dload_w , dmul, dneg, drem, +> dreturn, dstore_0, dstore_1, dstore_2, dstore_3, dstore_w, dsub, +> dup, dup2, dup2_x1, dup2_x2, dup_x1, dup_x2, f2d, f2i, f2l, +> fadd, faload, fastore, fcmpg, fcmpl, fconst_0, fconst_1, +> fconst_2, fdiv, fload_0, fload_1, fload_2, fload_3, fload_w, +> fmul, fneg, frem, freturn , fstore_0, fstore_1, fstore_2, +> fstore_3, fstore_w, fsub , i2b, i2c, i2d, i2f, i2l, i2s, iadd, +> iaload, iand, iastore, iconst_0, iconst_1, iconst_2, iconst_3, +> iconst_4, iconst_5, iconst_m1, idiv, iinc_w, iload_0, iload_1, +> iload_2, iload_3, iload_w, imul, ineg, int2byte, int2char, +> int2short, ior, irem, ireturn, ishl, ishr, istore_0, istore_1, +> istore_2, istore_3, istore_w, isub, iushr, ixor, l2d, l2f, l2i, +> label, ladd, laload, land, lastore, lcmp, lconst_0, lconst_1, +> ldiv, lload_0, lload_1, lload_2, lload_3, lload_w, lmul, lneg, +> lor, lrem, lreturn, lshl, lshr, lstore_0, lstore_1, lstore_2, +> lstore_3, lstore_w, lsub, lushr, lxor, monitorenter, monitorexit, +> nonpriv, nop, pop, pop2, priv, ret, return, ret_w, saload, +> sastore, swap, wide
+>
<No Arguments>
+> +> +> +> ## InvokeDynamic Instructions +> +> _InvokeDynamic instructions_ are instructions that allow dynamic +> binding of methods to a call site. These instructions in JASM form are +> rather complex, and the JASM assembler does some of the necessary work +> to create a _BootstrapMethods_ attribute for entries of binding +> methods. +> +> > class Test +> > version 51:0 +> > { +> > Method m:"()V" +> > stack 0 locals 1 +> > { +> > invokedynamic InvokeDynamic REF_invokeSpecial:bsmName:"()V" // information about bootstrap method +> > :methName:"(I)I" // dynamic call-site name ("methName") plus the argument and return types of the call ("(I)I") +> > int 1, long 2l; // optional sequence of additional static arguments to the bootstrap method (ldc-type constants) +> > } +> > } // end Class Test +> +> This JASM code has an _invokedynamic_ instruction of the form: +> _**invokedynamic InvokeDynamic (CONSTANT\_CELL(INVOKEDYNAMIC))**_ +> where the INVOKEDYNAMIC constant is represented as +> [specified](#invokedynamicconstant) +> +> (i.e. _invokedynamic InvokeDynamic INVOKESUBTAG : CONSTANT\_FIELD +> (bootstrapmethod signature) : NAME\_AND\_TYPE (CallSite) \[Arguments +> (Optional)\]_ ). +> +> The JASM assembler creates the appropriate constant entries and +> entries into the BootstrapMethods attribute in a resulting class file. +> +> You can also create InvokeDynamic constants and BootstrapMethods +> explicitly: +> +> > #22; //class Test3 +> > version 51:0 +> > { +> > +> > const #1 = InvokeDynamic 0:#11; // REF_invokeSpecial:Test3.bsmName:"()V":name:"(I)I" int 1, long 2l +> > const #2 = Asciz "Test3"; +> > const #3 = long 2l; +> > const #5 = class #6; // java/lang/Object +> > const #6 = Asciz "java/lang/Object"; +> > const #7 = Asciz "name"; +> > const #8 = int 1; +> > const #9 = Asciz "SourceFile"; +> > const #10 = Asciz "Test3.jasm"; +> > const #11 = NameAndType #7:#21; // name:"(I)I" +> > const #12 = Asciz "()V"; +> > const #13 = Method #22.#17; // Test3.bsmName:"()V" +> > const #14 = Asciz "Code"; +> > const #15 = Asciz "m"; +> > const #16 = Asciz "BootstrapMethods"; +> > const #17 = NameAndType #20:#12; // bsmName:"()V" +> > const #18 = Asciz "LineNumberTable"; +> > const #19 = MethodHandle 7:#13; // REF_invokeSpecial:Test3.bsmName:"()V" +> > const #20 = Asciz "bsmName"; +> > const #21 = Asciz "(I)I"; +> > const #22 = class #2; // Test3 +> > const #23 = class #6; // java/lang/Object +> > +> > +> > +> > Method #15:#12 +> > stack 0 locals 1 +> > { +> > 0: invokedynamic InvokeDynamic #1; // InvokeDynamic REF_invokeSpecial:Test3.bsmName:"()V":name:"(I)I" int 1, long 2l; +> > } +> > +> > BootstrapMethod #19 #8 #3; +> > +> > } // end Class Test3 +> +> In this example, `const #1 = InvokeDynamic 0:#11;` is the +> InvokeDynamic constant that refers to BootstrapMethod at index '0' in +> the BootstrapMethods Attribute (`BootstrapMethod #19 #8 #3;` which +> refers to the _MethodHandle_ at const \#19, plus 2 other static args +> (at const \#8 and const \#3). + + + +## Pseudo Instructions + +> Pseudo instructions are 'assembler directives', and not really +> instructions (in the VM sense) They typically come in two forms: +> Code-generating Pseudo-Instructions, and Attribute-Generating +> Pseudo-Instructions. +> +> +> +> ### Code-Generating Pseudo-Instructions +> +> The _bytecode_ directive instructs the assembler to put a collection +> of raw bytes into the code attribute of a methodK +> +> +> _**`bytecode NUMBERS`**_ +> NUMBERS is list of NUMBERs (divided by COMMA). +> Insert bytes in place of the instruction. May have any number of +> numeric arguments, each of them to be converted into a byte and +> inserted in method's code. +> +> +> +> ### Attribute-Generating Pseudo-Instructions +> +> The rest of pseudo\_instructions do not produce any bytecodes, and are +> used to form tables: local variable table, exception table, +> Stack Maps, and Stack Map Frames. Line Number Tables can not be +> specified, but they are constructed by the assembler itself. +> +> > #### Local Variable Table Attribute Generation +> > +> > _**`var LOCAL_VARIABLE`**_ +> > Starts local variable range +> > +> > _**`endvar LOCAL_VARIABLE`**_ +> > Ends local variable range. LOCAL\_VARIABLE means name or index of +> > local variable table entry. +> > +> > Example: +> > +> > static void main (String[] args) { +> > Tester inst = new Tester(); +> > inst.callSub(); +> > } +> > +> > will be coded in assembler as follows: +> > +> > > > > static Method #8:#9 // main:"([Ljava/lang/String;)V" +> > > > > stack 2 locals 2 +> > > > > { +> > > > > 4 var 0; // args:"[Ljava/lang/String;" +> > > > > 0: new #1; // class Tester; +> > > > > 3: dup; +> > > > > 4: invokespecial #2; // Method "":"()V"; +> > > > > 7: astore_1; +> > > > > 6 var 1; // inst:"LTester;" +> > > > > 8: aload_1; +> > > > > 9: invokevirtual #3; // Method callSub:"()V"; +> > > > > 7 12: return; +> > > > > endvar 0, 1; +> > > > > +> > > > > } +> > +> > #### Exception Table Attribute Generation +> > +> > To generate exception table, three pseudo-instructions are used. +> > +> > > _**`try TRAP_IDENT`**_ +> > > Starts rangePC range +> > > +> > > _**`endtry TRAP_IDENT`**_ +> > > Ends rangePC range +> > > +> > > _**`catch TRAP_IDENT CONSTANT_CELL(class)`**_ +> > > Starts exception handler. +> > +> > `TRAP_IDENT` represents the name or number of an exception table +> > entry. `CONSTANT_CELL` in "catch" pseudo\_instruction means catch +> > type. Each exception table entry contains 4 values:start-pc, end-pc, +> > catch-pc, catch-type. In jasm, each entry is denoted with some +> > (local) identifier, as an example: `TRAP_IDENT`. +> > +> > To set start-pc, place "try TRAP\_IDENT" before the instruction with +> > the desirable program counter. Similarly, use "endtry TRAP\_IDENT" +> > for end-pc and "catch TRAP\_IDENT, catch-type" for catch-pc and +> > catch-type (which is usually a constant pool reference). Try, +> > endtry, and catch pseudoinstructions may be placed in any order. The +> > order of entries in exception table is significant (see JVM +> > specification). However, the only way to control this order is to +> > place catch-clauses in appropriate textual order: assembler adds an +> > entry in the exception table each time it encounters a catch-clause. +> > +> > Example: +> > +> > try { +> > try { +> > throw new Exception("EXC"); +> > } catch (NullPointerException e){ +> > throw e; +> > } catch (Exception e){ +> > throw e; +> > } +> > } catch (Throwable e){ +> > throw e; +> > } +> > +> > will be coded in assembler as follows: +> > +> > > try R1, R2; // single "try" or "endtry" can start several regions +> > > new class java/lang/Exception; +> > > dup; +> > > ldc String "EXC"; +> > > invokespecial java/lang/Exception.:"(Ljava/lang/String;)V"; +> > > athrow; +> > > endtry R1; +> > > catch R1 java/lang/NullPointerException; // only one "catch" per entry allowed +> > > astore_1; +> > > aload_1; +> > > athrow; +> > > catch R1 java/lang/Exception; // same region (R1) can appear in different catches +> > > astore_1; +> > > aload_1; +> > > athrow; +> > > endtry R2; +> > > catch R2 java/lang/Throwable; +> > > astore_1; +> > > aload_1; +> > > athrow; +> > > +> > > +> > +> > #### StackMap Table Attribute Generation +> > +> > Stack Maps are denoted by the pseudo-op opcode _stack\_map, and they +> > can be identified by three basic items:_ +> > +> > _**`StackMapStatement =`**_``stack\_map +> > _**`(stackMap_Item_MapType |stackMap_Item_Object | stackMap_Item_NewObject)`**_`` +> > +> > _**`stackMap_Item_MapType = (`_**bogus | int | float | double | long +> > | null | this | CP**_`)`**_`` +> > +> > _**`stackMap_Item_Object = CONSTANT_CELL_CLASS`**_ +> > _**`stackMap_Item_NewObject =`**_``at``_**`LABEL`**_`` +> > +> > All stack\_map directives are collected by the assembler, and are +> > used to create a StackMap Table attribute. +> > +> > Example 1 +> > (MapType): +> > +> > public Method "":"()V" +> > stack 1 locals 1 +> > { +> > aload_0; +> > invokespecial Method java/lang/Object."":"()V"; +> > return; +> > stack_frame_type full; +> > stack_map bogus; +> > ... +> > } +> > +> > +> > Example 2 (Object): +> > +> > public Method +> > "<init>":"()V" +> > stack 2 locals 1 +> > { +> > ... +> > ***stack\_map class java/lang/Object;*** +> > nop; +> > return; +> > } +> > +> > Example 3 (NewObject): +> > +> > public Method +> > "<init>":"()V" +> > stack 2 locals 1 +> > { +> > ... +> > ***stack\_map at L5;*** +> > nop; +> > return; +> > } +> > +> > +> > +> > #### StackFrameType Table Attribute Generation +> > +> > StackFrameTypes are similar assembler directives as StackMap. These +> > directives can appear anywhere in the code, and the assembler will +> > collect them to produce a StackFrameType attribute. +> > +> > _**`StackFrameStatement =`**_``stack\_frame\_type``_**`frame_type`**_ +> > +> > _**`frame_type = (`**_ same | stack1 | stack1\_ex | chop1 | chop2 | +> > chop3 | same\_ex | append | full _**`)`**_ +> > +> > Example 1 (full _stack frame type_): +> > +> > public Method "":"()V" +> > stack 1 locals 1 +> > { +> > aload_0; +> > invokespecial Method java/lang/Object."":"()V"; +> > return; +> > stack_frame_type full; +> > stack_map bogus; +> > ... +> > } +> > +> > Example 2 (append, chop2, and same _stack frame types_): +> > +> > public Method foo:"(Z)V" +> > stack 2 locals 5 +> > { +> > ... +> > iload_2; +> > iconst_2; +> > if_icmpge L30; +> > L27: stack_frame_type append; +> > locals_map int, int; +> > iconst_2; +> > istore 4; +> > L30: stack_frame_type chop2; +> > goto L9; +> > L33: stack_frame_type same; +> > getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; +> > ldc String "Chop2 attribute test"; +> > invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; +> > return; +> > ... +> > } +> > +> > #### LocalsMap Table +> > +> > Locals Maps are typically associated with a _stack\_frame\_type_, +> > and are accumulated per stack frame. They typically follow a +> > _stack\_frame\_type_ directive. +> > +> > _**`LocalsMapStatement =`**_``locals\_map``_**`locals_type (, locals_type )*`**_ +> > +> > _**`locals_type = stackMap_Item_MapType | CONSTANT_CELL_CLASS`**_`` +> > +> > Example (a _locals map_ specifying 2 ints): +> > +> > public Method foo:"(Z)V" +> > stack 2 locals 5 +> > { +> > ... +> > iload_2; +> > iconst_2; +> > if_icmpge L30; +> > L27: stack_frame_type append; +> > locals_map int, int; +> > iconst_2; +> > istore 4; +> > L30: stack_frame_type chop2; +> > goto L9; +> > L33: stack_frame_type same; +> > getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; +> > ldc String "Chop2 attribute test"; +> > invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; +> > return; +> > ... +> > } + +------------------------------------------------------------------------ + + + +# Inner Class Declarations + +_**`INNER_CLASS_DECLARATIONS`**_: list of +`INNER_CLASS_DECLARATION` + +_**`INNER_CLASS_DECLARATION`**_: +`INNER_CLASS_ACCESS`**`InnerClass`**`[INNER_CLASS_NAME`**`=`**`]? INNER_CLASS_INFO [`**`of`**`OUTER_CLASS_INFO]? ;` + +_**`INNER_CLASS_NAME`**_: +`IDENT | CPX_name` + +_**`INNER_CLASS_INFO`**_: +`CONSTANT_CELL(class)` + +_**`OUTER_CLASS_INFO`**_: +`CONSTANT_CELL(class)` + +_**`INNER_CLASS_ACCESS`**_`: list of` +`[public|protected|private][static][final][interface][abstract][synthetic][annotation][enum]` + +Example: + + InnerClass InCl=class test$InCl of class test; + +------------------------------------------------------------------------ + + + +# Annotation Declarations + + + +## Member Annotations + +Member annotations are a subset of the basic annotations support +provided in JDK 5.0 (1.5). These are annotations that ornament Packages, +Classes, and Members either visibly (accessible at runtime) or invisibly +(not accessible at runtime). In JASM, visible annotations are denoted by +the token **@**, while invisible annotations are denoted by the token +**@-**. + +#### Synopsis + +_**`ANNOTATIONS`**_: +`[ANNOTATION_DECLARATION]+`; + +_**`ANNOTATION_DECLARATION`**_: +**`@+`**`|`**`@-`**`ANNOTATION_NAME [ANNOTATION_VALUE_DECLARATIONS]` + +The '**@+**' token identifies a Runtime Visible Annotation, where the +'**@-' token identifies a Runtime Invisible Annotation.** + +_**`ANNOTATION_NAME`**_: +`IDENT` + +_**`ANNOTATION_VALUE_DECLARATIONS`**_: list of (comma separated) +`ANNOTATION_VALUE_DECLARATION` + +_**`ANNOTATION_VALUE_DECLARATION`**_: +`[ANNOTATION_VALUE_IDENT=] [ANNOTATION_VALUE]` + +_**`ANNOTATION_VALUE_IDENT`**_: +`IDENT` + +_**`ANNOTATION_VALUE`**_: +`ANNOTATION_VALUE_PRIMITIVE | Array of ANNOTATION_VALUE_PRIMITIVE` + +_**`ANNOTATION_VALUE_PRIMITIVE`**_: +`PRIMITIVE_TYPE | STRING | CLASS | ENUM | ANNOTATION_DECLARATION` + + + +_**`CLASS`**_: +**`class`**`CONSTANT_CELL(class)` + + + +_**`ENUM`**_: +**`enum CONSTANT_CELL(class) CONSTANT_CELL(string) (where string is Enum type name)`** + + + +_**`PRIMITIVE_TYPE`**_: +`BOOLEAN | BYTE | CHAR | SHORT | INTEGER | LONG | FLOAT | DOUBLE` + +_**Note**_ + Types (Boolean, Byte, Char, and Short) are normalized into Integer's +within the constant pool. + Annotation values with these types may be identified with a keyword +in front of an integer value. + + eg. **boolean** true (or: boolean 1) + **byte** 20 + **char** 97 + **short** 2130 + + Other primitive types are parsed according to normal prefix and +suffix conventions + (eg. Double = xxx.x**d**, Float = xxx.x**f**, Long = xxx**L**). + Strings are identified and delimited by '"' (quotation marks). + + Keywords '**class**' and '**enum**' identify those annotation types +explicitly. Values within classes and enums may + either be identifiers (strings) or Constant Pool IDs. + + Annotations specified as the value of an Annotation field are +identified by the JASM annotation keywords '**@+**' and '**@-**'. + + Arrays are delimited by '{' and '}' marks, with individual elements +delimited by ',' (comma). + +#### Examples + +Example 1 (Class Annotation, Visible) + + @+ClassPreamble { + author = "John Doe", + date = "3/17/2002", + currentRevision = 6, + lastModified = "4/12/2004", + lastModifiedBy = "Jane Doe", + reviewers = { + "Alice", + "Bob", + "Cindy"} + } + + super public class MyClass + version 50:0 + { + ... + +Example 2 (Field Annotation, +Invisible) + + @-FieldPreamble { + author = "Mustafa", + date = "3/17/2009", + currentRevision = 4 + } + Field foo:I; + +... + +Example 3 (Field Annotation, +All subtypes) + + @+FieldPreamble { + boolAnnot = boolean 1, // Boolean + charBear = char 97, // Char + sharkByte = byte 17, // Byte + shortCircuit = short 4386, // Short + integerHead = 42, // Int + longJohnSilver = 55l, // Long + floatBoat = 1.0f, // Float + doubleDip = 10.0d, // Double + stringBeans = "foo", // String + severity = enum FieldPreamble$Severity IMPORTANT, // Enum + classAnnot = class FieldPreamble$FooBall, // Class + tm = @+Trademark { description = "embedded", owner = "ktl"} // Annotation + } + Field foo:I; + +... + +Example 4 (Module Annotation, Visible) + + @+java/lang/Deprecated { + since = "9", + forRemoval = boolean true + } + + moduleContent my.moduleContent + version 53:0 + { + ... + +Note: + JASM does not enforce the annotation value declarations like a compiler +would. It only checks to see that an annotation structure is +well-formed. + +## Type Annotations + +Member annotations are a subset of the basic annotations support +provided in JDK 7.0 (1.7). These are annotations that ornament Packages, +Classes, and Members either visibly (accessible at runtime) or invisibly +(not accessible at runtime). In JASM, visible annotations are denoted by +the token **@T+**, while invisible annotations are denoted by the token +**@T-**. + +#### Synopsis + +_**`TYPE_ANNOTATION_DECLARATION`**_: + +**`@T+`**`|`**`@T-`**`ANNOTATION_NAME [TYPE_ANNOTATION_VALUE_DECLARATIONS]` + +_**`TYPE_ANNOTATION_VALUE_DECLARATIONS`**_: list of (comma separated) + +`TYPE_ANNOTATION_VALUE_DECLARATION` + +_**`TYPE_ANNOTATION_VALUE_DECLARATION`**_: + +**`{`**``**`{`**`ANNOTATION_VALUE_DECLARATION`**`+`**``**`}`**` TARGET PATH`` `**`}`** + +_**`TARGET`**_: + +**`{`**` TARGET_TYPE TARGET_INFO `**`}`** + +**** + +_**`TARGET_TYPE`**_`:` + +`` + + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TARGET_TYPE:TARGET_INFO_TYPE:
CLASS_TYPE_PARAMETER TYPEPARAM
METHOD_TYPE_PARAMETER + TYPEPARAM
CLASS_EXTENDS SUPERTYPE
CLASS_TYPE_PARAMETER_BOUND TYPEPARAM_BOUND
METHOD_TYPE_PARAMETER_BOUNDTYPEPARAM_BOUND
FIELD EMPTY
METHOD_RETURN EMPTY|
+
METHOD_RECEIVEREMPTY
METHOD_FORMAL_PARAMETERMETHODPARAM
THROWSEXCEPTION
LOCAL_VARIABLELOCALVAR
RESOURCE_VARIABLELOCALVAR
EXCEPTION_PARAMCATCH
INSTANCEOFOFFSET
NEWOFFSET
CONSTRUCTOR_REFERE CE_RECEIVER
+
OFFSET
METHOD_REFERENCE_RECEIVEROFFSET
CAST
+
TYPEARG
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+
TYPEARG
METHOD_INVOCATION_TYPE_ARGUMENTTYPEARG
CONSTRUCTOR_REFERENCE_TYPE_ARGUMENTTYPEARG
METHOD_REFERENCE_TYPE_ARGUMENTTYPEARG
+ +_**`TARGET_INFO`**_`_TYPE``:` + +`` + +`TYPEPARAM | SUPERTYPE | TYPEPARAM_BOUND | EMPTY | METHODPARAM | EXCEPTION | LOCALVAR | CATCH |`` OFFSET | TYPEARG` + +**** + +**`TYPEPARAM`**`:` + +`paramIndex(`_`INTEGER`_`)`` ` + +**`SUPERTYPE`**`:` + +`typeIndex(`_`INTEGER`_`)``typeIndex(``INTEGER``)`` ` + +**`TYPEPARAM_BOUND`**`:` + +`paramIndex(`_`INTEGER`_`) ``boundIndex(`_`INTEGER`_`)`` ` + +**`EMPTY`**`:` + +`` + +**`METHODPARAM`**`:` + +`index(` + +`paramIndex(`_`INTEGER`_`)` + +**`EXCEPTION`**`:` + +`typeIndex(`_`INTEGER`_`)`_``_`` + +**** + +_**`LOCALVAR`**_`:` + +`{```**`LVENTRY }``+numEntries`**`` + +`` + +_**`LVENTRY`**_`:` + +`startpc(`_`INTEGER)`_`length``(`_`INTEGER)`_`index(`_`INTEGER)`_`` + +**`CATCH`**`:` + +`catch(`_`INTEGER)`_ + +`` + +_**`OFFSET`**_`:` + +`` + +`offset(`_`INTEGER)`_ + +`` + +**`TYPEARG`**`:` + +`offset(`_`INTEGER`_`) ``typeIndex(`_`INTEGER`_`)`` ` + +_**`PATH`**_`: list of (space separated)` +`` + +**`{`**_```PATH_ENTRY`_**`+`**``**`}`** + +_**`PATH_ENTRY`**_`:` + +`` + +`{``PATH_KIND PATH_INDEX }` + +_**`PATH_KIND`**_`:` + +`` + +`ARRAY | INNER_TYPE | WILDCARD | TYPE_ARGUMENT` + +**`PATH_INDEX`**`:` + +_`INTEGER`_`` + +**** + +**** + +## Parameter Names and Parameter Annotations + +Parameter annotations are another subset of the basic annotations +support provided in JDK 5.0 (1.5). These are annotations that ornament +Parameters to methods either visibly (accessible at runtime) or +invisibly (not accessible at runtime). In JASM, visible parameter +annotations are denoted by the token **@+**, while invisible parameter +annotations are denoted by the token **@-**. + +Parameter names come from an attribute introduced in JDK 8.0 (1.8). +These are fixed parameter names that are used to ornament parameters on +methods. In Jasm, parameter names are identified by the token \# +followed by { } braclets + +#### Synopsis + +_**`METHOD DECLARATION`**_: +`MODIFIERS Method METHOD_NAME:"METHOD_SIGNATURE" [STACK_DECL] [LOCALS_DECL] [PARAMETERS_DECL] {[CODE]}` + +_**`PARAMETERS_DECL`**_: +`[PARAMETER_DECL]``N``(where N < number of params in method, each N is a unique param number)` + +_**`PARAMETER_DECL`**_: +`PARAM_NUM : [PARAM_NAME_DECL] [ANNOTATION_DECLARATIONS]` + + + +_**`PARAM_NAME_DECL`**_: +`#{ name PARAM_ACCESS}` + +_**`PARAM_ACCESS`**_`: list of` +`[final][synthetic][mandated]` + +#### Examples + +Example 1 (Parameter Annotation) +_**Java Code**_ + + public class MyClass2 { + + ... + + public int doSomething( + @VisParamPreamble ( author = "gummy" ) @InVisParamPreamble ( author = "bears" ) int barber, + boolean of, + @VisParamPreamble ( author = "sour" ) @InVisParamPreamble ( author = "worms" ) int seville, + @InVisParamPreamble1 ( reviewers = {"Dilbert", "Garfield"} ) boolean pastrami) { + ... + } + ... + } + +_**JASM Code**_ + +Note: The first two +parameters are named ('P0'- 'P3'). Since this is a compiler controlled +option, there is no way to specify parameter naming in Java source. + + super public class MyClass2 + version 50:0 + { + ... + + public Method doSomething:"(IZIZ)I" + stack 2 locals 5 + + 0: #{P0 mandated} @+VisParamPreamble { author = "gummy" } @-InVisParamPreamble { author = "bears" } + 1: #{P1 final synthetic mandated} + 2: #{P2 mandated} @+VisParamPreamble { author = "sour" } @-InVisParamPreamble { author = "worms" } + 3: #{P3 mandated} @-InVisParamPreamble1 { reviewers = { "Dilbert", "Garfield"} } + { + ... + } + + } // end Class MyClass2 + + + +## Default Annotations + + Default annotations are another subset of the basic annotations +support provided in JDK 5.0 (1.5). These are annotations that ornament +Annotations either visibly (accessible at runtime) or invisibly (not +accessible at runtime). Default annotations specify a default value for +a given annotation field. + +#### Synopsis + +_**`ANNOTATION INTERFACE DECLARATION`**_: +`@interface ANNOTATION_NAME { ANNOTATION_FIELD_DECL``+``}` + +_**`ANNOTATION_FIELD_DECL`**_: +`ANNOT_FIELD_TYPE ANNOTATION_NAME [ANNOTATION_DEFAULT_VALUE_DECL];` + +_**`ANNOTATION_DEFAULT_VALUE_DECL`**_: +`default ANNOTATION_VALUE (where value must be of the type ANNOT_FIELD_TYPE)` + +#### Examples + +Example 1 (Default Annotation) +_**Java Code**_ + + import java.lang.annotation.*; + @Retention(RetentionPolicy.RUNTIME) + + @interface Meth2Preamble { + String author() default "John Steinbeck"; + } + +_**JASM Code**_ + + interface Meth2Preamble + implements java/lang/annotation/Annotation + version 50:0 + + { + public abstract Method author:"()Ljava/lang/String;" default { "John Steinbeck" } ; + } // end Class Meth2Preamble + +------------------------------------------------------------------------ + + + +# Module properties + + + +## Requires + +_**`MODULE_REQUIRES`**_: sequence of +requires `REQUIRES_FLAGS` `CONSTANT_CELL(moduleContent)`; + +_**`REQUIRES_FLAGS`**_: set of +\[`transitive`\] \[`static`\] + +Example: + + requires transitive static foo.bar; + + + +## Exports + +_**`MODULE_EXPORTS`**_: sequence of +exports `CONSTANT_CELL(package)` \[to `EXPORT_TO_MODULES`\]; + +_**`EXPORT_TO_MODULES`**_: list of +`CONSTANT_CELL(moduleContent)` + +Example: + + exports com/foo/bar to + foo2.bar2, + foo3.bar3; + + exports org/foo/bar; + + + +## Opens + +_**`MODULE_OPENS`**_: sequence of +opens `CONSTANT_CELL(package)` \[to `OPENS_TO_MODULES`\]; + +_**`OPENS_TO_MODULES`**_: list of +`CONSTANT_CELL(moduleContent)` + +Example: + + opens com/foo/bar to + foo2.bar2, + foo3.bar3; + + opens org/foo/bar; + + + +## Uses + +_**`MODULE_USES`**_: sequence of +uses `CONSTANT_CELL(class)`; + +Example: + + uses com/foo/bar; + + + +## Provides + +_**`MODULE_PROVIDES`**_: sequence of +provides `CONSTANT_CELL(class)` \[with `MODULE_PROVIDES_WITH_CLASSES`\]; + +_**`MODULE_PROVIDES_WITH_CLASSES`**_: list of +`CONSTANT_CELL(class)` + +Example: + + provides com/foo/bar with + foo2.bar2, + foo3.bar3; + + provides com/foo/bar; + +------------------------------------------------------------------------ + + + +# PicoJava Instructions + +These instructions takes 2 bytes: prefix (254 for non-privileged variant +and 255 for privileged) and the opcode itself. These instructions can be +coded in assembler in 2 ways: as single mnemocode identical to the +description or using "priv" and "nonpriv" instructions followed with an +integer representing the opcode. + + + + + + + + + +

Java Assembler Tools (AsmTools) User's Guide

000-0000-00

Table Of Contents Next Chapter

+ +------------------------------------------------------------------------ + +Copyright © 2012, 2017, Oracle and/or its affiliates. All rights +reserved. diff -Nru jtreg8-8.1+1+ds1/asmtools/maven/mvngen.sh jtreg8-8.3+1+ds1/asmtools/maven/mvngen.sh --- jtreg8-8.1+1+ds1/asmtools/maven/mvngen.sh 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/maven/mvngen.sh 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,75 @@ +#!/bin/bash + +##################################################################################################### +# Symlinks are forbidden in openjdk project, thus we generate them on the fly together with pom.xml # +##################################################################################################### + +set -eo pipefail + +## resolve folder of this script, following all symlinks, +## http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in +SCRIPT_SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SCRIPT_SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + SCRIPT_DIR="$( cd -P "$( dirname "$SCRIPT_SOURCE" )" && pwd )" + SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")" + # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located + [[ $SCRIPT_SOURCE != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE" +done +readonly SCRIPT_DIR="$( cd -P "$( dirname "$SCRIPT_SOURCE" )" && pwd )" +readonly PROJECT_DIR="$( readlink -f "$SCRIPT_DIR/.." )" + +PRODUCT_INFO="$PROJECT_DIR/build/productinfo.properties" +BUILD_INFO="$PROJECT_DIR/build/build.properties" + +function readProperty() { + if [ "x${2}" = "x" ] ; then + local file="$PRODUCT_INFO" + else + local file="${2}" + fi + cat "$file" | grep "$1\s*=" | sed "s/.*=\s*//" +} + +PRODUCT_NAME=$(readProperty "PRODUCT_NAME") +PRODUCT_VERSION=$(readProperty "PRODUCT_VERSION") +PRODUCT_MILESTONE=$(readProperty "PRODUCT_MILESTONE") +PRODUCT_BUILDNUMBER=$(readProperty "PRODUCT_BUILDNUMBER") +PRODUCT_NAME_LONG=$(readProperty "PRODUCT_NAME_LONG") +RELEASE=$(readProperty "javac.release.version" "$BUILD_INFO") + +echo "Generating $SCRIPT_DIR/pom.xml for $PRODUCT_NAME $PRODUCT_VERSION $PRODUCT_MILESTONE $PRODUCT_BUILDNUMBER ($PRODUCT_NAME_LONG)" +cat "$SCRIPT_DIR/pom.xml.in" | \ +sed "s/\[RELEASE\]/$RELEASE/g" | \ +sed "s/\[PRODUCT_NAME\]/$PRODUCT_NAME/g" | \ +sed "s/\[PRODUCT_VERSION\]/$PRODUCT_VERSION/g" | \ +sed "s/\[PRODUCT_MILESTONE\]/$PRODUCT_MILESTONE/g" | \ +sed "s/\[PRODUCT_BUILDNUMBER\]/$PRODUCT_BUILDNUMBER/g" | \ +sed "s/\[PRODUCT_NAME_LONG\]/$PRODUCT_NAME_LONG/g" > "$SCRIPT_DIR/pom.xml" +echo "Done" + +echo "Creating symlinks to symulate maven structure" +FILES_LINKS="src/main/java/org=../../../../src/org/ +src/test=../../test +src/main/resources/org/openjdk/asmtools/i18n.properties=../../../../../../../src/org/openjdk/asmtools/i18n.properties +src/main/resources/org/openjdk/asmtools/jasm/i18n.properties=../../../../../../../../src/org/openjdk/asmtools/jasm/i18n.properties +src/main/resources/org/openjdk/asmtools/jcoder/i18n.properties=../../../../../../../../src/org/openjdk/asmtools/jcoder/i18n.properties +src/main/resources/org/openjdk/asmtools/jdec/i18n.properties=../../../../../../../../src/org/openjdk/asmtools/jdec/i18n.properties +src/main/resources/org/openjdk/asmtools/jdis/i18n.properties=../../../../../../../../src/org/openjdk/asmtools/jdis/i18n.properties +src/main/resources/org/openjdk/asmtools/util/productinfo.properties=../../../../../../../../build/productinfo.properties" + +pushd $SCRIPT_DIR > /dev/null + for FILE_LINK in $FILES_LINKS ; do + FILE=$(echo "$FILE_LINK" | sed "s/=.*//") + LINK=$(echo "$FILE_LINK" | sed "s/.*=//") + DIR=$(dirname "$FILE") + NAME=$(basename "$FILE") + if [ ! -e "$SCRIPT_DIR/$FILE" ] ; then + mkdir -vp "$SCRIPT_DIR/$DIR" + pushd "$SCRIPT_DIR/$DIR" > /dev/null + echo "$SCRIPT_DIR/$DIR" + ln -sv "$LINK" "$NAME" + popd > /dev/null + fi + done +popd > /dev/null +echo "Done" diff -Nru jtreg8-8.1+1+ds1/asmtools/maven/pom.xml.in jtreg8-8.3+1+ds1/asmtools/maven/pom.xml.in --- jtreg8-8.1+1+ds1/asmtools/maven/pom.xml.in 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/maven/pom.xml.in 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,113 @@ + + + 4.0.0 + + org.openjdk + + [PRODUCT_NAME] + [PRODUCT_VERSION].b[PRODUCT_BUILDNUMBER]-[PRODUCT_MILESTONE] + + jar + + [PRODUCT_NAME] + Maven wrapper around [PRODUCT_NAME] - [PRODUCT_NAME_LONG] project + + + https://github.com/openjdk/asmtools + scm:git:https://git@github.com/openjdk/asmtools.git + scm:git:https://git@github.com/openjdk/asmtools.git + HEAD + + + UTF-8 + + + + + + src/main/resources + + true + + **/* + + + + src/test/resources + + true + + **/* + + + + + + maven-resources-plugin + 3.3.1 + + + class + bin + + UTF-8 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + [RELEASE] + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M9 + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + true + org.openjdk.asmtools.Main + + + + + + + + + + + org.junit.jupiter + junit-jupiter + 5.9.2 + test + + + org.junit.platform + junit-platform-launcher + 1.9.2 + test + + + org.opentest4j + opentest4j + 1.2.0 + + + org.hamcrest + hamcrest-library + 2.2 + test + + + diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/Main.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/Main.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/Main.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/Main.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools; + +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.util.I18NResourceBundle; +import org.openjdk.asmtools.util.ProductInfo; + +/** + * Wrapper class that reads the first command line argument and invokes a corresponding + * tool. + */ +public class Main { + + public static final I18NResourceBundle sharedI18n = I18NResourceBundle.getBundleForClass(org.openjdk.asmtools.Main.class); + public static final String VERSION_SWITCH="-version"; + public static final String STDIN_SWITCH="-"; + public static final String DIR_SWITCH="-d"; + public static final String WRITE_SWITCH="-w"; + public static final String DUAL_LOG_SWITCH ="-dls"; + + /** + * Parses the first argument and delegates execution to an appropriate tool + * + * @param args - command line arguments + */ + public static void main(String... args) { + if (args.length == 0) { + usage(sharedI18n.getString("main.error.no_arguments"), 1); + } + String cmd = args[0]; + if (cmd.equals("-?") || cmd.equals("-h") || cmd.equals("-help")) { + usage(null, Environment.OK); + } else if (cmd.equals(VERSION_SWITCH)) { + printVersion(); + System.exit(Environment.OK); + } else { + String[] newArgs = new String[args.length - 1]; + System.arraycopy(args, 1, newArgs, 0, args.length - 1); + if (cmd.equals("jasm")) { + jasm(newArgs); + } else if (cmd.equals("jdis")) { + jdis(newArgs); + } else if (cmd.equals("jcoder")) { + jcoder(newArgs); + } else if (cmd.equals("jdec")) { + jdec(newArgs); + } else { + usage(sharedI18n.getString("main.error.unknown_tool", cmd), 1); + } + } + } + + /** + * Prints usage info and error message, afterwards invokes System.exit() + * + * @param msg - error message to print, or null if no errors occurred + * @param exitCode - exit code to be returned by System.exit() + */ + public static void usage(String msg, int exitCode) { + System.err.println(sharedI18n.getString("main.usage", "asmtools.jar")); + if (msg != null) { + System.err.println(msg); + } + System.exit(exitCode); + } + + /** + * Prints the tools version + */ + public static void printVersion() { + System.out.println(ProductInfo.FULL_VERSION); + } + + /** + * Invokes jasm main class with passed arguments + */ + public static void jasm(String... args) { + org.openjdk.asmtools.jasm.Main.main(args); + } + + /** + * Invokes jcoder main class with passed arguments + */ + public static void jcoder(String... args) { + org.openjdk.asmtools.jcoder.Main.main(args); + } + + /** + * Invokes jdec main class with passed arguments + */ + public static void jdec(String... args) { + org.openjdk.asmtools.jdec.Main.main(args); + } + + /** + * Invokes jdis main class with passed arguments + */ + public static void jdis(String... args) { + org.openjdk.asmtools.jdis.Main.main(args); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/FormatConsumer.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/FormatConsumer.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/FormatConsumer.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/FormatConsumer.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,6 @@ +package org.openjdk.asmtools.asmutils; + +@FunctionalInterface +public interface FormatConsumer { + void format(F t, A... arg); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/HexUtils.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/HexUtils.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/HexUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/HexUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.asmutils; + +import java.util.List; + +/** + * Utility class for Hex strings, bytes manipulations + */ +public class HexUtils { + private static final String hexString = "0123456789ABCDEF"; + private static final char hexTable[] = hexString.toCharArray(); + + public static String toHex(long val, int width) { + StringBuffer sb = new StringBuffer(); + for (int i = width - 1; i >= 0; i--) { + sb.append(hexTable[((int) (val >> (4 * i))) & 0xF]); + } + String s = sb.toString(); + return "0x" + (s.isEmpty() ? "0" : s); + } + + public static String toHex(byte val) { + int width; + for (width = 2; width > 0; width--) { + if ((val >> (width - 1) * 4) != 0) { + break; + } + } + return toHex(val, width); + } + + + public static String toHex(long val) { + int width; + for (width = 16; width > 0; width--) { + if ((val >> (width - 1) * 4) != 0) { + break; + } + } + return toHex(val, width); + } + + public static String toHex(int val) { + int width; + for (width = 8; width > 0; width--) { + if ((val >> (width - 1) * 4) != 0) { + break; + } + } + return toHex(val, width); + } + + /** + * Converts bytes' list ot array + */ + public static byte[] toByteArray(List byteList) { + int length = byteList.size(); + byte[] array = new byte[length]; + for (int i = 0; i < length; i++) { + array[i] = byteList.get(i); + } + return array; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Pair.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Pair.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Pair.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Pair.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.asmutils; + +// Helper class +public class Pair { + public F first; + public S second; + + public Pair(F first, S second) { + this.first = first; + this.second = second; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Pair pair = (Pair) obj; + if (!first.equals(pair.first)) return false; + return second.equals(pair.second); + } + + @Override + public int hashCode() { + int result = first != null ? first.hashCode() : 0; + result = 31 * result + (second != null ? second.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Pair{ " + first + ", " + second + " }"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Range.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Range.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Range.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Range.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.asmutils; + +// Helper class +public record Range>(T from, T to) { + /** + * Verifies that a value is inside the range from the lower bound (from) to the upper bound (to) inclusively. + * + * @param value the value to verify its belonging to the range + * @return true if the value is in the range inclusively. + */ + public boolean in(T value) { + return (this.from.compareTo(value) <= 0) && (this.to.compareTo(value) >= 0); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/StringUtils.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/StringUtils.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/StringUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/StringUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.asmutils; + +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.UTFDataFormatException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.openjdk.asmtools.Main.sharedI18n; + +/** + * Utility class for string operations related to ASM tools. + *

+ * This class provides methods for removing comments from strings, + * converting UTF-8 strings to printable formats, and handling character + * encoding in a way that is suitable for assembly tools. + */ +public class StringUtils { + + public static final char[] hexTable = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + /** + * Removes Java comments from String + * Spaces ahead of comments will be removed; alternatively, if no spaces precede the comment, + * the space after it will be deleted. + * + * @param str string that contains comments + * @return string without comments + */ + public static String removeCommentFrom(String str) { + // firstly delete // comment if exists + int idx = str.indexOf("//"); + if (idx != -1) { + str = str.substring(0, idx--); + if (str.charAt(idx) == ' ') { + str = str.substring(0, idx); + } + } + // remove /* some comment */ comments + String[] list = str.split("\\/\\*.*?\\*\\/"); + if (list.length > 1) { + // comments found + str = ""; + for (int i = 0; i < list.length; i++) { + idx = list[i].length() - 1; + if (list[i].charAt(idx) == ' ') { + str += list[i].substring(0, idx); + } else { + str += list[i]; + idx = i + 1; + if (idx < list.length && list[idx].charAt(0) == ' ') { + list[idx] = list[idx].substring(1); + } + } + } + } + return str; + } + + /** + * Converts CONSTANT_Utf8_info string to a printable string for jdis/jdec. + * + * @param utf8 UTF8 string taken from within ConstantPool of a class file + * @param enclosingString strings to enclose output string + * @return output string for jcod/jasm + */ + public static String Utf8ToString(String utf8, String... enclosingString) { + final String leftBracket = enclosingString.length > 0 ? enclosingString[0] : ""; + final String rightBracket = enclosingString.length > 1 ? enclosingString[1] : leftBracket; + StringBuilder sb = new StringBuilder(leftBracket); + for (int k = 0; k < utf8.length(); k++) { + sb.append(charToUtf8String(utf8.charAt(k))); + } + return sb.append(rightBracket).toString(); + } + + /** + * Converts CONSTANT_Utf8_info string to a printable list of strings + * @param utf8 UTF8 string taken from within ConstantPool of a class file + * @param strLength the maximum length of each string in the resulting list + * @return list of strings for jcod/jasm + */ + public static List Utf8ToStringList(String utf8, int strLength) { + List list = new ArrayList<>(); + String s = ""; + for (int k = 0; k < utf8.length(); k++) { + if (s.length() >= strLength) { + list.add(s); + s = ""; + } + s += charToUtf8String(utf8.charAt(k)); + } + if (!s.isEmpty()) { + list.add(s); + } + return list; + } + + /** + * Converts a character to its UTF-8 string representation. + *

+ * Control characters and special characters are escaped using the appropriate escape sequences. + * Other characters are returned as is. + * + * @param c the character to convert + * @return the UTF-8 string representation of the character + */ + public static String charToUtf8String(char c) { + return switch (c) { + case '\t' -> "\\".concat("t"); + case '\n' -> "\\".concat("n"); + case '\r' -> "\\".concat("r"); + case '\b' -> "\\".concat("b"); + case '\f' -> "\\".concat("f"); + case '\"' -> "\\".concat("\""); + case '\'' -> "\\".concat("\'"); + case '\\' -> "\\".concat("\\"); + default -> Character.isISOControl(c) ? String.format("\\u%04x", (int) c) : Character.toString(c); + }; + } + + + /** + * Checks that ch is in the list + * + * @param i char for testing + * @param list of chars + * @return true if char ch found in the list + */ + public static boolean isOneOf(int i, char... list) { + char ch = (char) i; + for (char c : list) { + if (c == ch) + return true; + } + return false; + } + + /** + * Reads the set of bytes if all bytes are printable then they will be printed + * as the string "String"; otherwise the byte array 0x0F 0xB6 0x00 0x11; + * The result is the list of lines for printing. + * + * @param in input stream to get bytes for printing + * @param length number of bytes + * @param CHARS_IN_LINE max chars in line prepared for printing + * @return list of lines for printing + * @throws IOException exception might happen while reading DataInputStream + */ + public static List readUtf8String(DataInputStream in, int length, int CHARS_IN_LINE) throws IOException { + final int BYTES_IN_LINE = CHARS_IN_LINE / 6 + 1; + final List list = new ArrayList<>(); + List byteLines = new ArrayList() {{ + add(new StringBuilder()); + }}; + StringBuilder sb = byteLines.get(0); + byte[] buffer; + String utfString = null; + int count = 0; + try { + buffer = new byte[length + 2]; + buffer[0] = (byte) (length >> 8); + buffer[1] = (byte) length; + for (int i = 0; i < length; i++) { + byte b = in.readByte(); + buffer[i + 2] = b; + count++; + sb.append("0x").append(hexTable[(b >> 4) & 0xF]).append(hexTable[b & 0xF]); + if (i % BYTES_IN_LINE == BYTES_IN_LINE - 1) { + byteLines.add(sb = new StringBuilder()); + } else if (i + 1 != length) { + sb.append(" "); + } + } + if (count > 0) { + try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(buffer))) { + utfString = DataInputStream.readUTF(dis); + } catch (UTFDataFormatException utfDataFormatException) { + byteLines.add(0, new StringBuilder(format("// == %s ==", sharedI18n.getString("main.error.wrong.utf8")))); + } catch (IOException ignored) { + /*ignored*/ + } + } + } catch (NegativeArraySizeException negativeArraySizeException) { + throw new IOException("Requested array size exceeds VM limit", negativeArraySizeException); + } finally { + if (count > 0) { + List utf8Lines = getPrintable(utfString, CHARS_IN_LINE); + if (utf8Lines != null) { + utf8Lines.stream(). + forEach(s -> list.add(s.startsWith("// ==") ? s : format("\"%s\";", s))); + } else { + byteLines.stream().map(s -> s.toString()). + forEach(s -> list.add(s.startsWith("// ==") ? s : format("%s;", s))); + } + } + } + return list; + } + + /** + * @param buffer array of bytes + * @return null if buffer contains at least one of non-printable bytes + * otherwise the list of strings encoded in the buffer + */ + public static List getPrintable(byte[] buffer, final int CHARS_IN_LINE) { + List list = null; + try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(buffer))) { + String str = dis.readUTF(); + list = getPrintable(str, CHARS_IN_LINE); + } catch (IOException e) {/*ignore*/} + return list; + } + + /** + * @param rawString String + * @return null if buffer contains at least one of non-printable bytes + * otherwise the list of strings split by CHARS_IN_LINE + */ + public static List getPrintable(String rawString, final int CHARS_IN_LINE) { + List list = null; + if (rawString != null) { + String cleanedString = removeNonPrintableAscii(rawString); + if (cleanedString != null && !cleanedString.isEmpty() && !cleanedString.chars().anyMatch(c -> !isPrintableChar((char) c))) { + list = Utf8ToStringList(rawString, CHARS_IN_LINE); + } + } + return list; + } + + /** + * Removes non-printable ASCII characters from the given input string. + *

+ * Non-printable ASCII characters are those with ASCII values outside the range of 32 (space) to 126 (tilde). + * + * @param input the input string to be processed + * @return a new string with non-printable ASCII characters removed, or null if the input is null + */ + public static String removeNonPrintableAscii(String input) { + if (input == null) return null; + StringBuilder result = new StringBuilder(); + for (char c : input.toCharArray()) { + if (c >= 32 && c <= 126) { + result.append(c); + } + } + return result.toString(); + } + + /** + * Converts a list of strings to a formatted string representation. + * The output is enclosed in parentheses and elements are separated by commas. + * + * @param list the list of strings to convert + * @return a formatted string representation of the list + */ + public static String ListToString(List list) { + return ListToString(list, "(,)"); + } + + /** + * Converts a list of strings to a formatted string representation. + * The output is enclosed in square brackets and elements are separated by a specified delimiter. + * + * @param list the list of strings to convert + * @param separators a string containing the prefix, delimiter, and postfix characters + * (e.g., "[,]"), where: + * - first character is the prefix, + * - second character is the delimiter, + * - third character is the postfix. + * @return a formatted string representation of the list + */ + public static String ListToString(List list, String separators) { + int l = separators.length(); + String prefix = separators != null && l > 0 ? separators.substring(0, 1) : "["; + String delim = separators != null && l > 1 ? separators.substring(1, 2) : ","; + String postfix = separators != null && l > 2 ? separators.substring(2, 3) : "]"; + return prefix.concat(" ") + String.join(delim.concat(" "), list) + " ".concat(postfix); + } + + /** + * Converts an array of integers to a hex string representation. + * Each integer is converted to its hexadecimal format and joined with commas. + * + * @param array the array of integers to convert + * @return a string representation of the array in hexadecimal format + */ + public static String mapToHexString(int[] array) { + return format("{%s}", + Arrays.stream(array).mapToObj(HexUtils::toHex).collect(Collectors.joining(", "))); + } + + public static String repeat(String str, int count) { + return count <= 0 ? "" : new String(new char[count]).replace("\0", str); + } + + /** + * Checks if the character is printable. + * A character is considered printable if it is not a control character, + * is not undefined, and belongs to a valid Unicode block that is not SPECIALS. + * + * @param c the character to check + * @return true if the character is printable, false otherwise + */ + public static boolean isPrintableChar(char c) { + Character.UnicodeBlock block = Character.UnicodeBlock.of(c); + return (!Character.isISOControl(c)) && + c != KeyEvent.CHAR_UNDEFINED && + block != null && + block != Character.UnicodeBlock.SPECIALS; + } + + public static BiFunction, Boolean> endWith = (str, list) -> { + for (String suffix : list) { + if (str.endsWith(suffix)) { + return true; + } + } + return false; + }; + + public static BiFunction, Boolean> contains = (str, list) -> { + for (String substr : list) { + if (str.contains(substr)) { + return true; + } + } + return false; + }; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Triplet.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Triplet.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Triplet.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/asmutils/Triplet.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.asmutils; + +// Helper class +public class Triplet extends Pair { + public final T third; + + public Triplet(F first, S second, T third) { + super(first, second); + this.third = third; + } + + @Override + public String toString() { + return "Triplet{ " + first + ", " + second + ", " + third + " }"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Compiler.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Compiler.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Compiler.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Compiler.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import static org.openjdk.asmtools.common.Environment.OK; + +public abstract class Compiler> extends Tool { + protected Compiler(ToolOutput toolOutput, DualStreamToolOutput outerLog) { + super(toolOutput, outerLog); + } + + public synchronized boolean compile(String... argv) { + parseArgs(argv); + return this.compile() == OK; + } + + // Run a compiler when args already parsed + public abstract int compile(); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerConstants.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerConstants.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerConstants.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerConstants.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +/** + * This interface defines constant that are used throughout the compiler. It inherits from + * RuntimeConstants, which is an autogenerated class that contains constants defined in + * the interpreter. + */ +public interface CompilerConstants { + // End of input + int EOF = -1; + + // Jasm: Number of bits used in file offsets + int OFFSET_BITS = 32; + + //Jcoder: The increment for each character. + int OFFSET_INC = 1; + + // BACKSLASH is a special code indicating a pushback of a backslash that + // definitely isn't the start of a unicode sequence. + int BACKSLASH = -2; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerLogger.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerLogger.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerLogger.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/CompilerLogger.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.io.IOException; +import java.util.*; +import java.util.function.Function; +import java.util.regex.Matcher; + +import static java.lang.Math.min; +import static java.lang.String.format; +import static org.openjdk.asmtools.asmutils.StringUtils.repeat; +import static org.openjdk.asmtools.common.CompilerConstants.OFFSET_BITS; +import static org.openjdk.asmtools.common.EMessageKind.ERROR; +import static org.openjdk.asmtools.common.EMessageKind.WARNING; +import static org.openjdk.asmtools.common.Environment.OK; +import static org.openjdk.asmtools.common.structure.CFVersion.DEFAULT_MAJOR_VERSION; +import static org.openjdk.asmtools.common.structure.CFVersion.DEFAULT_MINOR_VERSION; + +// error,warning and info message is general and attached to a position of a scanned file. +public class CompilerLogger extends ToolLogger implements ILogger { + + // Message Container + private final Map> container = new HashMap<>(); + private final List fileContent = new ArrayList<>(); + + /** + * @param programName the tool name + * @param cls the environment class of the tool for which to obtain the resource bundle + * @param outerLog the logger stream + */ + public CompilerLogger(String programName, Class cls, DualStreamToolOutput outerLog) { + super(programName, cls, outerLog); + } + + @Override + public void warning(long where, String id, Object... args) { + Message message = getResourceString(WARNING, id, args); + if (message.notFound()) { + if (EMessageKind.isFromResourceBundle(id)) { + insert(NOWHERE, new Message(ERROR, "(I18NResourceBundle) The warning message '%s' not found", id)); + } else { + insert(where, new Message((strictWarnings) ? ERROR : WARNING, args.length == 0 ? id : format(id, args))); + } + } else { + insert(where, strictWarnings ? new Message(ERROR, message.text()) : message); + } + } + + @Override + public void error(long where, String id, Object... args) { + Message message = getResourceString(ERROR, id, args); + if (message.notFound()) { + if (EMessageKind.isFromResourceBundle(id)) { + insert(NOWHERE, new Message(ERROR, "(I18NResourceBundle) The error message '%s' not found", id)); + } else { + insert(where, new Message(ERROR, args.length == 0 ? id : format(id, args))); + } + } else { + insert(where, message); + } + } + + @Override + public String getInfo(String id, Object... args) { + String message = getResourceString(id, args); + if (message == null) { + if (EMessageKind.isFromResourceBundle(id)) { + printErrorLn("(I18NResourceBundle) The info message '%s' not found", id); + } else { + println(id, args); + } + } + return message; + } + + @Override + public void usage(List usageIDs) { + usage(usageIDs, id -> id.equals("info.opt.cv") ? + getInfo(id, DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION) : + getInfo(id)); + } + + @Override + public void usage(List usageIDs, Function func) { + for (String id : usageIDs) { + String s = func.apply(id); + if (s != null) { + Matcher m = usagePattern.matcher(s); + if (m.find()) { + println(format(" %-35s %s", m.group(1).trim(), m.group(2).trim())); + } else { + println(s); + } + } + } + } + + @Override + public void setInputFileName(ToolInput inputFileName) throws IOException { + super.setInputFileName(inputFileName); + fileContent.clear(); + fileContent.addAll(inputFileName.readAllLines()); + } + + /** + * Gets a pair of line number and line position for the pointer where A position consists of: ((linenr >> OFFSETBITS) | offset) + * this means that both the line number and the exact offset into the file are encoded in each position value. + * + * @param where absolute position in file = (linepos << OFFSETBITS) | bytepos; + * @return the pair: [line number, line offset] + */ + Pair filePosition(long where) { + if (where == NOWHERE || fileContent.isEmpty()) { + return null; + } else { + long lineNumber = lineNumber(where); + return new Pair<>(lineNumber, lineOffset(lineNumber, where)); + } + } + + public long lineNumber(long where) { + return where >> OFFSET_BITS; + } + + public long lineOffset(long lineNumber, long where) { + long absPos = where & ((1L << OFFSET_BITS) - 1); + return absPos - (fileContent.subList(0, (int) lineNumber - 1). + stream().mapToInt(String::length).sum() + lineNumber - 1); + + } + + public long getCount(EMessageKind kind) { + return noMessages() ? 0 : container.values().stream(). + flatMap(Collection::stream).filter(m -> m.kind() == kind).count(); + } + + public boolean noMessages() { + return container.isEmpty(); + } + + /** + * @param printTotals whether to print the total line: N warning(s), K error(s) + * @return 0 if there are no errors otherwise a number of errors + */ + public synchronized int flush(boolean printTotals) { + if (noMessages()) return OK; + int nErrors = 0, nWarnings = 0; + List>> list = new ArrayList<>(container.entrySet()); + list.sort(Map.Entry.comparingByKey()); + ToolOutput output = getOutputs().getSToolObject(); + for (Map.Entry> entry : list) { + long where = entry.getKey(); + Pair filePosition = filePosition(where); + for (Message msg : entry.getValue()) { + if (msg.kind() == WARNING && ignoreWarnings) { + continue; + } + if (msg.kind() == ERROR) { + output = getOutputs().getEToolObject(); + nErrors++; + } + nWarnings += msg.kind() == WARNING ? 1 : 0; + if (where == NOWHERE) { + // direct message isn't connected to a position in a scanned file + output.printlns(msg.text()); + } else { + output.printlns(format("%s (%d:%d) %s", getSimpleInputFileName(), + filePosition.first, filePosition.second, + msg.text())); + printAffectedSourceLine(output, filePosition); + } + } + } + DualStreamToolOutput totalOutput = (printTotals) ? getOutputs() : null; + if (printTotals) { + if (nWarnings != 0) + totalOutput.printe(format("%d warning(s)%s", nWarnings, nErrors != 0 ? ", " : "\n")); + if (nErrors != 0) + totalOutput.printlne(format("%d error(s)", nErrors)); + } + + synchronized (output) { + output.flush(); + if (totalOutput != null) { + totalOutput.flush(); + } + container.clear(); + } + + return nErrors; + } + + // Removes tabs from a source line to get the correct line position while printing. + private void printAffectedSourceLine(ToolOutput output, Pair filePosition) { + int ln = (int) (filePosition.first - 1); + boolean eof = filePosition.first > fileContent.size(); + String line = fileContent.get(min(fileContent.size() - 1, ln)); + long countOfExtraSpaces = line.chars().filter(ch -> ch == '\t').count(); + line = line.replace("\t", TAB_REPLACEMENT); + long linePosition = (eof) ? line.length() : + (filePosition.second + countOfExtraSpaces * TAB_REPLACEMENT.length()) - countOfExtraSpaces; + output.printlns(line); + output.printlns(repeat(" ", (int) linePosition) + "^"); + } + + /** + * Insert a message in the list of outstanding messages. The list is sorted on input position. + */ + private void insert(long where, Message message) { + if (where != NOWHERE && fileContent.isEmpty()) { + addToContainer(NOWHERE, + new Message(ERROR, EMessageFormatter.LONG.apply(ERROR, this.getProgramName(), + "Content of the file %s not found", getSimpleInputFileName()))); + where = NOWHERE; + } + // message format + addToContainer(where, new Message(message.kind(), where == NOWHERE ? + EMessageFormatter.VERBOSE.apply(this.getProgramName(), message) : + EMessageFormatter.LONG.apply(this.getProgramName(), message))); + } + + private void addToContainer(long where, Message msg) { + Set messages = container.get(where); + if (messages != null) { + messages.add(msg); + } else { + Set msgSet = new HashSet<>(1); + msgSet.add(msg); + container.put(where, msgSet); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Decoder.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Decoder.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Decoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Decoder.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import static org.openjdk.asmtools.common.Environment.OK; + +public abstract class Decoder> extends Tool { + protected Decoder(ToolOutput toolOutput, DualStreamToolOutput outerLog) { + super(toolOutput, outerLog); + } + + // Runs the decoder with args + public synchronized boolean decode(String... argv) { + parseArgs(argv); + return this.decode() == OK; + } + + // Run a decoder when args already parsed + public abstract int decode(); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/DecompilerLogger.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/DecompilerLogger.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/DecompilerLogger.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/DecompilerLogger.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Matcher; + +import static java.lang.Math.max; +import static java.lang.String.format; +import static org.openjdk.asmtools.common.EMessageKind.ERROR; +import static org.openjdk.asmtools.common.EMessageKind.WARNING; +import static org.openjdk.asmtools.common.Environment.OK; + +public class + +DecompilerLogger extends ToolLogger implements ILogger { + + // Message Container + private final LinkedHashSet messages = new LinkedHashSet(); + + private Consumer addToContainer = (String msg) -> { + if (msg != null) { + messages.add(msg); + } + }; + + /** + * @param programName the tool name + * @param cls the environment class of the tool for which to obtain the resource bundle + * @param outerLog the logger stream + */ + public DecompilerLogger(String programName, Class cls, DualStreamToolOutput outerLog) { + super(programName, cls, outerLog); + } + + + @Override + public void warning(String id, Object... args) { + String msg = getResourceString(id, args); + if (msg == null) { + if (EMessageKind.isFromResourceBundle(id)) { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.ERROR, + "(I18NResourceBundle) The warning message '%s' not found", id); + } else { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.WARNING, super.getProgramName(), format(id, args)); + } + } else { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.WARNING, super.getProgramName(), msg); + } + addToContainer.accept(msg); + } + + @Override + public void error(String id, Object... args) { + String msg = getResourceString(id, args); + if (msg == null) { + if (EMessageKind.isFromResourceBundle(id)) { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.ERROR, + super.getProgramName(), + "(I18NResourceBundle) The error message '%s' not found", id); + } else { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.ERROR, super.getProgramName(), format(id, args)); + } + } else { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.ERROR, super.getProgramName(), msg); + } + addToContainer.accept(msg); + } + + @Override + public void info(String id, Object... args) { + String msg = getResourceString(id, args); + if (msg == null) { + if (EMessageKind.isFromResourceBundle(id)) { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.ERROR, + super.getProgramName(), + "(I18NResourceBundle) The error message '%s' not found", id); + } else { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.ERROR, super.getProgramName(), format(id, args)); + } + } else { + msg = EMessageFormatter.SHORT.apply(EMessageKind.ERROR, super.getProgramName(), msg); + } + addToContainer.accept(msg); + } + + @Override + public void printErrorLn(String format, Object... args) { + String msg = (args == null || args.length == 0) ? format : format(format, args); + addToContainer.accept(msg); + } + + + @Override + public void error(Throwable exception) { + String msg = ToolLogger.EMessageFormatter.VERBOSE.apply(ERROR, super.getProgramName(), exception.getMessage()); + addToContainer.accept(msg); + } + + @Override + public String getInfo(String id, Object... args) { + String message = getResourceString(id, args); + if (message == null) { + String msg; + if (EMessageKind.isFromResourceBundle(id)) { + msg = EMessageFormatter.VERBOSE.apply(EMessageKind.ERROR, super.getProgramName(), + "(I18NResourceBundle) The error message '%s' not found", id); + } else { + msg = (args == null || args.length == 0) ? id : format(id, args); + } + addToContainer.accept(msg); + } + return message; + } + + @Override + public long getCount(EMessageKind kind) { + return messages.stream().filter(msg -> msg.contains(kind.shortForm())).count(); + } + + public int registerTotalIssues(int rc, ToolInput toolInput) { + int ret = OK; + int nErrors = (int) getCount(ERROR); + int nWarnings = (int) getCount(WARNING); + if (nWarnings > 0 || nErrors > 0) { + // don't take into account warnings + ret = max(rc, nErrors); + String sWarnings = (nWarnings > 0) ? + "%d warning(s)".formatted(nWarnings).concat((nErrors > 0) ? ", " : "") : ""; + String sErrors = (nErrors > 0) ? "%d error(s) ".formatted(nErrors) : " "; + info("err.count.issues", sWarnings, sErrors, toolInput); + } + return ret; + } + + public synchronized void flush() { + if (!messages.isEmpty()) { + DualStreamToolOutput output = getOutputs(); + // output.printe('\n'); + for (String msg : messages) { + output.printlne(msg); + } + synchronized (output) { + output.flush(); + messages.clear(); + } + } + } + + @Override + public void usage(List usageIDs) { + usage(usageIDs, id -> getInfo(id)); + } + + @Override + public void usage(List usageIDs, Function func) { + for (String id : usageIDs) { + String s = func.apply(id); + if (s != null) { + Matcher m = usagePattern.matcher(s); + if (m.find()) { + println(format(" %-21s %s", m.group(1).trim(), m.group(2).trim())); + if (s.contains("\n")) { + // multiline + String[] lines = s.split("\\n"); + for (int i = 1; i < lines.length; i++) { + println(format("%s%s", " ".repeat(24), lines[i].trim())); + } + } + } else { + String[] lines = s.split("\\n"); + if (lines.length > 1 && lines[0].trim().startsWith("-")) { + println(format(" %s", lines[0].trim())); + for (int i = 1; i < lines.length; i++) { + println(format("%s%s", " ".repeat(24), lines[i].trim())); + } + } else { + println(s); + } + } + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/EMessageKind.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/EMessageKind.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/EMessageKind.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/EMessageKind.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +package org.openjdk.asmtools.common; + +public enum EMessageKind { + ERROR("err."), + WARNING("warn."), + INFO("info."); + final String prefix; + + EMessageKind(String prefix) { + this.prefix = prefix; + } + + public static boolean isFromResourceBundle(String msg) { + for (EMessageKind kind : values()) { + if (msg.startsWith(kind.prefix)) { + return true; + } + } + return false; + } + + public String longForm() { + return name().substring(0, 1) + name().substring(1).toLowerCase(); + } + + public String shortForm() { + return name().length() > 5 ? name().substring(0, 4) : name(); + } +} + + diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Environment.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Environment.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Environment.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Environment.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.io.DataInputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract class Environment implements ILogger { + + // Results + public final static int OK = 0; + public final static int FAILED = 1; + + T toolLogger; + + //-w Specify where to place generated class files, without considering the classpath. + // If not specified, output will be directed to . + private boolean ignorePackage = false; + + // processed input file or stdin + private ToolInput toolInput; + private ToolOutput toolOutput; + // checks output verbosity + private boolean verboseFlag; + + public boolean isTraceFlag() { + return traceFlag; + } + + private boolean traceFlag; + + /** + * @param builder the environment builder + */ + protected Environment(Builder builder) { + this.toolOutput = builder.toolOutput; + this.toolLogger = (T) builder.toolLogger; + } + + public void setToolInput(ToolInput toolInput) throws IOException, URISyntaxException { + this.toolInput = toolInput; + toolLogger.setInputFileName(toolInput); + } + + public void setTraceFlag(boolean flag) { + this.traceFlag = flag; + } + + public void setIgnoreWarningsOn() { + toolLogger.ignoreWarnings = true; + } + + public void setStrictWarningsOn() { + toolLogger.strictWarnings = true; + } + + + public boolean isIgnorePackage() { + return ignorePackage; + } + + public Environment setIgnorePackage(boolean ignorePackage) { + this.ignorePackage = ignorePackage; + return this; + } + + public String getSimpleInputFileName() { + return toolLogger.getSimpleInputFileName(); + } + + /** + * Returns the name of the source file that is used by the tool to assemble the SourceFile attribute + * + * @return the name of the source file + */ + public String getSourceName() { + String sourceFileName = getSimpleInputFileName(); + String sourceName = sourceFileName.contains(".") ? + sourceFileName.substring(0, sourceFileName.indexOf('.')) : + sourceFileName; + return sourceName; + } + + public ToolInput getToolInput() { + return toolInput; + } + + /** + * @return DataInputStream or null if the method can't read a file + */ + protected DataInputStream getDataInputStream() throws URISyntaxException, IOException { + Objects.requireNonNull(this.toolInput, "Input must be defined."); + return toolInput.getDataInputStream(Optional.of(this)); + } + + @Override + public void traceln(String id, Object... args) { + if (traceFlag) + ILogger.super.traceln(id, args); + } + + public void traceln(Supplier supplier) { + if (traceFlag) { + ILogger.super.traceln(supplier.get()); + } + } + + @Override + public void trace(String id, Object... args) { + if (traceFlag) + ILogger.super.trace(id, args); + } + + @Override + public void error(String id, Object... args) { + toolLogger.error(id, args); + } + + @Override + public void error(Throwable exception) { + toolLogger.error(exception); + } + + public void trace(Supplier supplier) { + if (traceFlag) { + ILogger.super.trace(supplier.get()); + } + } + + @Override + public void info(String id, Object... args) { + toolLogger.info(id, args); + } + + public String getInfo(String id, Object... args) { + return toolLogger.getInfo(id, args); + } + + public void usage(List ids) { + toolLogger.usage(ids); + } + + public void usage(List ids, Function func) { + toolLogger.usage(ids, func); + } + + @Override + public void printException(Throwable throwable) { + if (verboseFlag) + toolLogger.printException(throwable); + } + + @Override + public DualStreamToolOutput getOutputs() { + return getLogger().getOutputs(); + } + + @Override + public void setOutputs(DualStreamToolOutput nw) { + getLogger().setOutputs(nw); + } + + @Override + public ToolOutput getToolOutput() { + return toolOutput; + } + + @Override + public void setToolOutput(ToolOutput toolOutput) { + this.toolOutput = toolOutput; + } + + public boolean getVerboseFlag() { + return verboseFlag; + } + + public Environment setVerboseFlag(boolean value) { + this.verboseFlag = value; + return this; + } + + public T getLogger() { + return (T) toolLogger; + } + + /** + * The Environment builder. + */ + public abstract static class Builder { + T toolLogger; + public ToolOutput toolOutput; + + public Builder(ToolOutput toolOutput, T toolLogger) { + this.toolOutput = toolOutput; + this.toolLogger = toolLogger; + } + + /** + * @return new environment + */ + abstract public E build(); + } +} // end Environment diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/ErrorMessage.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ErrorMessage.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/ErrorMessage.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ErrorMessage.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +package org.openjdk.asmtools.common; + +/** + * A sorted list of error messages + */ +public final class ErrorMessage { + + public int where; + public String message; + public ErrorMessage next; + + /** + * Constructor + */ + public ErrorMessage(int where, String message) { + this.where = where; + this.message = message; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/FormatError.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/FormatError.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/FormatError.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/FormatError.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +/** + * FormatError is the generic error thrown by jdis, jdec while parsing a class file. + */ +public class FormatError extends ClassFormatError { + + /** + * Checks and returns formatted string if id isn't a reference in i18n.properties + * + * @param id either format string or a resource id + * @param args arguments of the format string + * @return null id isn't format string otherwise formatted string + */ + private static String getResourceMsg(String id, Object... args) { + return id.startsWith("err.") || id.startsWith("warn.") ? null : String.format(id, args); + } + + public FormatError(T logger, String id, Object... args) { + super( logger.getResourceString(id, args) == null ? + (FormatError.getResourceMsg(id, args) == null ? "(i18n.properties) The message '" + id + "' not found" : FormatError.getResourceMsg(id, args)) + : logger.getResourceString(id, args)); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/ILogger.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ILogger.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/ILogger.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ILogger.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.util.regex.Pattern; + +import static java.lang.String.format; + +public interface ILogger { + + // A logged message isn't attached to a position of a parsed file + int NOWHERE = Integer.MAX_VALUE; + // Replacement for the tab found in an input + CharSequence TAB_REPLACEMENT = " ".repeat(4); + + Pattern usagePattern = Pattern.compile("(-\\S+\\p{Blank}*\\S*)\\p{Blank}+([PGSDCSOIU]+.*)"); + + default String getResourceString(String id, Object... args) { + throw new NotImplementedException(); + } + + default void warning(long where, String id, Object... args) { + throw new NotImplementedException(); + } + + default void error(long where, String id, Object... args) { + throw new NotImplementedException(); + } + + default void info(String id, Object... args) { + String message = getInfo(id, args); + if (message != null) { + println(message); + } + } + + default long getCount(EMessageKind kind) { + throw new NotImplementedException(); + } + + default String getInfo(String id, Object... args) { + throw new NotImplementedException(); + } + + default void warning(String id, Object... args) { + throw new NotImplementedException(); + } + + default void error(String id, Object... args) { + throw new NotImplementedException(); + } + + default void error(Throwable exception) { + error(NOWHERE, exception.getMessage()); + } + + default void traceln(String format, Object... args) { + getOutputs().printlne((args == null || args.length == 0) ? format : format(format, args)); + ; + } + + default void trace(String format, Object... args) { + getOutputs().printe((args == null || args.length == 0) ? format : format(format, args)); + } + + default void printErrorLn(String format, Object... args) { + getOutputs().printlne((args == null || args.length == 0) ? format : format(format, args)); + } + + default void println(String format, Object... args) { + getOutputs().printlns((args == null || args.length == 0) ? format : format(format, args)); + } + + default void println() { + getOutputs().printlns(""); + } + + default void print(String format, Object... args) { + getOutputs().prints((args == null || args.length == 0) ? format : format(format, args)); + } + + default void print(char ch) { + getOutputs().prints(ch); + } + + DualStreamToolOutput getOutputs(); + + void setOutputs(DualStreamToolOutput nwoutput); + + default ToolOutput getToolOutput() { + throw new NotImplementedException("implement wisely!"); + } + + default void setToolOutput(ToolOutput toolOutput) { + throw new NotImplementedException("implement wisely!"); + } + + void printException(Throwable throwable); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/NotImplementedException.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/NotImplementedException.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/NotImplementedException.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/NotImplementedException.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,11 @@ +package org.openjdk.asmtools.common; + +/** class used to indicate missing functionality */ +public class NotImplementedException extends RuntimeException { + public NotImplementedException() { + super("The method is not yet implemented"); + } + public NotImplementedException(String reason) { + super(reason); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/SyntaxError.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/SyntaxError.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/SyntaxError.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/SyntaxError.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +/** + * SyntaxError is the generic error thrown by jasm, jcoder while parsing either a jasm file or jcod file. + */ +public class SyntaxError extends Error { + private boolean fatalError = false; + + public SyntaxError setFatal() { + this.fatalError = true; + return this; + } + + public boolean isFatal() { + return this.fatalError; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Tool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Tool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/Tool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/Tool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + + +import org.openjdk.asmtools.common.inputs.StdinInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.FSOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.io.File; +import java.util.ArrayList; + +import static org.openjdk.asmtools.common.outputs.FSOutput.FSDestination.DIR; + +public abstract class Tool> { + + protected final ArrayList fileList = new ArrayList<>(); + protected T environment; + private ToolOutput toolOutput; + + protected Tool(ToolOutput toolOutput, DualStreamToolOutput outerLog) { + this.environment = getEnvironment(toolOutput, outerLog); + } + + public Environment setVerboseFlag(boolean value) { + environment.setVerboseFlag(value); + return environment; + } + + public Environment setTraceFlag(boolean value) { + environment.setTraceFlag(value); + return environment; + } + + public T getEnvironment() { + return environment; + } + + // Build environment + public T getEnvironment(ToolOutput toolOutput, DualStreamToolOutput outerLog) { + throw new NotImplementedException(); + } + + // Usage + protected abstract void usage(); + + // Parse arguments. The Tool will be left using System.Exit if an error is found. + protected abstract void parseArgs(String... argv); + + protected void setFSDestination(FSOutput.FSDestination destination, int index, String... argv) { + File file; + if ((index) >= argv.length) { + environment.error(destination == FSOutput.FSDestination.FILE ? "err.f_requires_argument" : "err.d_requires_argument"); + usage(); + throw new IllegalArgumentException(); + } + String fname = argv[index]; + file = new File(fname); + if (destination == DIR && !file.exists()) { + environment.error("err.does_not_exist", fname); + throw new IllegalArgumentException(); + } + if (toolOutput == null) { + toolOutput = new FSOutput(); + } + switch (destination) { + case FILE: + environment.setToolOutput(((FSOutput) toolOutput).setFile(new File("."), fname)); + break; + case DIR: + environment.setToolOutput(((FSOutput) toolOutput).setDir(file)); + } + } + + protected void addStdIn() { + for (ToolInput toolInput : fileList) { + if (toolInput instanceof StdinInput) { + //or throw? + return; + } + } + fileList.add(new StdinInput()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/ToolLogger.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ToolLogger.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/ToolLogger.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/ToolLogger.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.util.I18NResourceBundle; + +import java.io.IOException; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +import static java.lang.String.format; +import static org.openjdk.asmtools.Main.sharedI18n; +import static org.openjdk.asmtools.common.EMessageKind.ERROR; +import static org.openjdk.asmtools.common.EMessageKind.INFO; + +public abstract class ToolLogger implements ILogger { + + protected boolean ignoreWarnings = false; // do not print / ignore warnings + protected boolean strictWarnings = false; // consider warnings as errors + + class ToolResources { + private final static HashMap resources = new HashMap<>(); + + public ToolResources(String programName, Class cls) { + if (!ToolResources.resources.containsKey(programName)) { + ToolResources.resources.put(programName, I18NResourceBundle.getBundleForClass(cls)); + } + } + + public void setWarn(boolean value) { + ToolResources.resources.get(ToolLogger.this.programName).setWarn(value); + } + + public String getString(String id, Object... args) { + return ToolResources.resources.get(ToolLogger.this.programName).getString(id, args); + } + + public boolean containsKey(String key) { + return ToolResources.resources.get(ToolLogger.this.programName).containsKey(key); + } + } + + private final String programName; + + private ToolResources toolResources; + + DualStreamToolOutput outerLog; + // Input file name is needed for logging purposes + private String inputFileName; + private String simpleInputFileName; + + static { + sharedI18n.setWarn(false); + } + + /** + * @param programName the tool name + * @param cls the environment class of the tool for which to obtain the resource bundle + * @param outerLog the logger stream + */ + public ToolLogger(String programName, Class cls, DualStreamToolOutput outerLog) { + // Set Resource bundle for the tool + this.toolResources = new ToolResources(programName, cls); + this.programName = programName; + this.outerLog = outerLog; + } + + @Override + public String getResourceString(String id, Object... args) { + String resString; + toolResources.setWarn(false); + try { + resString = toolResources.getString(id, args); + } finally { + toolResources.setWarn(true); + } + if (resString == null || resString.equals(id)) { + resString = sharedI18n.getString(id, args); + } + if (resString == null || resString.equals(id)) { + //to get a proper error message + resString = toolResources.getString(id, args); + } + return resString; + } + + public void setInputFileName(ToolInput inputFileName) throws IOException { + this.inputFileName = inputFileName.getName(); + this.simpleInputFileName = Paths.get(inputFileName.getName()).getFileName().toString(); + // the content of the input file will be loaded only if the file is parsed by jasm/jcoder + } + + public Message getResourceString(EMessageKind kind, String id, Object... args) { + String str; + for (String prefix : Set.of("", kind.prefix)) { + if (toolResources.containsKey(prefix + id) || sharedI18n.containsKey(prefix + id)) { + str = getResourceString(id, args); + if (str != null) { + return new Message(kind, str); + } + } + } + return new Message(ERROR, null); + } + + @Override + public DualStreamToolOutput getOutputs() { + return outerLog; + } + + @Override + public void setOutputs(DualStreamToolOutput nwoutput) { + this.outerLog = nwoutput; + } + + public String getSimpleInputFileName() { + return simpleInputFileName; + } + + @Override + public void printException(Throwable throwable) { + getOutputs().stacktrace(throwable); + } + + public String getProgramName() { + return programName; + } + + public abstract void usage(List ids); + + public abstract void usage(List ids, Function func); + + public enum EMessageFormatter { + SHORT((severity, name, message) -> format("%s", message)), + LONG((severity, name, message) -> format("%s: %s", severity.longForm(), message)), + VERBOSE((severity, name, message) -> severity == INFO ? message : + format("%-7s-%6s: %s", name, severity.shortForm(), message)); + final private TriFunction triFunc; + + EMessageFormatter(TriFunction func) { + this.triFunc = func; + } + + public String apply(EMessageKind kind, String name, String format, Object... args) { + return (format == null || name == null) ? "" : triFunc.apply(kind, name, format(format, args)); + } + + public String apply(String name, Message message) { + return message.notFound() ? "" : triFunc.apply(message.kind(), name, message.text()); + } + } + + public record Message(EMessageKind kind, String text) { + + Message(EMessageKind kind, String format, Object... args) { + this(kind, format(format, args)); + } + + public boolean notFound() { + return kind == ERROR && text == null; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/TriFunction.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/TriFunction.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/TriFunction.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/TriFunction.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +@FunctionalInterface +public interface TriFunction { + R apply(T t, U u, V v); + + // Default method to compose functions (like BiFunction.andThen) + default TriFunction andThen(java.util.function.Function after) { + if (after == null) throw new NullPointerException("After function must not be null"); + return (t, u, v) -> after.apply(apply(t, u, v)); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ByteInput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ByteInput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ByteInput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ByteInput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023, 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.inputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.*; +import java.net.URISyntaxException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; + +public class ByteInput implements ToolInput { + + private boolean detailedInput = false; + private MessageDigest md = null; + + //compilers passes input more than one times, so saving it for reuse; + protected byte[] bytes; + + public ByteInput(final byte[] bytes) { + this.bytes = bytes; + } + + protected ByteInput() { + } + + public byte[] getBytes() { + return bytes; + } + + public ByteInput setDetailedInput(boolean detailedInput) { + this.detailedInput = detailedInput; + return this; + } + + @Override + public MessageDigest getMessageDigest() { + return md; + } + + @Override + public int getSize() { + return bytes.length; + } + + @Override + public String getName() { + //get parent is used + return "bytes/bytes"; + } + + @Override + public String toString() { + return getName(); + } + + protected void init() { + + } + + @Override + public DataInputStream getDataInputStream(Optional logger) { + init(); + try { + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + if (detailedInput) { + md = MessageDigest.getInstance("SHA-256"); + DigestInputStream dis = new DigestInputStream(bais, md); + return new DataInputStream(dis); + } else { + return new DataInputStream(bais); + } + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + @Override + public Collection readAllLines() throws IOException { + init(); + ArrayList resultingLines = new ArrayList(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), "utf-8"))) { + while (true) { + String l = br.readLine(); + if (l == null) { + break; + } + resultingLines.add(l); + } + } + return resultingLines; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/FileInput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/FileInput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/FileInput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/FileInput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.inputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Collection; +import java.util.Optional; + +public class FileInput implements ToolInput { + + private boolean detailedInput = false; + private final String fileName; + private MessageDigest md = null; + private CapacityInputStream cis = null; + + public FileInput(String fileName) { + this.fileName = fileName; + } + + @Override + public String getName() { + return fileName; + } + + public Collection readAllLines() throws IOException { + return Files.readAllLines(Paths.get(getName())); + } + + public FileInput setDetailedInput(boolean detailedInput) { + this.detailedInput = detailedInput; + return this; + } + + @Override + public MessageDigest getMessageDigest() { + return md; + } + + @Override + public int getSize() { + return cis != null ? cis.size() : 0; + } + + @Override + public DataInputStream getDataInputStream(Optional logger) throws URISyntaxException, IOException { + try { + FileInputStream fis = new FileInputStream(this.getName()); + if (detailedInput) { + cis = new CapacityInputStream(fis); + md = MessageDigest.getInstance("SHA-256"); + DigestInputStream dis = new DigestInputStream(cis, md); + return new DataInputStream(dis); + } else { + return new DataInputStream(fis); + } + } catch (IOException ex) { + if (this.getName().matches("^[A-Za-z]+:.*")) { + try { + final URI uri = new URI(this.getName()); + final URL url = uri.toURL(); + final URLConnection conn = url.openConnection(); + conn.setUseCaches(false); + return new DataInputStream(conn.getInputStream()); + } catch (URISyntaxException | IOException exception) { + if (logger.isPresent()) { + logger.get().error("err.cannot.read", this.getName()); + } + throw exception; + } + } else { + throw ex; + } + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + @Override + public String toString() { + return getName(); + } + + private static class CapacityInputStream extends FilterInputStream { + CapacityInputStream(InputStream in) { + super(in); + } + + int size() { + return size; + } + + @Override + public int read(byte[] buf, int offset, int length) throws IOException { + int n = super.read(buf, offset, length); + if (n > 0) + size += n; + return n; + } + + @Override + public int read() throws IOException { + int b = super.read(); + size += 1; + return b; + } + + private int size; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StdinInput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StdinInput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StdinInput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StdinInput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.inputs; + +public class StdinInput extends StreamInput { + + public StdinInput() { + super(System.in); + } + + @Override + public String getName() { + //get parent is used + return "stdin/stdin"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StreamInput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StreamInput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StreamInput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StreamInput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.inputs; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +public class StreamInput extends ByteInput { + + private final InputStream originalStream; + + public StreamInput(InputStream is) { + originalStream = is; + } + + @Override + protected void init() { + if (bytes == null) { + bytes = drainIs(originalStream); + } + } + + public static byte[] drainIs(InputStream is) { + try { + byte[] buffer = new byte[32 * 1024]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int bytesRead; + while ((bytesRead = is.read(buffer)) > 0) { + baos.write(buffer, 0, bytesRead); + } + return baos.toByteArray(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public String getName() { + //get parent is used + return "stream/stream"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StringInput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StringInput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StringInput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/StringInput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.inputs; + +import java.nio.charset.StandardCharsets; + +public class StringInput extends ByteInput { + + public StringInput(final String bytes) { + super(bytes.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public String getName() { + //get parent is used + return "string/string"; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/TextInput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/TextInput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/TextInput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/TextInput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.inputs; + +import java.io.DataInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +/** + * Base class for JasmEnvironment.InputFile and + * JcoderEnvironment.InputFile that read the jasm, jcod text files + */ +public abstract class TextInput { + + public long position; + protected int charPos = 0; + protected int linepos = 1; + + + // Buffer to keep the text file content + protected final String strData; + + public TextInput(DataInputStream dataInputStream) throws IOException { + byte[] data = new byte[dataInputStream.available()]; + dataInputStream.read(data); + strData = new String(data, StandardCharsets.UTF_8); + dataInputStream.close(); + } + + public abstract int readUTF(); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ToolInput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ToolInput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ToolInput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/inputs/ToolInput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.inputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.DataInputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.MessageDigest; +import java.util.Collection; +import java.util.Optional; + +/** + * This class is a generic interface, symbolising any input for jdis/jasm/jdec/jcoder. + * Asmtools as application internally uses FileInput and StdinInput. + * UnitTests for asmtools uses mainly StringInput for assemblers and ByteInput for disassemblers. + *

+ * String/Byte/Stream inputs can be used as any 3rd part code which do not need files, aka IDE, instrumentation or similar. + *

+ * The interface methods goes in favor of asmtools, and for details and help see individual implementations + */ +public interface ToolInput { + + String getName(); + + DataInputStream getDataInputStream(Optional logger) throws URISyntaxException, IOException; + + Collection readAllLines() throws IOException; + + default boolean isDetailedInput() { + return false; + } + + default ToolInput setDetailedInput(boolean value) { + return this; + } + + default MessageDigest getMessageDigest() { + return null; + } + + default int getSize() { + return 0; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ByteOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ByteOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ByteOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ByteOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2023, 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Optional; +import java.util.stream.Collectors; + +public class ByteOutput extends NamedToolOutput { + private final ArrayList outputs = new ArrayList<>(); + private ByteArrayOutputStream currentClass; + + public ArrayList getOutputs() { + return outputs; + } + + @Override + public String toString() { + return outputs.stream().map(a -> a.toString()).collect(Collectors.joining(System.lineSeparator())); + } + + @Override + public DataOutputStream getDataOutputStream() throws FileNotFoundException { + return new DataOutputStream(currentClass); + } + + + @Override + public void startClass(String fullyQualifiedName, Optional suffix, Environment logger) throws IOException { + super.startClass(fullyQualifiedName, suffix, logger); + currentClass = new ByteArrayOutputStream(1024); + } + + @Override + public void finishClass(String fullyQualifiedName) throws IOException { + String fqn = getCurrentClassName(); + if ( fqn != null && !fqn.equals(fullyQualifiedName)) { + throw new RuntimeException("Ended different class: %s then was started %s". + formatted(fullyQualifiedName, fqn)); + } + if (currentClass != null) { + outputs.add(new NamedBinary(fullyQualifiedName, currentClass.toByteArray())); + } + super.finishClass(fullyQualifiedName); + currentClass = null; + + } + + @Override + public void printlns(String line) { + try { + currentClass.write((line + System.lineSeparator()).getBytes(StandardCharsets.UTF_8)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public void prints(String line) { + try { + currentClass.write(line.getBytes(StandardCharsets.UTF_8)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public void prints(char line) { + currentClass.write(line); + } + + @Override + public void flush() { + + } + + @Override + public String getName() { + return "byte stream"; + } + + public class NamedBinary { + private final String fqn; + private final byte[] body; + + public NamedBinary(String fqn, byte[] body) { + this.fqn = fqn; + this.body = body; + } + + public String getFqn() { + return fqn; + } + + public byte[] getBody() { + return body; + } + + @Override + public String toString() { + return fqn + ": " + body.length + "b"; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/EscapedPrintStreamOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/EscapedPrintStreamOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/EscapedPrintStreamOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/EscapedPrintStreamOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs; + +import org.openjdk.asmtools.common.uEscWriter; + +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; + +public class EscapedPrintStreamOutput extends PrintWriterOutput { + + private final OutputStream originalStream; + + public EscapedPrintStreamOutput(OutputStream os) { + super(new uEscWriter(os)); + this.originalStream = os; + } + + @Override + public DataOutputStream getDataOutputStream() throws FileNotFoundException { + return new DataOutputStream(new BufferedOutputStream(originalStream)); + } + + @Override + public void finishClass(String fullyQualifiedName) throws IOException { + super.finishClass(fullyQualifiedName); + originalStream.flush(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/FSOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/FSOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/FSOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/FSOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2023, 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.*; +import java.nio.file.FileSystems; +import java.nio.file.Paths; +import java.util.Optional; + +/** + * A concrete implementation of {@link NamedToolOutput} that writes output to a file system. + * + * @author Leonid Kuskov + */ +public class FSOutput extends NamedToolOutput { + + private FSDestination destination; + private File dir; + private File file; + private FileOutputStream fos; + private PrintWriter pw; + + private static final String fileSeparator = FileSystems.getDefault().getSeparator(); + + public FSOutput() { + } + + @Override + public boolean isReady() { + return pw != null; + } + + public FSOutput setFile(File dir, String file) { + if (this.dir == null) + this.dir = dir; + destination = FSDestination.FILE; + setDestinationFileName(file); + return this; + } + + public FSOutput setDir(File dir) { + this.dir = dir; + if (destination == null) { + destination = FSDestination.DIR; + } + return this; + } + + public File getDir() { + return dir; + } + + @Override + public String toString() { + String str = super.toString(); + if (dir != null && file != null) { + str.concat(dir != null ? dir.toString() : ""). + concat(fileSeparator). + concat(file != null ? file.toString() : ""); + } + return str; + } + + @Override + public void printlns(String line) { + pw.println(line); + } + + @Override + public void prints(String line) { + pw.print(line); + } + + @Override + public void prints(char line) { + pw.print(line); + } + + /** + * Starts writing a new class file with the specified fully qualified name and optional file extension. + * + * @param fullyQualifiedName the fully qualified name of the class + * @param fileExtension the optional file extension + * @param environment the current environment + * @throws IOException if an I/O error occurs + */ + @Override + public void startClass(String fullyQualifiedName, Optional fileExtension, Environment environment) throws IOException { + super.startClass(fullyQualifiedName, fileExtension, environment); + String packageName, fileName; + int index = fullyQualifiedName.lastIndexOf(fileSeparator); + if (index != -1) { + packageName = environment.isIgnorePackage() ? "" : fullyQualifiedName.substring(0, index); + fileName = fullyQualifiedName.substring(index + 1); + } else { + packageName = ""; + fileName = fullyQualifiedName; + } + /** + * The destinationFileName is used to form the filename of the output. + * 1. File FILENAME or class file CLASSNAME takes the highest priority. This filename cannot be overridden. + * 2. Public class CLASSNAME { }– class name is CLASSNAME, and this CLASSNAME will be used to generate the filename (i.e., CLASSNAME.class). + * 3. this_class – The filename will be CLASSNAME.class, but the class name will be this_class. + * + * Also, if the -f option is used and the number of processed class files is more than 1, + * then destinationFileName will only apply to the first input file only. + * For example, if you run jdis -w . -f FILE input.class input2.class, then in the output directory, + * the files FILE.jasm and input2.jasm will be generated. + */ + String destinationFileName = this.getDestinationFileName(); + if (destinationFileName != null) { + fileName = destinationFileName + fileExtension.orElse(""); + } else { + fileName = fileName + fileExtension.orElse(""); + } + if (dir == null) { + environment.traceln("writing to %s %s".formatted(packageName, fileName)); + file = new File(packageName, fileName); + } else { + file = Paths.get(dir.getPath(), packageName, fileName).toFile(); + environment.traceln(() -> "writing -d %s = \"%s\"".formatted(dir.getPath(), file.getAbsolutePath())); + File outDir = new File(file.getParent()); + if (!outDir.exists() && !outDir.mkdirs()) { + environment.error("err.cannot.create", outDir.getPath()); + return; + } + } + fos = new FileOutputStream(file); + pw = new PrintWriter(new OutputStreamWriter(fos)); + } + + @Override + public void finishClass(String fullyQualifiedName) throws IOException { + super.finishClass(fullyQualifiedName); + flush(); + try { + if (pw != null) { + pw.close(); + } + } finally { + if (fos != null) { + fos.close(); + } + } + + } + + @Override + public void flush() { + if (fos != null) { + try { + fos.flush(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + + @Override + public DataOutputStream getDataOutputStream() throws FileNotFoundException { + return new DataOutputStream(new BufferedOutputStream(fos)); + } + + @Override + public String getName() { + return ( file !=null ) ? file.toString() : "file stream"; + } + + public enum FSDestination { + FILE, DIR; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/NamedToolOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/NamedToolOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/NamedToolOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/NamedToolOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023, 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.IOException; +import java.util.Optional; + +/** + * Historically, the output loggers for compilers had two stderrs, one to stdout and second to stderr. + * That should be removed, in favour of just dual stream tool output, printing output to stdout and log into stderr + */ +public abstract class NamedToolOutput implements ToolOutput { + + protected String fullyQualifiedName = ""; + /** + * If the output is a file, then the destinationFileName is used to form the filename of the output. + * 1. File FILENAME or class file CLASSNAME takes the highest priority. This filename cannot be overridden. + * 2. Public class CLASSNAME { }– class name is CLASSNAME, and this CLASSNAME will be used to generate the filename (i.e., CLASSNAME.class). + * 3. this_class – The filename will be CLASSNAME.class, but the class name will be this_class. + *

+ * Also, if the -f option is used and the number of processed class files is more than 1, + * then destinationFileName will only apply to the first input file only. + * For example, if you run jdis -w . -f FILE input.class input2.class, then in the output directory, + * the files FILE.jasm and input2.jasm will be generated. + */ + protected String destinationFileName = null; + private Optional suffix; + private Environment environment; + + @Override + public String getCurrentClassName() { + return fullyQualifiedName; + } + + @Override + public void startClass(String fullyQualifiedName, Optional suffix, Environment logger) throws IOException { + this.fullyQualifiedName = fullyQualifiedName; + this.suffix = suffix; + this.environment = logger; + } + + @Override + public void finishClass(String fullyQualifiedName) throws IOException { + this.destinationFileName = null; + this.fullyQualifiedName = null; + } + + public String getDestinationFileName() { + return destinationFileName; + } + + public NamedToolOutput setDestinationFileName(String destinationFileName) { + this.destinationFileName = destinationFileName; + return this; + } + + public abstract String getName(); + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/PrintWriterOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/PrintWriterOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/PrintWriterOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/PrintWriterOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023, 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs; + +import org.openjdk.asmtools.common.NotImplementedException; + +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.Writer; + +public class PrintWriterOutput extends NamedToolOutput { + + protected PrintWriter os; + + public PrintWriterOutput(OutputStream os) { + //although it is usually System.out, it is set from Environment, or custom + this.os = new PrintWriter(os, true); + } + + public PrintWriterOutput(Writer os) { + //although it is usually System.out, it is set from Environment, or custom + this.os = new PrintWriter(os, true); + } + + @Override + public void printlns(String line) { + os.println(line); + } + + @Override + public void prints(String line) { + os.print(line); + } + + @Override + public void prints(char line) { + os.print(line); + } + + @Override + public void finishClass(String fullyQualifiedName) throws IOException { + super.finishClass(fullyQualifiedName); + os.flush(); + } + + @Override + public void flush() { + os.flush(); + } + + @Override + public DataOutputStream getDataOutputStream() throws FileNotFoundException { + throw new NotImplementedException("Use EscapedPrintStreamOutput"); + } + + @Override + public String getName() { + return "text-output stream"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/StdoutOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/StdoutOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/StdoutOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/StdoutOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,9 @@ +package org.openjdk.asmtools.common.outputs; + +public class StdoutOutput extends EscapedPrintStreamOutput { + + public StdoutOutput() { + super(System.out); + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/TextOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/TextOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/TextOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/TextOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2023, 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import static java.lang.String.format; + +public class TextOutput extends NamedToolOutput { + + // decoration for text output + private BiFunction namedSourceOrnament; + + private final ArrayList outputs = new ArrayList<>(); + private StringBuilder curClsStringBuilder; + + public ArrayList getOutputs() { + return outputs; + } + + @Override + public String toString() { + return outputs.stream().map(a -> a.toString()). + collect(Collectors.joining(System.lineSeparator())); + } + + @Override + public DataOutputStream getDataOutputStream() throws FileNotFoundException { + return null; //If you are here, you probably wanted ToolOutput.ByteOutput for assembled binary output + } + + @Override + public void startClass(String fullyQualifiedName, Optional suffix, Environment logger) throws IOException { + super.startClass(fullyQualifiedName, suffix, logger); + curClsStringBuilder = new StringBuilder(); + } + + @Override + public void finishClass(String fullyQualifiedName) throws IOException { + String fqn = getCurrentClassName(); + if (fqn != null && !fqn.equals(fullyQualifiedName)) { + throw new RuntimeException("Ended with a different class: %s; then %s was started.". + formatted(fullyQualifiedName, fqn)); + } + if (curClsStringBuilder != null) { + outputs.add(new NamedSource(fullyQualifiedName, curClsStringBuilder.toString(), namedSourceOrnament)); + } + super.finishClass(fullyQualifiedName); + curClsStringBuilder = null; + } + + public TextOutput setNamedSourceOrnament(BiFunction namedSourceOrnament) { + this.namedSourceOrnament = namedSourceOrnament; + return this; + } + + @Override + public void printlns(String line) { + curClsStringBuilder.append(line).append("\n"); + } + + @Override + public void prints(String line) { + curClsStringBuilder.append(line); + } + + @Override + public void prints(char line) { + curClsStringBuilder.append(line); + } + + @Override + public void flush() { + } + + @Override + public String getName() { + return "string"; + } + + public class NamedSource { + // decoration for text output + private BiFunction ornament = (fname, body) -> + format( + """ + /** + %s + **/ + %s + /** + %s + **/ + """, fname, body, fname); + private final String fullyQualifiedName; + private final String body; + + public NamedSource(String fullyQualifiedName, String body) { + this.fullyQualifiedName = fullyQualifiedName; + this.body = body; + } + + public NamedSource(String fullyQualifiedName, String body, BiFunction ornament) { + this.fullyQualifiedName = fullyQualifiedName; + this.body = body; + this.ornament = ornament; + } + + public NamedSource setOrnament(BiFunction ornament) { + this.ornament = ornament; + return this; + } + + public String getFullyQualifiedName() { + return fullyQualifiedName; + } + + public String getBody() { + return body; + } + + @Override + public String toString() { + return ornament == null ? body : ornament.apply(fullyQualifiedName, body); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ToolOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ToolOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ToolOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/ToolOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.asmtools.common.outputs; + +import org.openjdk.asmtools.common.Environment; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +/** + * This class is a generic interface, symbolizing any output from jdis/jasm/jdec/jcoder. + * Asmtools as application internally uses DirOutput and StdoutOutput (via EscapedPrintStreamOutput). + * UnitTests for asmtools uses mainly ByteOutput for assemblers and TextOutput for disassemblers. + *

+ * Text/Byte/EscapedPrintStream outputs can be used as any 3rd part code that does not need files, aka IDE, + * instrumentation or similar. + *

+ * The interface methods go in favor of asmtools, and for details and help see individual implementations + */ +public interface ToolOutput { + + DataOutputStream getDataOutputStream() throws FileNotFoundException; + + String getCurrentClassName(); + + void startClass(String fullyQualifiedName, Optional suffix, Environment logger) throws IOException; + + void finishClass(String fullyQualifiedName) throws IOException; + + void printlns(String line); + + void prints(String line); + + void prints(char line); + + void flush(); + + public static String exToString(Throwable e) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(out, true, StandardCharsets.UTF_8)); + return new String(out.toByteArray(), StandardCharsets.UTF_8); + } + + default boolean isReady() { + return true; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualOutputStreamOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualOutputStreamOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualOutputStreamOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualOutputStreamOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs.log; + +import org.openjdk.asmtools.common.outputs.PrintWriterOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; + +public class DualOutputStreamOutput extends NamedDualStreamToolOutput { + + protected PrintWriter os; + protected PrintWriter es; + + + public DualOutputStreamOutput() { + this(System.out, System.err); + } + + //todo, remove once tests asdapts + public DualOutputStreamOutput(PrintWriter os, PrintWriter er) { + this.os = os; + this.es = er; + } + + public DualOutputStreamOutput(PrintStream os, PrintStream er) { + //although it is usually System.out, it is set from Environment, or custom + this.os = new PrintWriter(os, true); + //although it is usually System.err, it is set from Environment, or custom + this.es = new PrintWriter(er, true); + } + + @Override + public void printlns(String line) { + os.println(line); + } + + @Override + public void prints(String line) { + os.print(line); + } + + @Override + public void prints(char line) { + os.print(line); + } + + @Override + public void printlne(String line) { + es.println(line); + } + + @Override + public void printe(String line) { + es.print(line); + } + + @Override + public void printe(char line) { + es.print(line); + } + + @Override + public void finishClass(String fqn) throws IOException { + super.finishClass(fqn); + try { + os.flush(); + } finally { + es.flush(); + } + } + + @Override + public void stacktrace(Throwable ex) { + ex.printStackTrace(es); + } + + @Override + public ToolOutput getSToolObject() { + return new PrintWriterOutput(os); + } + + @Override + public ToolOutput getEToolObject() { + return new PrintWriterOutput(es); + } + + @Override + public void flush() { + this.os.flush(); + this.es.flush(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualStreamToolOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualStreamToolOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualStreamToolOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/DualStreamToolOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs.log; + +import org.openjdk.asmtools.common.NotImplementedException; +import org.openjdk.asmtools.common.outputs.ToolOutput; + +import java.io.DataOutputStream; +import java.io.FileNotFoundException; + +/** + * This is special case of output - for log and trace outputs form compilation, not for bytecode/sources themselves. + * Historically, asmtools had duals stream logger, where tracing was polluting stdout. + * This logic is by default off, but can be turned on by secret switch if needed. + * For application, although logging is still done in two streams, the log is united into stderr via StderrLog. + * + * UnitTest and 3rd party applications such as IDE or instrumentation providers s should be using unified StringLog. + * + * Once (if ever) the historical dependants on duality of log are removed, the logger should be simple and direct to a single buffer. + */ +public interface DualStreamToolOutput extends ToolOutput { + void printlne(String line); + + void printe(String line); + + void printe(char line); + + void stacktrace(Throwable ex); + + ToolOutput getSToolObject(); + + ToolOutput getEToolObject(); + + @Override + default DataOutputStream getDataOutputStream() throws FileNotFoundException { + throw new NotImplementedException("Not going to happen"); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/NamedDualStreamToolOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/NamedDualStreamToolOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/NamedDualStreamToolOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/NamedDualStreamToolOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs.log; + +import org.openjdk.asmtools.common.Environment; + +import java.io.IOException; +import java.util.Optional; + +public abstract class NamedDualStreamToolOutput implements DualStreamToolOutput { + private String fqn; + private Optional suffix; + private Environment environment; + + @Override + public String getCurrentClassName() { + return fqn; + } + + @Override + public void startClass(String fullyQualifiedName, Optional suffix, Environment logger) throws IOException { + this.fqn = fullyQualifiedName; + this.suffix = suffix; + this.environment = logger; + } + + @Override + public void finishClass(String fqn) throws IOException { + this.fqn = null; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/SingleDualOutputStreamOutput.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/SingleDualOutputStreamOutput.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/SingleDualOutputStreamOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/SingleDualOutputStreamOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs.log; + +import java.io.PrintStream; +import java.io.PrintWriter; + +public class SingleDualOutputStreamOutput extends DualOutputStreamOutput { + + public SingleDualOutputStreamOutput(PrintWriter er) { + super(er, er); + } + + public SingleDualOutputStreamOutput(PrintStream er) { + super(er, er); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StderrLog.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StderrLog.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StderrLog.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StderrLog.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs.log; + + +public class StderrLog extends SingleDualOutputStreamOutput { + + public StderrLog() { + super(System.err); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StringLog.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StringLog.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StringLog.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/outputs/log/StringLog.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.outputs.log; + +import org.openjdk.asmtools.common.outputs.ToolOutput; + +public class StringLog extends NamedDualStreamToolOutput { + + private final StringBuilder log = new StringBuilder(); + + @Override + public String toString() { + return log.toString(); + } + + @Override + public void printlns(String line) { + log.append(line).append(System.lineSeparator()); + } + + @Override + public void prints(String line) { + log.append(line); + } + + @Override + public void prints(char line) { + log.append(line); + } + + @Override + public void flush() { + + } + + @Override + public void printlne(String line) { + log.append(line).append(System.lineSeparator()); + } + + @Override + public void printe(String line) { + log.append(line); + } + + @Override + public void printe(char line) { + log.append(line); + } + + @Override + public void stacktrace(Throwable ex) { + log.append(ToolOutput.exToString(ex)); + } + + @Override + public ToolOutput getSToolObject() { + return this; + } + + @Override + public ToolOutput getEToolObject() { + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/CFVersion.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/CFVersion.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/CFVersion.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/CFVersion.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.structure; + +import static org.openjdk.asmtools.common.structure.ClassFileContext.ORDINARY; +import static org.openjdk.asmtools.common.structure.ClassFileContext.VALUE_OBJECTS; + +/* + * Class File Version + */ +public class CFVersion { + /** + * Default versions of class file + */ + public static final int DEFAULT_MAJOR_VERSION = 45; + public static final int DEFAULT_MINOR_VERSION = 3; + public static final int DEFAULT_MODULE_MAJOR_VERSION = 53; + public static final int DEFAULT_MODULE_MINOR_VERSION = 0; + public static final int UNDEFINED_VERSION = -1; + /* The version of a class file since which the compact format of stack map is necessary */ + public static final int SPLIT_VERIFIER_CFV = 50; + // Vlahalla: Value Classes and Objects + public static final int VALUE_OBJECTS_MAJOR_VERSION = 69; + public static final int VALUE_OBJECTS_MINOR_VERSION = 65535; + + private int major_version; + private int minor_version; + + private int threshold_major_version; + private int threshold_minor_version; + + private boolean frozen; + + // Whether is the CVF set as a tool parameter -cv? + private boolean isSetByParameter; + + public CFVersion() { + setVersion(UNDEFINED_VERSION, UNDEFINED_VERSION); + threshold_major_version = UNDEFINED_VERSION; + threshold_minor_version = UNDEFINED_VERSION; + EModifier.setGlobalContext(ORDINARY); + isSetByParameter = false; + frozen = false; + } + + public CFVersion(CFVersion other) { + this.setVersion(other.major_version, other.minor_version); + threshold_major_version = other.threshold_major_version; + threshold_minor_version = other.threshold_minor_version; + this.isSetByParameter = other.isSetByParameter; + if (isValueObjectContext()) { + EModifier.setGlobalContext(VALUE_OBJECTS); + } else { + EModifier.setGlobalContext(ORDINARY); + } + this.frozen = other.frozen; + } + + public CFVersion(int major_version, int minor_version) { + this.major_version = major_version; + this.minor_version = minor_version; + if (isValueObjectContext()) { + EModifier.setGlobalContext(VALUE_OBJECTS); + } else { + EModifier.setGlobalContext(ORDINARY); + } + } + + public CFVersion setFrozen(boolean frozen) { + this.frozen = frozen; + return this; + } + + public CFVersion setThreshold(int major_version, int minor_version) { + this.threshold_major_version = major_version; + this.threshold_minor_version = minor_version; + return this; + } + + public CFVersion setVersion(int major_version, int minor_version) { + this.major_version = major_version; + this.minor_version = minor_version; + if (isValueObjectContext()) { + EModifier.setGlobalContext(VALUE_OBJECTS); + } + return this; + } + + public CFVersion setFileVersion(int major_version, int minor_version) { + if (isSet() && isFrozen()) { + if (isThresholdSet()) { + if ((major_version < threshold_major_version) || + (major_version == threshold_major_version && minor_version < threshold_minor_version)) { + return this; + } + } else { + return this; + } + } + return setVersion(major_version, minor_version); + } + + + public CFVersion setMajorVersion(int major_version) { + if (!frozen) { + setVersion(major_version, this.minor_version); + } + return this; + } + + public CFVersion setMinorVersion(int minor_version) { + if (!frozen) { + setVersion(this.major_version, minor_version); + } + return this; + } + + public CFVersion setByParameter(boolean parameter) { + isSetByParameter = parameter; + return this; + } + + public boolean isSet() { + return major_version != UNDEFINED_VERSION && minor_version != UNDEFINED_VERSION; + } + + public boolean isThresholdSet() { + return threshold_major_version != UNDEFINED_VERSION && threshold_minor_version != UNDEFINED_VERSION; + } + + public boolean isSetByParameter() { + return this.isSetByParameter; + } + + public boolean isFrozen() { + return frozen; + } + + public String asString() { + return String.format("%s:%s", major_version == UNDEFINED_VERSION ? "(undef)" : major_version, + minor_version == UNDEFINED_VERSION ? "(undef)" : minor_version); + } + + public String asThresholdString() { + return String.format("%s:%s-%s:%s", + threshold_major_version == UNDEFINED_VERSION ? "(undef)" : threshold_major_version, + threshold_minor_version == UNDEFINED_VERSION ? "(undef)" : threshold_minor_version, + major_version == UNDEFINED_VERSION ? "(undef)" : major_version, + minor_version == UNDEFINED_VERSION ? "(undef)" : minor_version + ); + } + + // A class file whose version number is 50.0 or above (§4.1) must be verified using the type checking rules given + // in the section 4.10.1. Verification by Type Checking + public boolean isTypeCheckingVerifier() { + return isSet() ? major_version >= SPLIT_VERIFIER_CFV : false; + } + + public CFVersion initModuleDefaultVersion() { + if (!isSet()) { + setVersion(DEFAULT_MODULE_MAJOR_VERSION, DEFAULT_MODULE_MINOR_VERSION); + } + return this; + } + + public CFVersion initClassDefaultVersion() { + if (!isSet()) { + if (EModifier.GlobalContext() == VALUE_OBJECTS) { + setVersion(VALUE_OBJECTS_MAJOR_VERSION, VALUE_OBJECTS_MINOR_VERSION); + } else { + setVersion(DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION); + } + } + return this; + } + + public static CFVersion copyOf(CFVersion cfv) { + CFVersion cfVersion = new CFVersion(cfv); + return cfVersion; + } + + public int minor_version() { + return this.minor_version; + } + + public int major_version() { + return this.major_version; + } + + public boolean isValueObjectContext() { + return major_version > VALUE_OBJECTS_MAJOR_VERSION || + (major_version == VALUE_OBJECTS_MAJOR_VERSION && minor_version == VALUE_OBJECTS_MINOR_VERSION); + } + + public static boolean isValueObjectContext(int major_version, int minor_version) { + return major_version > VALUE_OBJECTS_MAJOR_VERSION || + (major_version == VALUE_OBJECTS_MAJOR_VERSION && minor_version == VALUE_OBJECTS_MINOR_VERSION); + } + + public static CFVersion ValueObjectsVersion() { + return new CFVersion(VALUE_OBJECTS_MAJOR_VERSION, VALUE_OBJECTS_MINOR_VERSION); + } + + /** + * Returns true if the class file version only supports Synthetic attribute and doesn't support the ACC_SYNTHETIC flag + *

+ * When jasm processes files with classfile version <= 45, it shouldn't set the ACC_SYNTHETIC bit + * but add the Synthetic attribute instead. The ACC_SYNTHETIC bit wasn't introduced until classfile version 46. + * + * @return true if only Synthetic attribute is supported, false otherwise + */ + public boolean isSyntheticAttributeContext() { + return major_version <= 45; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ClassFileContext.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ClassFileContext.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ClassFileContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ClassFileContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.structure; + +/** + * Class File context CF_Context enums + */ +public enum ClassFileContext { + + NONE(0x0000, "n/a", false), + CLASS(0x0001, "class", false), + FIELD(0x0002, "field", false), + METHOD(0x0004, "method", false), + INNER_CLASS(0x0008, "inner-class", false), + MODULE(0x0010, "module", false), + REQUIRES(0x0020, "requires", false), + EXPORTS(0x0040, "exports", false), + OPENS(0x0080, "opens", false), + METHOD_PARAMETERS(0x0100, "method parameters", false), + MODULE_DIRECTIVES(0x0020 | 0x0040 | 0x0080, "module directives", false), + ORDINARY(0x0200, "ordinary", true), + VALUE_OBJECTS(0x0200, "value classes and objects", true); + + private final int id; + private final String printVal; + private final boolean globalContext; + + ClassFileContext(int id, String print, boolean globalContext) { + this.id = id; + this.printVal = print; + this.globalContext = globalContext; + } + + public int getID() { + return id; + } + + public String getName() { + return printVal; + } + + public boolean isGlobal() { + return globalContext; + } + + public boolean isOneOf(ClassFileContext... contexts) { + for (ClassFileContext cfc : contexts) { + if ((cfc.id & this.id) != 0) { + return true; + } + } + return false; + } + + public boolean belongToContextOf(EModifier modifier) { + return (this.id & modifier.getAllovedContextMask()) != 0; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EAttribute.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EAttribute.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EAttribute.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EAttribute.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.structure; + +import org.openjdk.asmtools.jasm.ClassFileConst; + +import java.util.HashMap; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.*; + +/** + * 4.7. Attributes + */ +public enum EAttribute { + + // Constant for JVMS + ATT_Unrecognized(-1, "ATT_Unrecognized", "", CONSTANT_UNKNOWN), + ATT_StackMap(1, "ATT_StackMap", "StackMap", CONSTANT_UNKNOWN), + // Numbers correspond to VM spec (chapter 4.7.X) + ATT_ConstantValue(2, "ATT_ConstantValue", "ConstantValue", CONSTANT_UTF8), + ATT_Code(3, "ATT_Code", "Code", CONSTANT_UNKNOWN), + ATT_StackMapTable(4, "ATT_StackMapTable", "StackMapTable", CONSTANT_UNKNOWN), + ATT_Exceptions(5, "ATT_Exceptions", "Exceptions", CONSTANT_UNKNOWN), + ATT_InnerClasses(6, "ATT_InnerClasses", "InnerClasses", CONSTANT_CLASS), + ATT_EnclosingMethod(7, "ATT_EnclosingMethod", "EnclosingMethod", CONSTANT_CLASS), + ATT_Synthetic(8, "ATT_Synthetic", "Synthetic", CONSTANT_UNKNOWN), + ATT_Signature(9, "ATT_Signature", "Signature", CONSTANT_UTF8), + ATT_SourceFile(10, "ATT_SourceFile", "SourceFile", CONSTANT_UTF8), + ATT_SourceDebugExtension(11, "ATT_SourceDebugExtension", "SourceDebugExtension", CONSTANT_UTF8), + ATT_LineNumberTable(12, "ATT_LineNumberTable", "LineNumberTable", CONSTANT_UNKNOWN), + ATT_LocalVariableTable(13, "ATT_LocalVariableTable", "LocalVariableTable", CONSTANT_UNKNOWN), + ATT_LocalVariableTypeTable(14, "ATT_LocalVariableTypeTable", "LocalVariableTypeTable", CONSTANT_UNKNOWN), + ATT_Deprecated(15, "ATT_Deprecated", "Deprecated", CONSTANT_UNKNOWN), + ATT_RuntimeVisibleAnnotations(16, "ATT_RuntimeVisibleAnnotations", "RuntimeVisibleAnnotations", CONSTANT_UNKNOWN), + ATT_RuntimeInvisibleAnnotations(17, "ATT_RuntimeInvisibleAnnotations", "RuntimeInvisibleAnnotations", CONSTANT_UNKNOWN), + ATT_RuntimeVisibleParameterAnnotations(18, "ATT_RuntimeVisibleParameterAnnotations", "RuntimeVisibleParameterAnnotations", CONSTANT_UNKNOWN), + ATT_RuntimeInvisibleParameterAnnotations(19, "ATT_RuntimeInvisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", CONSTANT_UNKNOWN), + ATT_AnnotationDefault(20, "ATT_AnnotationDefault", "AnnotationDefault", CONSTANT_UNKNOWN), + ATT_BootstrapMethods(21, "ATT_BootstrapMethods", "BootstrapMethods", CONSTANT_METHODHANDLE), + ATT_RuntimeVisibleTypeAnnotations(22, "ATT_RuntimeVisibleTypeAnnotations", "RuntimeVisibleTypeAnnotations", CONSTANT_UNKNOWN), + ATT_RuntimeInvisibleTypeAnnotations(23, "ATT_RuntimeInvisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations", CONSTANT_UNKNOWN), + ATT_MethodParameters(24, "ATT_MethodParameters", "MethodParameters", CONSTANT_UTF8), + ATT_Module(25, "ATT_Module", "Module", CONSTANT_MODULE), + ATT_Version(26, "ATT_Version", "Version", CONSTANT_UTF8), + ATT_TargetPlatform(27, "ATT_TargetPlatform", "TargetPlatform", CONSTANT_UTF8), + ATT_MainClass(28, "ATT_MainClass", "MainClass", CONSTANT_CLASS), + ATT_ModulePackages(29, "ATT_ModulePackages", "ModulePackages", CONSTANT_PACKAGE), + ATT_ModuleMainClass(30, "ATT_ModuleMainClass", "ModuleMainClass", CONSTANT_CLASS), + // ATT_ModuleTarget(31, "ATT_ModuleTarget", "ModuleTarget", CONSTANT_UNKNOWN), + // JEP 181: class file 55.0 + ATT_NestHost(32, "ATT_NestHost", "NestHost", CONSTANT_CLASS), + ATT_NestMembers(33, "ATT_NestMembers", "NestMembers", CONSTANT_CLASS), + // JEP 359 Record(Preview): class file 58.65535 + // Record_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 components_count; + // component_info components[components_count]; + // } + ATT_Record(34, "ATT_Record", "Record", CONSTANT_UTF8), + // JEP 360 (Sealed types): class file 59.65535 + // PermittedSubclasses_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 number_of_classes; + // u2 classes[number_of_classes]; + // } + ATT_PermittedSubclasses(35, "ATT_PermittedSubclasses", "PermittedSubclasses", CONSTANT_CLASS), + // Valhalla + ATT_LoadableDescriptors(36, "ATT_LoadableDescriptors", "LoadableDescriptors", CONSTANT_CLASS); + + private final Integer value; + private final String printVal; + private final String parseKey; + private final ClassFileConst.ConstType constType; + private static HashMap parseKeyToTags; + private static HashMap valueToTags; + + EAttribute(Integer value, String printValue, String parseKey, ClassFileConst.ConstType constType) { + this.value = value; + this.printVal = printValue; + this.parseKey = parseKey; + this.constType = constType; + } + + public boolean isOneOf(EAttribute... attributes) { + for (EAttribute attribute : attributes) { + if (attribute == this) { + return true; + } + } + return false; + } + + public String printValue() { + return printVal; + } + + public String parseKey() { + return parseKey; + } + + public ClassFileConst.ConstType getCPTypeOfIndex() { + return constType; + } + + public int value() { + return value; + } + + public static EAttribute get(int value) { + if (valueToTags == null) { + valueToTags = (HashMap) Stream. + of(EAttribute.values()). + collect(Collectors.toMap(EAttribute::value, Function.identity())); + } + EAttribute tg = valueToTags.get(value); + if (tg == null) { + tg = EAttribute.ATT_Unrecognized; + } + return tg; + } + + public static EAttribute get(String parseKey) { + if (parseKeyToTags == null) { + parseKeyToTags = (HashMap) Stream. + of(EAttribute.values()). + collect(Collectors.toMap(EAttribute::parseKey, Function.identity())); + } + EAttribute tg = parseKeyToTags.get(parseKey); + if (tg == null) { + tg = EAttribute.ATT_Unrecognized; + } + return tg; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ELocation.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ELocation.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ELocation.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/ELocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.structure; + +/** + * Attribute location + * Table 4.7-C. Predefined class file attributes (by location) + */ +public enum ELocation { + unknown("Unknown"), + class_file("ClassFile"), + field_info("field_info"), + method_info("method_info"), + record_component_info("record_component_info"), + code_atribute("Code"); + + public String getDescription() { + return description; + } + + private final String description; + + ELocation(String description) { + this.description = description; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EModifier.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EModifier.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EModifier.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/EModifier.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.structure; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.openjdk.asmtools.common.structure.ClassFileContext.*; + +/** + * 4. The class File Format + *

+ * The enum contains all JVMS (class, field, method, nested class, module and module statements) accesses and modifiers + * taken from tables 4.1-A, 4.1-B, 4.5-A, 4.6-A, 4.7.6-A, 4.7.25 etc according to their context @see EClassFileContext + */ +public enum EModifier { + + ACC_NONE(0x0000, "", NONE), // <> + ACC_PUBLIC(0x0001, "public", CLASS, INNER_CLASS, FIELD, METHOD), + ACC_PRIVATE(0x0002, "private", INNER_CLASS, FIELD, METHOD), + ACC_PROTECTED(0x0004, "protected", INNER_CLASS, FIELD, METHOD), + ACC_STATIC(0x0008, "static", INNER_CLASS, FIELD, METHOD), + + ACC_FINAL(0x0010, "final", CLASS, INNER_CLASS, FIELD, METHOD, METHOD_PARAMETERS), + + ACC_SUPER(0x0020, "super", CLASS), + ACC_IDENTITY(0x0020, "identity", CLASS, INNER_CLASS, VALUE_OBJECTS), // Value Classes and Objects + ACC_VALUE(0x0000, "value", CLASS, INNER_CLASS, VALUE_OBJECTS), // Value Classes and Objects + + ACC_TRANSITIVE(0x0020, "transitive", REQUIRES), + ACC_SYNCHRONIZED(0x0020, "synchronized", METHOD), + ACC_OPEN(0x0020, "open", MODULE), + + ACC_VOLATILE(0x0040, "volatile", FIELD), + ACC_BRIDGE(0x0040, "bridge", METHOD), + ACC_STATIC_PHASE(0x0040, "static", REQUIRES), + + ACC_TRANSIENT(0x0080, "transient", FIELD), + ACC_VARARGS(0x0080, "varargs", METHOD), + + ACC_NATIVE(0x0100, "native", METHOD), + + ACC_INTERFACE(0x0200, "interface", CLASS, INNER_CLASS), + + ACC_ABSTRACT(0x0400, "abstract", CLASS, INNER_CLASS, METHOD), + + ACC_STRICT(0x0800, "strict", METHOD, FIELD, VALUE_OBJECTS), // FIELD added for VALUE_OBJECTS CONTEXT + + ACC_SYNTHETIC(0x1000, "synthetic", CLASS, INNER_CLASS, FIELD, METHOD, MODULE, REQUIRES, EXPORTS, OPENS, METHOD_PARAMETERS), + + ACC_ANNOTATION(0x2000, "annotation", CLASS, INNER_CLASS), + + ACC_ENUM(0x4000, "enum", CLASS, INNER_CLASS, FIELD), + + ACC_MODULE(0x8000, "module", CLASS), + ACC_MANDATED(0x8000, "mandated", MODULE, REQUIRES, EXPORTS, OPENS, METHOD_PARAMETERS), + + SYNTHETIC_ATTRIBUTE(0x00010000, "Synthetic(Pseudo)", CLASS, INNER_CLASS, FIELD, METHOD), + DEPRECATED_ATTRIBUTE(0x00020000, "Deprecated(Pseudo)", CLASS, INNER_CLASS, FIELD, METHOD), + + VALUE_OBJECTS_ATTRIBUTE(0x010000000, "ValueObjects(Pseudo)", CLASS, INNER_CLASS, FIELD); + + // Method access and property flags (Table 4.6-A) + public static final EModifier[] MM_METHOD = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, + ACC_SYNCHRONIZED, ACC_BRIDGE, ACC_VARARGS, ACC_NATIVE, ACC_ABSTRACT, + ACC_SYNTHETIC, + ACC_STRICT }; // Valhalla SPECIFIC + // Class access and property modifiers (Table 4.1-A) + public static final EModifier[] MM_CLASS = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_FINAL, + ACC_SUPER, ACC_IDENTITY, ACC_INTERFACE, + ACC_ABSTRACT, ACC_SYNTHETIC, + ACC_ANNOTATION, ACC_ENUM, ACC_MODULE}; + + // Valid interface flags. + public static final EModifier[] MM_INTERFACE = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, + ACC_INTERFACE, + ACC_ABSTRACT, ACC_SYNTHETIC, ACC_ANNOTATION}; + // Field access and property flags (Table 4.5-A) + public static final EModifier[] MM_FIELD = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, + ACC_STATIC, ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT, + ACC_SYNTHETIC, ACC_ENUM, + ACC_STRICT}; // Valhalla SPECIFIC + // Abstract method + public static final EModifier[] MM_ABSTRACT_METHOD = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, + ACC_BRIDGE, ACC_VARARGS, ACC_ABSTRACT, + ACC_SYNTHETIC}; + // , method + public static final EModifier[] MM_INIT_METHOD = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, + ACC_VARARGS, ACC_SYNTHETIC, + ACC_STRICT, ACC_STATIC}; + // Nested class access and property flags (Table 4.7.6-A) + public static final EModifier[] MM_NESTED_CLASS = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, + ACC_STATIC, ACC_FINAL, + ACC_INTERFACE, ACC_ABSTRACT, ACC_SYNTHETIC, ACC_ANNOTATION, ACC_ENUM}; + // Interface method + private static final EModifier[] MM_INTERFACE_METHOD = {ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, + ACC_STATIC, ACC_BRIDGE, ACC_VARARGS, + ACC_ABSTRACT, ACC_STRICT, ACC_SYNTHETIC}; + private static final EModifier[] MM_MODULE = {ACC_OPEN, ACC_SYNTHETIC, ACC_MANDATED}; + private static final EModifier[] MM_MODULE_REQUIRES = {ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC, ACC_MANDATED}; + private static final EModifier[] MM_MODULE_EXPORTS = {ACC_SYNTHETIC, ACC_MANDATED}; + private static final EModifier[] MM_MODULE_OPENS = {ACC_SYNTHETIC, ACC_MANDATED}; + // ToString converters + public static String NAMES_DELIMITER = ", "; + public static String NAMES_SUFFIX = ""; + public static String KEYWORDS_DELIMITER = " "; + public static String KEYWORDS_SUFFIX = " "; + private final int flag; + private final String keyword; + private final Set contexts; + private int contextMask = 0; + + // Externally changed switchers + private static ClassFileContext globalContext = ORDINARY; + + EModifier(int flag, String keyword, ClassFileContext... contexts) { + this.flag = flag; + this.keyword = keyword; + this.contexts = new HashSet<>(10); + if (contexts != null) { + for (ClassFileContext c : contexts) { + this.contexts.add(c); + contextMask |= c.getID(); + } + } + } + + public static void setGlobalContext(ClassFileContext globalContext) { + EModifier.globalContext = globalContext; + } + + public static ClassFileContext GlobalContext() { + return EModifier.globalContext; + } + + // Wrappers + public static boolean isPublic(int flags) { + return (flags & ACC_PUBLIC.flag) != 0; + } + + public static boolean isPrivate(int flags) { + return (flags & ACC_PRIVATE.flag) != 0; + } + + public static boolean isProtected(int flags) { + return (flags & ACC_PROTECTED.flag) != 0; + } + + public static boolean isStatic(int flags) { + return (flags & ACC_STATIC.flag) != 0; + } + + public static boolean isFinal(int flags) { + return (flags & ACC_FINAL.flag) != 0; + } + + public static boolean isTransitive(int flags) { + return isFinal(flags); + } + + public static boolean isSuper(int flags) { + return (flags & ACC_SUPER.flag) != 0; + } + + public static boolean isSynchronized(int flags) { + return isSuper(flags); + } + + public static boolean isVolatile(int flags) { + return (flags & ACC_VOLATILE.flag) != 0; + } + + public static boolean isBridge(int flags) { + return isVolatile(flags); + } + + public static boolean isStaticPhase(int flags) { + return isVolatile(flags); + } + + public static boolean isTransient(int flags) { + return (flags & ACC_TRANSIENT.flag) != 0; + } + + public static boolean isVarArgs(int flags) { + return isTransient(flags); + } + + public static boolean isNative(int flags) { + return (flags & ACC_NATIVE.flag) != 0; + } + + public static boolean isInterface(int flags) { + return (flags & ACC_INTERFACE.flag) != 0; + } + + public static boolean isAbstract(int flags) { + return (flags & ACC_ABSTRACT.flag) != 0; + } + + public static boolean isStrict(int flags) { + return (flags & ACC_STRICT.flag) != 0; + } + + public static int getNotPermitted(int flags, EModifier[] set) { + int notPermitted = 0; + for (EModifier mod : set) { + if ((flags & mod.flag) != 0) { + flags &= ~mod.flag; + ClassFileContext context = mod.getGlobalContext(); + if( globalContext != context && context != ORDINARY) { + notPermitted |= mod.flag; + } + } + } + notPermitted |= flags; + return notPermitted; + } + + public ClassFileContext getGlobalContext() { + for (ClassFileContext c : contexts) { + if (c.isGlobal()) { + return c; + } + } + return ORDINARY; + } + + + public static boolean isSynthetic(int flags) { + return (flags & ACC_SYNTHETIC.flag) != 0; + } + + public static boolean isAnnotation(int flags) { + return (flags & ACC_ANNOTATION.flag) != 0; + } + + public static boolean isEnum(int flags) { + return (flags & ACC_ENUM.flag) != 0; + } + + public static boolean isModule(int flags) { + return (flags & ACC_MODULE.flag) != 0; + } + + public static boolean isMandated(int flags) { + return isModule(flags); + } + + public static boolean isSyntheticPseudoMod(int flags) { + return (flags & SYNTHETIC_ATTRIBUTE.flag) != 0; + } + + public static boolean isDeprecatedPseudoMod(int flags) { + return (flags & DEPRECATED_ATTRIBUTE.flag) != 0; + } + + // Value Classes and Objects + public static boolean isValueObjects(int flags) { + return (flags & VALUE_OBJECTS_ATTRIBUTE.flag) != 0; + } + + public static boolean isIdentity(int flags) { + return (flags & ACC_IDENTITY.flag) != 0; + } + + public static boolean hasPseudoMod(int flags) { + return isSyntheticPseudoMod(flags) || isDeprecatedPseudoMod(flags); + } + + /* + * Check that only one flag is set + */ + public static boolean onlyOneOfFlags(int flag, EModifier... modifiers) { + if (modifiers.length >= 2) { + final int mask = flag & getFlags(modifiers); + return Arrays.stream(modifiers).mapToInt(EModifier::getFlag).anyMatch(f -> (f | mask) == f); + } + return modifiers.length != 0 && flag == modifiers[0].getFlag(); + } + + /* + * Check that at least one flag is set + */ + public static boolean anyOf(int flag, EModifier... modifiers) { + if (modifiers.length > 0) { + return (flag & getFlags(modifiers)) != 0; + } + return false; + } + + public static int cleanFlags(int flag, EModifier... modifiers) { + if (modifiers.length > 0) { + for (EModifier m : modifiers) { + flag &= ~m.flag; + } + } + return flag; + } + + /* + * Are both flags set? + */ + public static boolean both(int flags, EModifier modifierA, EModifier modifierB) { + final int bothFlags = modifierA.getFlag() | modifierB.getFlag(); + return (flags & bothFlags) == bothFlags; + } + + /* + * Is more than one flag set in the list? + */ + public static boolean moreThanOne(int flags, EModifier... modifiers) { + int count = 0; + for (EModifier m : modifiers) { + if( (flags & m.flag) != 0) { + count++; + } + } + return count > 1; + } + + /* + * Check that there are no other modifiers in flags except given. + */ + public static boolean noFlagsExcept(int flags, EModifier... modifiers) { + return (flags & getFlags(modifiers)) == flags; + } + + public static int getFlags(EModifier... modifiers) { + int flag = 0; + if (modifiers.length > 0) { + for (EModifier m : modifiers) { + flag |= m.flag; + } + } + return flag; + } + + public static int getFlags(ClassFileContext context, EModifier... modifiers) { + int flag = 0; + if (modifiers.length == 0) { + modifiers = EModifier.values(); + } + for (EModifier m : modifiers) { + if (m.contexts.contains(context)) { + flag |= m.flag; + } + } + return flag; + } + + private static int addTo(ArrayList list, int flags, boolean isName, EModifier modifier) { + list.add(isName ? modifier.getFlagName() : modifier.getJavaFlagModifier()); + return clearIfSet(flags, modifier); + } + + public static String asKeywords(int modifiers, ClassFileContext context) { + return flagsToString(modifiers, false, context, KEYWORDS_DELIMITER, KEYWORDS_SUFFIX); + } + + public static String asNames(int modifiers, ClassFileContext context) { + return flagsToString(modifiers, true, context, NAMES_DELIMITER, NAMES_SUFFIX); + } + + private static String flagsToString(int modifiers, boolean isName, ClassFileContext context, String delimiter, String suffix) { + String s = String.join(delimiter, flagsToList(modifiers, isName, context)); + return s.isBlank() ? "" : s + suffix; + } + + /** + * Get either a keyword or a name of a flags according to the context. + * + * @param flags the flags to choose the corresponding names or keywords. + * @param isName either the JVMS modifier names or JLS keywords are selected + * @param context the entity for which the names/keywords are selected + * @return the List of the names or the keywords according to the parameter isName + */ + private static ArrayList flagsToList(int flags, boolean isName, ClassFileContext context) { + ArrayList list = new ArrayList<>(); + // run through all access flags + if (isPublic(flags) && context.belongToContextOf(ACC_PUBLIC)) { + flags = addTo(list, flags, isName, ACC_PUBLIC); + } + if (isPrivate(flags) && context.belongToContextOf(ACC_PRIVATE)) { + flags = addTo(list, flags, isName, ACC_PRIVATE); + } + if (isProtected(flags) && context.belongToContextOf(ACC_PROTECTED)) { + flags = addTo(list, flags, isName, ACC_PROTECTED); + } + // ACC_STATIC + if (isStatic(flags) && context.belongToContextOf(ACC_STATIC)) { + // Static CLASS doesn't exist. Only INNER_CLASS, FIELD, METHOD can have this modifier. + flags = addTo(list, flags, isName, ACC_STATIC); + } + // ACC_FINAL + if (isFinal(flags) && context.isOneOf(CLASS, INNER_CLASS, FIELD, METHOD, METHOD_PARAMETERS)) { + flags = addTo(list, flags, isName, ACC_FINAL); + } + // ACC_TRANSITIVE ACC_SUPER ACC_SYNCHRONIZED ACC_OPEN + if (isSuper(flags)) { // == isTransitive(flags) == isSynchronized(flags) == isOpen(flags) + switch (context) { + case CLASS -> { + // In Java SE 8, the ACC_SUPER semantics became mandatory, + // regardless of the setting of ACC_SUPER or the class file version number, + // and the flags no longer had any effect. + // still we have to keep it in here (if it was here), as if the new class is used for hotswap, it s absence would casue + // java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the class modifiers + flags = addTo(list, flags, isName, (globalContext == VALUE_OBJECTS) ? ACC_IDENTITY : ACC_SUPER); + } + case INNER_CLASS -> { + if(globalContext == VALUE_OBJECTS) { + flags = addTo(list, flags, isName, ACC_IDENTITY); + } + } + case REQUIRES -> flags = addTo(list, flags, isName, ACC_TRANSITIVE); + case METHOD -> flags = addTo(list, flags, isName, ACC_SYNCHRONIZED); + case MODULE -> flags = addTo(list, flags, isName, ACC_OPEN); + } + } + // ACC_VOLATILE ACC_BRIDGE ACC_STATIC_PHASE ACC_PERMITS_VALUE + if (isVolatile(flags)) { // == isBridge(flags) ==isStaticPhase(flags) == isPermitsValue(flags) + switch (context) { + case FIELD -> flags = addTo(list, flags, isName, ACC_VOLATILE); + case METHOD -> flags = addTo(list, flags, isName, ACC_BRIDGE); + case REQUIRES -> flags = addTo(list, flags, isName, ACC_STATIC_PHASE); + } + } + // ACC_TRANSIENT ACC_VARARGS + if (isTransient(flags)) { // == isVarArgs(flags) + switch (context) { + case FIELD -> flags = addTo(list, flags, isName, ACC_TRANSIENT); + case METHOD -> flags = addTo(list, flags, isName, ACC_VARARGS); + } + } + // ACC_NATIVE ACC_VALUE + if (isNative(flags)) { // == isValue(flags) + switch (context) { + case METHOD -> flags = addTo(list, flags, isName, ACC_NATIVE); + } + } + // ACC_INTERFACE + if (isInterface(flags) && context.isOneOf(CLASS, INNER_CLASS)) { + if (isName) { + flags = addTo(list, flags, true, ACC_INTERFACE); + } else { + flags = clearIfSet(flags, ACC_INTERFACE); + } + } + // ACC_ABSTRACT + if (isAbstract(flags) && context.isOneOf(CLASS, INNER_CLASS, METHOD)) { + flags = addTo(list, flags, isName, ACC_ABSTRACT); + } + + // ACC_STRICT + if (isStrict(flags)) { + switch (context) { + case METHOD -> flags = addTo(list, flags, isName, ACC_STRICT); + case FIELD -> { + if (globalContext == VALUE_OBJECTS) { + flags = addTo(list, flags, isName, ACC_STRICT); + } + } + } + } + // ACC_SYNTHETIC + if (isSynthetic(flags) && context.belongToContextOf(ACC_SYNTHETIC)) { + flags = addTo(list, flags, isName, ACC_SYNTHETIC); + } + // ACC_ANNOTATION + if (isAnnotation(flags) && context.isOneOf(CLASS, INNER_CLASS)) { + flags = addTo(list, flags, isName, ACC_ANNOTATION); + } + // ACC_ENUM + if (isEnum(flags) && context.isOneOf(CLASS, INNER_CLASS, FIELD)) { + flags = addTo(list, flags, isName, ACC_ENUM); + } + // ACC_MODULE ACC_MANDATED + if (isModule(flags)) { // == isMandated(flags) + if (context == CLASS) { + if (isName) { + flags = addTo(list, flags, true, ACC_MODULE); + } else { + flags = clearIfSet(flags, ACC_MODULE); + } + } else if (context.isOneOf(MODULE, REQUIRES, EXPORTS, OPENS, METHOD_PARAMETERS)) { + flags = addTo(list, flags, isName, ACC_MANDATED); + } + } + if (flags != 0) { + list.add(String.format("0x%04X", flags)); + } + return list; + } + + private static int clearIfSet(int flag, EModifier... modifiers) { + for (EModifier m : modifiers) { + if ((flag & m.flag) != 0) { + flag &= ~m.flag; + } + } + return flag; + } + + public Set getClassFileContext() { + return contexts; + } + + public int getAllovedContextMask() { + return contextMask; + } + + public int getFlag() { + return flag; + } + + public String getJavaFlagModifier() { + return keyword; + } + + public String getFlagName() { + return this.toString(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/StackMap.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/StackMap.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/StackMap.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/structure/StackMap.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common.structure; + +import org.openjdk.asmtools.asmutils.FormatConsumer; +import org.openjdk.asmtools.asmutils.Range; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 4.7.4. The StackMapTable Attribute + */ +public class StackMap { + + /** + * @param verificationTypeID u1 tag + * @param errorConsumer consumer to announce a problem + * @return associated StackMap Verification Type + */ + public static VerificationType getVerificationType(int verificationTypeID, Optional> errorConsumer) { + if (VerificationType.isValidVerificationType(verificationTypeID)) { + return VerificationType.get(verificationTypeID); + } else { + errorConsumer.ifPresent(c -> c.format("error.stackmap.unknown.type", verificationTypeID)); + return VerificationType.ITEM_UNKNOWN; + } + } + + public static VerificationType getVerificationType(String printName) { + return VerificationType.getByPrintName(printName); + } + + /** + * Get Entry Type by tag belonging the range + * + * @param tag u1 tag in range + * @return + */ + public static EntryType stackMapEntryType(int tag) { + EntryType entryType; + entryType = EntryType.getByTag(tag); + return entryType; + } + + /** + * Get frame type id by a name + * + * @param frameTypeName frame type name + * @return Stack FrameType tag [0..255] + */ + public static int getFrameTypeTagByName(String frameTypeName) { + return EntryType.getByTagName(frameTypeName).fromTag(); + } + + /** + * Get entry type id by a name + * + * @param entryTypeName entry type name + * @return Stack FrameType tag [0..255] + */ + public static EntryType getEntryTypeByName(String entryTypeName) { + return EntryType.getByTagName(entryTypeName); + } + + /** + * Checks if the tag belongs to range of valid Frame Types + * + * @param tag + * @return true if the tag does not belong to a range either of UNKNOWN_TYPE or RESERVED + */ + public static boolean isValidEntryType(int tag) { + return EntryType.isValid(tag); + } + + /** + * MapTypes table. These constants are used in stackmap pseudo-instructions only. + */ + public enum VerificationType { + /* Type codes for StackMap attribute */ + ITEM_UNKNOWN(-1, "??? Unknown verification type", "UNKNOWN"), // placeholder for wrong types + ITEM_Bogus(0, "bogus", "B"), // an unknown or uninitialized value + ITEM_Integer(1, "int", "I"), // a 32-bit integer + ITEM_Float(2, "float", "F"), // not used + ITEM_Double(3, "double", "D"), // not used + ITEM_Long(4, "long", "L"), // a 64-bit integer + ITEM_Null(5, "null", "N"), // the type of null + ITEM_InitObject(6, "this", "IO"), // "this" in constructor + ITEM_Object(7, "CP", "O"), // followed by 2-byte index of class name + ITEM_NewObject(8, "at", "NO"); // followed by 2-byte ref to "new" + + private static HashMap printNameToType; + private static HashMap parseKeyToType; + private static HashMap tagToType; + private final String printName; + private final String parseKey; + private Integer tag; + + VerificationType(Integer tag, String printName, String parseKey) { + this.tag = tag; + this.printName = printName; + this.parseKey = parseKey; + } + + static boolean isValidVerificationType(int tag) { + return tag >= ITEM_Bogus.tag && tag <= ITEM_NewObject.tag; + } + + public static VerificationType getByPrintName(String printName) { + if (printNameToType == null) { + printNameToType = (HashMap) Arrays.stream(VerificationType.values()). + collect(Collectors.toMap(VerificationType::printName, Function.identity())); + } + return printNameToType.get(printName); + } + + public static VerificationType getByParseKey(String parseKey) { + if (parseKeyToType == null) { + parseKeyToType = (HashMap) Arrays.stream(VerificationType.values()). + collect(Collectors.toMap(VerificationType::parseKey, Function.identity())); + } + VerificationType verificationType = parseKeyToType.get(parseKey); + return verificationType == null ? VerificationType.ITEM_UNKNOWN : verificationType; + } + + public static VerificationType get(int tag) { + if (tagToType == null) { + tagToType = (HashMap) Arrays.stream(VerificationType.values()). + collect(Collectors.toMap(VerificationType::tag, Function.identity())); + } + return tagToType.get(tag); + } + + public String parseKey() { + return this.parseKey; + } + + public String printName() { + return this.printName; + } + + public Integer tag() { + return this.tag; + } + } + + /** + * StackMap-FrameType table. These constants are used in stackmap pseudo-instructions + * only. + */ + public enum EntryType { + UNKNOWN_TYPE(-1, -1, "unknown", false, false, false), // placeholder for wrong frame types + /* Type codes for StackMapFrame attribute */ + SAME_FRAME(0, 63, "same", false, false, false), + SAME_LOCALS_1_STACK_ITEM_FRAME(64, 127, "stack1", false, true, false), + RESERVED(128, 245, "reserved", false, false, false), + EARLY_LARVAL(246, 246, "early_larval", false, false, true), + SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED(247, 247, "stack1_ex", false, true, false), + CHOP_1_FRAME(250, 250, "chop1", false, false, false), + CHOP_2_FRAME(249, 249, "chop2", false, false, false), + CHOP_3_FRAME(248, 248, "chop3", false, false, false), + SAME_FRAME_EXTENDED(251, 251, "same_ex", false, false, false), + APPEND_FRAME(252, 254, "append", true, false, false), + FULL_FRAME(255, 255, "full", true, true, false); + + private static HashMap tagNameToFrameType; + private final Range tagRange; + private final String tagName; + private final boolean localMap; + private final boolean stackMap; + private final boolean fields; + + EntryType(int from, int to, String tagName, boolean localMap, boolean stackMap, boolean fields) { + this.tagRange = new Range<>(from, to); + this.tagName = tagName; + this.localMap = localMap; + this.stackMap = stackMap; + this.fields = fields; + } + + public boolean hasLocalMap() { + return localMap; + } + + public boolean hasStackMap() { + return stackMap; + } + + public boolean hasFields() { + return fields; + } + + public static EntryType getByTagName(String tagName) { + if (tagNameToFrameType == null) { + tagNameToFrameType = (HashMap) Arrays.stream(EntryType.values()). + collect(Collectors.toMap(EntryType::tagName, Function.identity())); + } + EntryType type = tagNameToFrameType.get(tagName); + return type == null ? EntryType.UNKNOWN_TYPE : type; + } + + public static EntryType getByTag(int tag) { + for (EntryType type : EntryType.values()) { + if (type.inRange(tag)) { + return type; + } + } + return EntryType.UNKNOWN_TYPE; + } + + public int fromTag() { + return tagRange.from(); + } + + public String tagName() { + return tagName; + } + + public String printName() { + String buf = this.name().toLowerCase().replace("_frame", ""); + return buf.startsWith("chop") ? tagName : buf; + } + + public boolean inRange(int tag) { + return tagRange.in(tag); + } + + /** + * Checks if the tag belongs to range of valid Frame Types + * + * @param tag + * @return true if the tag does not belong to a range either of UNKNOWN_TYPE or RESERVED + */ + public static boolean isValid(int tag) { + for (EntryType entryType : Set.of(UNKNOWN_TYPE, RESERVED)) { + if (entryType.inRange(tag)) + return false; + } + return true; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/uEscWriter.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/uEscWriter.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/common/uEscWriter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/common/uEscWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.charset.StandardCharsets; + +public class uEscWriter extends Writer { + + static final char[] hexTable = "0123456789ABCDEF".toCharArray(); + OutputStream out; + byte[] tmpl; + + public uEscWriter(OutputStream out) { + this.out = out; + tmpl = new byte[6]; + tmpl[0] = (byte) '\\'; + tmpl[1] = (byte) 'u'; + } + + + @Override + public synchronized void write(char[] cc, int ofs, int len) throws IOException { + byte[] b = String.copyValueOf(cc, ofs, len).getBytes(StandardCharsets.UTF_8); + out.write(b, ofs, b.length); + } + + @Override + public void flush() { + } + + @Override + public void close() { + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/i18n.properties jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/i18n.properties --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/i18n.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/i18n.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +main.usage=\ +Usage: java -jar {0} run jasm, jdis, jcoder, or jdec tool\n\ +\ or: java -jar {0} -?|-h|-help print Help (this message) and exit\n\ +\ or: java -jar {0} -version print version information and exit\n\ +use -dls switch to return the ancient dual stream logging\n + +main.error.no_arguments=No arguments provided! See options above. +main.error.unknown_tool=Tool name \"{0}\" unrecognized. See the usage above for possible tool choices. + +# shared strings +err.does_not_exist=The output directory \"{0}\" does not exist +err.d_requires_argument=-d requires argument +err.f_requires_argument=-f requires argument +info.opt.d=\ +\ -d Specify where to place generated class files, otherwise +info.opt.w=\ +\ -w Specify where to place generated class files, without considering the classpath, otherwise +info.opt.v=\ +\ -v Print additional information +info.opt.t=\ +\ -t Print debug, trace information +info.opt.version=\ +\ -version Print the program version + +main.error.wrong.utf8=The bytes do not represent a valid modified UTF-8 encoding of a Unicode string. +main.error.wrong.bytes=Corrupted class file. The bytes do not represent a valid class attribute. +error.stackmap.unknown.type=Unknown StackMapTable verification type {0} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AnnotationData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AnnotationData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AnnotationData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AnnotationData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.stream.IntStream; + +/** + * JVMS 4.7.16. + * + * annotation { + * u2 type_index; + * u2 num_element_value_pairs; + * { u2 element_name_index; + * element_value value; + * } element_value_pairs[num_element_value_pairs]; + * } + */ +class AnnotationData implements ConstantPoolDataVisitor { + + boolean invisible; + Indexer typeCPX; + ArrayList elemValuePairs; + + @Override + public T visit(ConstantPool pool) { + for( ElemValuePair pair : elemValuePairs ) { + pair.visit(pool); + } + return (T) this; + } + + /** + * AnnotationElemValue + * + * Used to store Annotation Data + */ + static public class ElemValuePair implements ConstantPoolDataVisitor { + + ConstCell name; + DataWriter value; + + public ElemValuePair(ConstCell name, DataWriter value) { + this.name = name; + this.value = value; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + name.write(out); + value.write(out); + } + + @Override + public int getLength() { + return 2 + value.getLength(); + } + + @Override + public T visit(ConstantPool pool) { + this.name = visitConstCell(this.name, pool); + this.value = visitData(this.value, pool); + return (T) this; + } + } + + public AnnotationData(Indexer typeCPX, boolean invisible) { + this.typeCPX = typeCPX; + this.elemValuePairs = new ArrayList<>(); + this.invisible = invisible; + } + + public void add(ElemValuePair elemValuePair) { + elemValuePairs.add(elemValuePair); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(typeCPX.cpIndex); + out.writeShort(elemValuePairs.size()); + for (DataWriter pair : elemValuePairs) { + pair.write(out); + } + } + + @Override + public int getLength() { + return 4 + elemValuePairs.stream().flatMapToInt(elem-> IntStream.of(elem.getLength())).sum(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ArrayAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ArrayAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ArrayAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ArrayAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Base class of the "classes/descriptors[]" data of attributes + *

+ * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + *

+ * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubclasses_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + *

+ * Valhalla: + * LoadableDescriptors_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_descriptors; + * u2 descriptors[number_of_descriptors]; + * } + */ +public class ArrayAttr extends AttrData { + + List cells = new ArrayList<>(); + + public ArrayAttr(ConstantPool pool, EAttribute attribute, List constCellList) { + super(pool, attribute); + for (ConstCell cell : constCellList) { + this.cells.add(classifyConstCell(pool, cell)); + } + } + + public int size() { + return cells.size(); + } + + @Override + public int attrLength() { + return 2 + cells.size() * 2; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeShort(cells.size()); + for (ConstCell c : cells) { + out.writeShort(c.cpIndex); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AttrData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AttrData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AttrData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/AttrData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; +import java.util.Optional; + +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.*; + +/** + * AttrData + *

+ * AttrData is the base class for many attributes (or parts of attributes), and it is + * instantiated directly for simple attributes (like Synthetic or Deprecated). + */ +class AttrData implements ConstantPoolDataVisitor { + + private final EAttribute attribute; + private final ConstCell attributeNameConstantCell; + + AttrData(ConstantPool pool, EAttribute attribute) { + this.attribute = attribute; + this.attributeNameConstantCell = pool.findUTF8Cell(attribute.parseKey()); + } + + @Override + public T visit(ConstantPool pool) { + if (this instanceof CPXAttr cpxAttr) { + final ConstCell cell = cpxAttr.cell; + if (! cell.isSet()) { + if (cell.getType() == CONSTANT_STRING) { + if (attribute.getCPTypeOfIndex() == CONSTANT_UTF8) { + Optional> strCell = pool.ConstantPoolHashByValue.values().stream(). + filter(v -> v.isSet() && v.getType() == CONSTANT_STRING && v.equalsByValue(cell)). + findFirst(); + cpxAttr.cell = strCell.isPresent() ? + strCell.get() : + pool.findCell(new ConstantPool.ConstValue_String((ConstCell) cell.ref.value)); + } + } + } + } + return (T) this; + } + + protected ConstCell classifyConstCell(ConstantPool pool, ConstCell cell) { + switch (cell.getType()) { + case CONSTANT_CLASS -> { + return cell; + } + case CONSTANT_UTF8 -> { + if( attribute.getCPTypeOfIndex() == CONSTANT_CLASS ) { + Optional> clsCell = pool.ConstantPoolHashByValue.values().stream(). + filter(v -> v.getType() == CONSTANT_CLASS && v.ref.value.equals(cell)). + findAny(); + if (clsCell.isPresent()) { + return clsCell.get(); + } else { + // create class cell referencing to UTF8 + return pool.findCell(new ConstantPool.ConstValue_Class((ConstCell) cell)); + } + } + } + default -> { + // no action + } + } + return cell; + } + + // full length of the attribute + // declared in Data + @Override + public int getLength() { + return 6 + attrLength(); + } + + // subclasses must redefine this + public int attrLength() { + return 0; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(attributeNameConstantCell.cpIndex); + out.writeInt(attrLength()); // attribute length + } + public EAttribute getAttribute() { + return attribute; + } +} // end class AttrData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/BootstrapMethodData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/BootstrapMethodData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/BootstrapMethodData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/BootstrapMethodData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +class BootstrapMethodData extends Indexer implements DataWriter { + + ConstCell bootstrapMethodHandle; + List> arguments; + + public BootstrapMethodData(ConstCell bsmHandle, List> arguments) { + super(); + this.bootstrapMethodHandle = bsmHandle; + this.arguments = arguments; + } + + // methodAttrIndex - bootstrap_method_attr_index + // The value of the bootstrap_method_attr_index item must be a valid index into the bootstrap_methods array + // of the bootstrap method table of this class file (§4.7.23). + public BootstrapMethodData(int methodAttrIndex) { + super(); + this.bootstrapMethodHandle = null; + this.arguments = new ArrayList<>(); + super.cpIndex = methodAttrIndex; + } + + public int getLength() { + return 4 + arguments.size() * 2; + } + + public boolean hasMethodAttrIndex() { + return super.isSet(); + } + + public void setMethodAttrIndex(int methodAttrIndex) { + super.cpIndex = methodAttrIndex; + } + + public int getMethodAttrIndex() { + return super.cpIndex; + + } + + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(bootstrapMethodHandle.cpIndex); + out.writeShort(arguments.size()); + + for (ConstCell argument : arguments) { + out.writeShort(argument.cpIndex); + } + } + + @Override + public String toString() { + return String.format("{MethodHandle:%s Arguments:%s}", + bootstrapMethodHandle == null || bootstrapMethodHandle.cpIndex == NotSet ? " n/a" : " #" + bootstrapMethodHandle.cpIndex, + arguments == null || arguments.isEmpty() ? "{}" : + "{ " + arguments.stream().map(a -> String.format("#%d", a.cpIndex)).collect(Collectors.joining(", ")) + " }"); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BootstrapMethodData)) return false; + BootstrapMethodData that = (BootstrapMethodData) o; + if (!Objects.equals(bootstrapMethodHandle, that.bootstrapMethodHandle)) + return false; + return this.cpIndex == that.cpIndex & Objects.equals(arguments, that.arguments); + } + + @Override + public int hashCode() { + int result = 31 * (bootstrapMethodHandle != null ? bootstrapMethodHandle.hashCode() : 0); + result = 31 * result + (arguments != null ? arguments.hashCode() : 0); + return result; + } + + public boolean equalsByValue(Object o) { + if (this == o) return true; + if (!(o instanceof BootstrapMethodData)) return false; + BootstrapMethodData that = (BootstrapMethodData) o; + if (!Objects.equals(bootstrapMethodHandle, that.bootstrapMethodHandle)) + return false; + if (arguments == that.arguments) return true; + if (arguments != null && (arguments.size() == that.arguments.size())) { + for (int i = 0; i < arguments.size(); i++) { + if (!arguments.get(i).equalsByValue(that.arguments.get(i))) { + return false; + } + } + return true; + } + return false; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPTagVisitor.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPTagVisitor.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPTagVisitor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPTagVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.CompilerConstants; + +import static java.lang.String.format; + +/** + * Constant Pool Tag Visitor base class defining a visitor for decoding constants. + */ +public abstract class CPTagVisitor implements CompilerConstants { + + public CPTagVisitor() { } + + public final R visit(ClassFileConst.ConstType tag) { + switch (tag) { + case CONSTANT_UTF8, CONSTANT_ASCIZ -> { + return visitUTF8(); + } + case CONSTANT_INTEGER, CONSTANT_INT, + CONSTANT_BYTE, CONSTANT_C_BYTE, + CONSTANT_CHAR, CONSTANT_C_CHAR, + CONSTANT_SHORT, CONSTANT_C_SHORT, + CONSTANT_C_BOOLEAN, CONSTANT_BOOLEAN -> { + return visitInteger(tag); + } + case CONSTANT_FLOAT, CONSTANT_C_FLOAT -> { + return visitFloat(); + } + case CONSTANT_DOUBLE, CONSTANT_C_DOUBLE -> { + return visitDouble(); + } + case CONSTANT_LONG, CONSTANT_C_LONG -> { + return visitLong(); + } + case CONSTANT_METHODTYPE -> { + return visitMethodType(); + } + case CONSTANT_STRING, CONSTANT_L_STRING -> { + return visitString(); + } + case CONSTANT_CLASS, CONSTANT_C_CLASS -> { + return visitClass(); + } + case CONSTANT_METHODREF, CONSTANT_METHOD -> { + return visitMethod(); + } + case CONSTANT_FIELDREF, CONSTANT_FIELD -> { + return visitField(); + } + case CONSTANT_INTERFACEMETHODREF, CONSTANT_INTERFACEMETHOD -> { + return visitInterfaceMethod(); + } + case CONSTANT_NAMEANDTYPE -> { + return visitNameAndType(); + } + case CONSTANT_METHODHANDLE -> { + return visitMethodHandle(); + } + case CONSTANT_DYNAMIC -> { + return visitDynamic(); + } + case CONSTANT_INVOKEDYNAMIC -> { + return visitInvokeDynamic(); + } + case CONSTANT_PACKAGE -> { + return visitPackage(); + } + case CONSTANT_MODULE -> { + return visitModule(); + } + } + throw new RuntimeException( + format("The Constant Type \"%s\" does not have a corresponding visitor function.", tag.printVal())); + } + + public abstract R visitUTF8(); + + // The following types are allowed: CONSTANT_INTEGER, CONSTANT_INTEGER_BYTE, + // CONSTANT_INTEGER_CHAR, CONSTANT_INTEGER_SHORT, CONSTANT_INTEGER_BOOLEAN + public abstract R visitInteger(ClassFileConst.ConstType tag); + + public abstract R visitFloat(); + + public abstract R visitDouble(); + + public abstract R visitLong(); + + public abstract R visitMethodType(); + + public abstract R visitString(); + + public abstract R visitClass(); + + public abstract R visitMethod(); + + public abstract R visitField(); + + public abstract R visitInterfaceMethod(); + + public abstract R visitNameAndType(); + + public abstract R visitMethodHandle(); + + public abstract R visitDynamic(); + + public abstract R visitInvokeDynamic(); + + public abstract R visitModule(); + + public abstract R visitPackage(); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPVisitor.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPVisitor.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPVisitor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +/** + * CPVisitor base class defining a visitor for decoding constants. + */ +public interface CPVisitor< C extends ConstantPool.ConstValue_Cell, P extends ConstantPool.ConstValue_Pair> { + default void visit(ConstValue constValue) { + switch (constValue.tag) { + case CONSTANT_ZERO: + break; // ignore + case CONSTANT_METHODTYPE, + CONSTANT_STRING, CONSTANT_L_STRING, + CONSTANT_CLASS, CONSTANT_C_CLASS, + CONSTANT_MODULE, CONSTANT_PACKAGE: + visitConstValueCell((C) constValue); + break; + case CONSTANT_METHODREF, CONSTANT_METHOD, + CONSTANT_FIELDREF, CONSTANT_FIELD, + CONSTANT_INTERFACEMETHODREF, CONSTANT_INTERFACEMETHOD, + CONSTANT_NAMEANDTYPE: + visitConstValueRefCell((P) constValue); + break; + case CONSTANT_METHODHANDLE: + visitMethodHandle((ConstantPool.ConstValue_MethodHandle) constValue); + break; + case CONSTANT_UTF8, CONSTANT_ASCIZ, + CONSTANT_INTEGER, CONSTANT_INT, + CONSTANT_BYTE, CONSTANT_C_BYTE, + CONSTANT_CHAR, CONSTANT_C_CHAR, + CONSTANT_SHORT, CONSTANT_C_SHORT, + CONSTANT_C_BOOLEAN, CONSTANT_BOOLEAN, + CONSTANT_FLOAT, CONSTANT_C_FLOAT, + CONSTANT_DOUBLE, CONSTANT_C_DOUBLE, + CONSTANT_LONG, CONSTANT_C_LONG, + CONSTANT_DYNAMIC, CONSTANT_INVOKEDYNAMIC: + // default + default: + } + } + void visitConstValueCell(C constValue); + void visitConstValueRefCell(P constValue); + void visitMethodHandle(ConstantPool.ConstValue_MethodHandle constValue); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPXAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPXAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPXAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CPXAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; + +/** + * Constant Pool Index Attribute + */ +class CPXAttr extends AttrData { + + ConstCell cell; + + public CPXAttr(ConstantPool pool, EAttribute attribute, ConstCell cell) { + super(pool, attribute); + this.cell = classifyConstCell(pool, cell); + } + + public int attrLength() { + return 2; + } + + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); // attr name, attr len + out.writeShort(cell.cpIndex); + } +} // end class CPXAttr diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; + +public interface CheckedDataOutputStream { + + void write(int b) throws IOException; + + void write(byte b[], int off, int len) throws IOException; + + default void write(byte b[]) throws IOException { + write(b,0, b.length); + } + + void writeBoolean(boolean v) throws IOException; + + void writeByte(int v) throws IOException; + + void writeShort(int v) throws IOException; + + void writeChar(int v) throws IOException; + + void writeInt(int v) throws IOException; + + void writeLong(long v) throws IOException; + + void writeFloat(float v) throws IOException; + + void writeDouble(double v) throws IOException; + + void writeBytes(String s) throws IOException; + + void writeChars(String s) throws IOException; + + void writeUTF(String s) throws IOException; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Checker.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Checker.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Checker.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Checker.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.ClassFileContext; +import org.openjdk.asmtools.common.structure.EModifier; + +import static org.openjdk.asmtools.common.structure.EModifier.*; +import static org.openjdk.asmtools.jasm.JasmTokens.Token; + +/** + * Utility methods to verify modifiers masks for classes, interfaces, methods and fields + */ +public class Checker { + + private Checker() { + } + + /* + * Check that only one of the Access flags is set. + */ + private static boolean validAccess(int mod) { + return EModifier.onlyOneOfFlags(mod, ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED); + } + + public static boolean validNestedClass(int flags) { + return (flags & ~getFlags(MM_NESTED_CLASS)) == 0; + } + + public static boolean validField(int flags) { + return (flags & ~getFlags(MM_FIELD)) == 0; + } + + public static int notValidField(int flags) { + return getNotPermitted(flags, MM_FIELD); + } + + /* + * Methods of classes may have any of the flags in Table 4.6-A set. (MM_METHOD) + * However, each method of a class may have at most one of its ACC_PUBLIC, ACC_PRIVATE, and ACC_PROTECTED flags set (JLS §8.4.3). + */ + private static boolean validMethod(int mod) { + return noFlagsExcept(mod, MM_METHOD); + } + + public static boolean validAbstractMethod(int flags) { + return (flags & ~getFlags(MM_ABSTRACT_METHOD)) == 0; + } + + public static boolean validInitMethod(int flags) { + return (flags & ~getFlags(MM_INIT_METHOD)) == 0; + } + + /* + * Fields of interfaces must have their ACC_PUBLIC, ACC_STATIC, and ACC_FINAL flags set; + * they may have their ACC_SYNTHETIC flag set and must not have any of the other flags in Table 4.5-A set (JLS §9.3). + */ + public static boolean validInterfaceField(int mod) { + int flags = isSynthetic(mod) ? mod & ~ACC_SYNTHETIC.getFlag() : mod; + flags = isStrict(flags) ? flags & ~ACC_STRICT.getFlag() : flags; + return noFlagsExcept(flags, ACC_PUBLIC, ACC_STATIC, ACC_FINAL); + } + + /** + * The only flags are allowed in interface: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_SYNTHETIC, ACC_ANNOTATION + */ + public static boolean validInterface(int mod) { + return noFlagsExcept(mod, MM_INTERFACE); + } + + /* + * The only flags allowed to the Class are set. + */ + public static boolean validClass(int mod) { + return noFlagsExcept(mod, MM_CLASS); + } + + public static boolean isValueObjectsContext() { + return EModifier.GlobalContext() == ClassFileContext.VALUE_OBJECTS; + } + + /** + * Check the modifier flags for the class + * + * @param mod The modifier flags being checked + * @param scanner The file parser + */ + public static void checkClassModifiers(int mod, Scanner scanner) { + // Check "Value Classes and Objects" Context + if (EModifier.isValueObjects(mod)) { + EModifier.setGlobalContext(ClassFileContext.VALUE_OBJECTS); + } + + mod = EModifier.cleanFlags(mod, DEPRECATED_ATTRIBUTE, SYNTHETIC_ATTRIBUTE, VALUE_OBJECTS_ATTRIBUTE); + + // check Ambiguous use of similar modifiers + if (EModifier.moreThanOne(mod, ACC_PUBLIC, ACC_PROTECTED, ACC_PRIVATE)) { + scanner.environment.warning(scanner.pos, "warn.repeated.modifier"); + } + + if (scanner.token != Token.CLASS && !EModifier.isInterface(mod)) { + scanner.environment.warning(scanner.pos, "warn.one.of.two.token.expected", + Token.CLASS.parseKey(), Token.INTERFACE.parseKey(), Token.CLASS.parseKey()); + } +// Interface + if (isInterface(mod)) { + // If the ACC_INTERFACE flag is set, the ACC_ABSTRACT flag must also be set. + if (!isAbstract(mod)) { + scanner.environment.warning(scanner.pos, "warn.invalid.modifier.int.abs", + EModifier.asNames(mod, ClassFileContext.CLASS)); + } + // If the ACC_INTERFACE flag is set, the ACC_FINAL, ACC_IDENTITY, ACC_ENUM, and ACC_MODULE flags must not be set. + if (anyOf(mod, ACC_FINAL, ACC_ENUM, ACC_IDENTITY, ACC_MODULE)) { + if (isValueObjectsContext()) { + scanner.environment.warning(scanner.pos, "warn.invalid.modifier.interface.set.vo", + EModifier.asNames(mod, ClassFileContext.CLASS)); + } else { + scanner.environment.warning(scanner.pos, "warn.invalid.modifier.interface.set", + EModifier.asNames(mod, ClassFileContext.CLASS)); + } + } +// Class + } else { + // If the ACC_INTERFACE flag is not set, any of the other flags in Table 4.1-B may be set except ACC_ANNOTATION and ACC_MODULE. + if (anyOf(mod, ACC_ANNOTATION, ACC_MODULE)) { + scanner.environment.warning(scanner.pos, "warn.invalid.modifier.not.interface.set", + EModifier.asNames(mod, ClassFileContext.CLASS)); + } + if (isValueObjectsContext()) { + // However, such a class file must have at least one of its ACC_FINAL, ACC_IDENTITY, or ACC_ABSTRACT flags set, + if (!anyOf(mod, ACC_FINAL, ACC_IDENTITY, ACC_ABSTRACT)) { + String buf = EModifier.asNames(mod, ClassFileContext.CLASS); + buf = (buf.isEmpty() ? "ACC_VALUE" : "ACC_VALUE, ".concat(buf)); + scanner.environment.warning(scanner.pos, "warn.invalid.modifier.not.interface.set.vo", buf); + } + + } + if (!validClass(mod)) { + scanner.environment.warning(scanner.pos, "warn.invalid.modifier.class", + EModifier.asNames(mod & ~getFlags(MM_CLASS), ClassFileContext.CLASS)); + } + } + + // Must not have both its ACC_FINAL and ACC_ABSTRACT flags set (JLS §8.1.1.2). + if (both(mod, ACC_ABSTRACT, ACC_FINAL)) { + scanner.environment.warning(scanner.pos, "warn.invalid.modifier.class.finabs", + EModifier.asNames(mod, ClassFileContext.CLASS)); + } + } + + /** + * Check the modifier flags for the field + * + * @param classData The ClassData for the current class + * @param mod The modifier flags being checked + * @param pos the position of the parser in the file + */ + public static void checkFieldModifiers(ClassData classData, int mod, long pos) { + JasmEnvironment environment = classData.getEnvironment(); + mod = EModifier.cleanFlags(mod, DEPRECATED_ATTRIBUTE, SYNTHETIC_ATTRIBUTE); + if (classData.isInterface()) { // For interfaces fields. + // Fields of interfaces must have their ACC_PUBLIC, ACC_STATIC, and ACC_FINAL flags set; + //they may have their ACC_STRICT_INIT or ACC_SYNTHETIC flag set, and must not have any of the other flags in Table 4.5-A set (JLS §9.3). + if (!validInterfaceField(mod)) { + environment.warning(pos, "warn.invalid.modifier.intfield", + EModifier.asNames(mod, ClassFileContext.FIELD)); + } + // + if( !isPublic(mod)) { + environment.warning(pos, "warn.invalid.modifier.intfield", + EModifier.asNames(mod, ClassFileContext.FIELD)); + } + } else { // For non-interface fields. + if (isValueObjectsContext()) { + // Each field of a value class must have at least one of its ACC_STATIC or ACC_STRICT_INIT flags set. + if (classData.isValue()) { + if (!EModifier.anyOf(mod, ACC_STATIC, ACC_STRICT)) { + environment.warning(pos, "warn.invalid.modifier.for.value", + EModifier.asNames(mod, ClassFileContext.FIELD)); + } + } + } + //Fields of classes may set any of the flags in Table 4.5-A. + // However, each field of a class may have at most one of its ACC_PUBLIC, ACC_PRIVATE, and ACC_PROTECTED flags set (JLS §8.3.1), + // and must not have both its ACC_FINAL and ACC_VOLATILE flags set (JLS §8.3.1.4). + int invalidFlags = notValidField(mod); + if (invalidFlags != 0) { + environment.warning(pos, "warn.invalid.modifier.field", + EModifier.asNames(invalidFlags, ClassFileContext.FIELD)); + } + if (!validAccess(mod)) { + environment.warning(pos, "warn.invalid.modifier.acc", + EModifier.asNames(mod, ClassFileContext.FIELD)); + } + if (both(mod, ACC_FINAL, ACC_VOLATILE)) { + environment.warning(pos, "warn.invalid.modifier.fiva", + EModifier.asNames(mod, ClassFileContext.FIELD)); + } + } + } + + /** + * Check the modifier flags for the method + * + * @param classData The ClassData for the current class + * @param mod The modifier flags being checked + * @param pos the position of the parser in the file + * @param isInit is the method constructor + * @param isClinit is the method static initializer + */ + public static void checkMethodModifiers(ClassData classData, int mod, long pos, boolean isInit, boolean isClinit) { + final JasmEnvironment environment = classData.getEnvironment(); + final int cfvMajorVersion = classData.cfv.major_version(); + mod = EModifier.cleanFlags(mod, DEPRECATED_ATTRIBUTE, SYNTHETIC_ATTRIBUTE); + int wrongFlags; + if (!validMethod(mod)) { + wrongFlags = mod & ~EModifier.getFlags(MM_METHOD); + environment.warning(pos, "warn.invalid.modifier.mth", + EModifier.asNames(wrongFlags, ClassFileContext.METHOD)); + } + if (!validAccess(mod)) { + environment.warning(pos, "warn.invalid.modifier.mth.acc", + EModifier.asNames(mod, ClassFileContext.METHOD)); + } + if (isClinit) { // + // In a class file whose version number is 51.0 or above, a method whose name is must have its ACC_STATIC flag set. + if (classData.cfv.major_version() > 51 && !isStatic(mod)) { + environment.warning(pos, "warn.clinit.static", + EModifier.asNames(mod, ClassFileContext.METHOD)); + } + } else { // any method + // interface methods. + if (classData.isInterface()) { + if (isInit) { + environment.warning(pos, "warn.init.in_int"); + } else { + validateInterfaceMethod(mod, classData, pos); + } + // class methods + } else { + if (isInit && !validInitMethod(mod)) { + wrongFlags = mod & ~EModifier.getFlags(MM_INIT_METHOD); + environment.warning(pos, "warn.invalid.modifier.init", + EModifier.asNames(wrongFlags, ClassFileContext.METHOD)); + } else if (isAbstract(mod)) { + if (!validAbstractMethod(mod)) { + wrongFlags = mod & ~EModifier.getFlags(MM_ABSTRACT_METHOD); + environment.warning(pos, "warn.invalid.modifier.abst", + EModifier.asNames(wrongFlags, ClassFileContext.METHOD)); + } else if (isStrict(mod) && (cfvMajorVersion >= 46 && cfvMajorVersion <= 60)) { + environment.warning(pos, "warn.invalid.modifier.strict"); + } + } + } + } + } + + /** + * Check the modifier flags for the inner-class + * + * @param classData The ClassData for the current class + * @param mod The modifier flags being checked + * @param pos the position of the parser in the file + */ + public static void checkInnerClassModifiers(ClassData classData, int mod, long pos) { + JasmEnvironment environment = classData.getEnvironment(); + mod = EModifier.cleanFlags(mod, DEPRECATED_ATTRIBUTE, SYNTHETIC_ATTRIBUTE); + if (!validNestedClass(mod)) { + int wrongFlags = mod & ~EModifier.getFlags(MM_NESTED_CLASS); + environment.warning(pos, "warn.invalid.modifier.innerclass", + EModifier.asNames(wrongFlags, ClassFileContext.INNER_CLASS)); + } + } + + // Methods of interfaces may have any of the flags in Table 4.6-A set except ACC_PROTECTED, ACC_FINAL, ACC_SYNCHRONIZED, + // and ACC_NATIVE (JLS §9.4). In a class file whose version number is less than 52.0, each method of an interface + // must have its ACC_PUBLIC and ACC_ABSTRACT flags set; in a class file whose version number is 52.0 or above, + // each method of an interface must have exactly one of its ACC_PUBLIC and ACC_PRIVATE flags set. + public static void validateInterfaceMethod(int mod, ClassData cd, long pos) { + final int cfvMajorVersion = cd.cfv.major_version(); + final JasmEnvironment environment = cd.getEnvironment(); + if (EModifier.anyOf(mod, ACC_PROTECTED, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE)) { + environment.warning(pos, "warn.invalid.modifier.method", + EModifier.asNames(mod, ClassFileContext.METHOD)); + } + if (cfvMajorVersion < 52) { + if (!both(mod, ACC_PUBLIC, ACC_ABSTRACT)) { + environment.warning(pos, "warn.invalid.modifier.intmth.less.52", + EModifier.asNames(mod, ClassFileContext.METHOD)); + } else { // cfvMajorVersion >= 52 + if (!EModifier.onlyOneOfFlags(mod, EModifier.ACC_PUBLIC, ACC_PRIVATE)) { + environment.warning(pos, "warn.invalid.modifier.intmth.is.52", + EModifier.asNames(mod, ClassFileContext.METHOD)); + } + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,822 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.outputs.NamedToolOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.structure.CFVersion; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.ELocation; +import org.openjdk.asmtools.common.structure.EModifier; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.openjdk.asmtools.common.structure.ClassFileContext.INNER_CLASS; +import static org.openjdk.asmtools.common.structure.EAttribute.ATT_Record; +import static org.openjdk.asmtools.jasm.ClassData.CoreClasses.PLACE.HEADER; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.CONSTANT_DYNAMIC; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.CONSTANT_INVOKEDYNAMIC; +import static org.openjdk.asmtools.jasm.ClassFileConst.JAVA_MAGIC; +import static org.openjdk.asmtools.jasm.Indexer.NotSet; + +/** + * ClassData + *

+ * This is the main data structure for representing parsed class data. This structure + * renders directly to a class file. + */ +class ClassData extends MemberData { + + private static final String DEFAULT_EXTENSION = ".class"; + /* ClassData Fields */ + private final JasmEnvironment environment; + public CDOutputStream cdos; + String fileExtension = DEFAULT_EXTENSION; + MethodData curMethod; + CFVersion cfv; + String myClassName; + // Core classes of the class file: this_class, super_class + CoreClasses coreClasses = new CoreClasses(); + AttrData sourceFileAttr; + SourceDebugExtensionAttr sourceDebugExtensionAttr; + ArrayList interfaces; + ArrayList fields = new ArrayList<>(); + ArrayList methods = new ArrayList<>(); + DataVectorAttr innerClasses = null; + DataVectorAttr bootstrapMethodsAttr = null; + // JEP 181 - NestHost, NestMembers attributes since class version 55.0 + CPXAttr nestHostAttr; + NestMembersAttr nestMembersAttr; + // JEP 261: Module System since class file 53.0 + ModuleAttr moduleAttribute = null; + // JEP 359 - Record attribute since class file 58.65535 + private RecordData recordData; + // + // JEP 360 - PermittedSubclasses attribute since class file 59.65535 + private PermittedSubclassesAttr permittedSubclassesAttr; + // Valhalla + private LoadableDescriptorsAttr loadableDescriptorsAttr; + // EnclosingMethod + private EnclosingMethodAttr enclosingMethodAttr; + + /** + * @param environment The error reporting environment. + * @param cfv Class file version + */ + public ClassData(JasmEnvironment environment, CFVersion cfv) { + super(new ConstantPool(environment), environment); // for a class, these get initialized in the super - later. + this.attributeLocation = ELocation.class_file; + this.environment = environment; + this.cdos = new CDOutputStream(); + this.cfv = cfv; + } + + /** + * Initializes the ClassData. + * + * @param this_class The constant pool reference to this class + * @param super_class The constant pool reference to the super class + * @param interfaces A list of interfaces that this class implements + */ + public final void init(int access, ConstCell this_class, ConstCell super_class, ArrayList interfaces) { + this.access = access; + // normalize the modifiers to access flags + if (EModifier.hasPseudoMod(access)) { + createPseudoMod(); + } + this.coreClasses.this_class(HEADER, this_class); + this.coreClasses.super_class(HEADER, super_class); + this.interfaces = interfaces; + // Set default class file version if it is not set. + this.cfv.initClassDefaultVersion(); + } + + public final void initAsPackageInfo(int access, String className) { + this.access = access; + // this_class: class "package_name/package-info" + this.myClassName = className; + this.cfv.initClassDefaultVersion(); + } + + public final void initAsModule() { + this.access = EModifier.ACC_MODULE.getFlag(); + // If the ACC_MODULE flag is set in the access_flags item + // super_class: zero + this.coreClasses.super_class(HEADER, new ConstCell(0)); + this.cfv.initModuleDefaultVersion(); + } + + /** + * Predicate that describes if this class has an access flag indicating that it is an + * interface. + * + * @return True, if the class access flag indicates it is an interface. + */ + public final boolean isInterface() { + return EModifier.isInterface(access); + } + + // Entity of the Value Classes and Objects + public final boolean isValue() { + return !EModifier.isIdentity(access); + } + + /** + * Predicate that describes if this class has an abstract flag indicating that it is the abstract class. + * + * @return True, if the class access flag indicates it is the abstract class. + */ + public final boolean isAbstract() { + return EModifier.isAbstract(access); + } + + /* + * After a constant pool has been explicitly declared, + * this method links the Constant_InvokeDynamic|Constant_Dynamic + * constants with any bootstrap methods that they index in the + * Bootstrap Methods Attribute + */ + protected void relinkBootstrapMethods() { + if (bootstrapMethodsAttr != null) { + ArrayList> cells = pool.getPoolValuesByRefType(CONSTANT_INVOKEDYNAMIC, CONSTANT_DYNAMIC); + environment.traceln("relinkBSMs: %d items", cells.size()); + for (ConstCell cell : cells) { + ConstantPool.ConstValue_BootstrapMethod refVal = (ConstantPool.ConstValue_BootstrapMethod) cell.ref; + BootstrapMethodData bsmData = refVal.bsmData(); + if (refVal.isSet() & refVal.value.ref == null) { + ConstCell c = pool.getCell(((ConstCell) refVal.value).cpIndex); + refVal.setValue(c); + } + if (bsmData != null && bsmData.hasMethodAttrIndex()) { + // find the real BSM Data at the index + int methodAttrIndex = bsmData.getMethodAttrIndex(); + if (methodAttrIndex < 0 || methodAttrIndex > bootstrapMethodsAttr.size()) { + // bad BSM index - give a warning, but place the index in the arg anyway + environment.warning("warn.bootstrapmethod.attr.bad", methodAttrIndex); + bsmData.setMethodAttrIndex(methodAttrIndex); + } else { + // make the IndyPairs BSM Data point to the one from the attribute + refVal.setBsmData(bootstrapMethodsAttr.get(methodAttrIndex), methodAttrIndex); + } + } + } + } + } + + /** + * Finds first BSM data element by value in a collection + */ + private > int getFirstIndex(T collection, BootstrapMethodData bsmData) { + if (!collection.isEmpty()) { + BootstrapMethodData[] array = collection.toArray(BootstrapMethodData[]::new); + for (int i = 0; i < array.length; i++) { + if (bsmData.equalsByValue(array[i])) { + return i; + } + } + } + return NotSet; + } + + /** + * Relinks BSM data (BootstrapMethod Attribute) and Constant Pool Constant_InvokeDynamic|Constant_Dynamic entries if + * at least one CP cell has undefined method attribute index also the method removes duplicates in BootstrapMethod + * Attribute if found + */ + private void uniquifyBootstrapMethods() { + if (bootstrapMethodsAttr != null) { + int index = 0; + final List cpBsmList = this.getPool(). + getPoolCellsByType(CONSTANT_DYNAMIC, CONSTANT_INVOKEDYNAMIC). + stream().map(item -> ((ConstantPool.ConstValue_BootstrapMethod) item.ref). + bsmData()).toList(); + if (cpBsmList.stream().anyMatch(item -> !item.hasMethodAttrIndex())) { + environment.traceln("numberBSM: %d items", cpBsmList.size()); + // remove duplicates in BootstrapMethod_Attribute if found + // Fix 7902888: Excess entries in BootstrapMethods with the same bsm, bsmKind, bsmArgs + final ArrayList newBsmList = new ArrayList<>(cpBsmList.size()); + for (int i = 0; i < cpBsmList.size(); i++) { + BootstrapMethodData bsmData = cpBsmList.get(i); + int cachedIndex = getFirstIndex(newBsmList, bsmData); + if (cachedIndex != NotSet) { + bsmData.setMethodAttrIndex(cachedIndex); + } else { + if (getFirstIndex(this.bootstrapMethodsAttr, bsmData) == NotSet) { + environment.warning("warn.bootstrapmethod.attr.expected", bsmData.toString()); + } else { + bsmData.setMethodAttrIndex(index++); + } + newBsmList.add(bsmData); + } + } + bootstrapMethodsAttr.replaceAll(newBsmList); + } + } + } + + public AttrData setSourceFileAttr(ConstCell value_cpx) { + this.sourceFileAttr = new CPXAttr(pool, EAttribute.ATT_SourceFile, value_cpx); + return this.sourceFileAttr; + } + + public SourceDebugExtensionAttr setSourceDebugExtensionAttr() { + this.sourceDebugExtensionAttr = new SourceDebugExtensionAttr(pool); + return this.sourceDebugExtensionAttr; + } + + public RecordData setRecord(long where) { + checkExistence(ATT_Record, () -> environment.warning(where, "warn.record.repeated")); + this.recordData = new RecordData(this); + return this.recordData; + } + + /** + * Rejects a record: removes the record attribute if there are no components + */ + public void rejectRecord() { + this.recordData = null; + } + + // Field + public ConstantPool.ConstValue_FieldRef makeFieldRef(ConstCell name, ConstCell descriptor) { + return new ConstantPool.ConstValue_FieldRef(name, descriptor); + } + + public FieldData addFieldIfAbsent(int access, ConstCell name, ConstCell descriptor) { + ConstantPool.ConstValue_FieldRef fieldRef = makeFieldRef(name, descriptor); + environment.traceln(() -> " [ClassData.addFieldIfAbsent]: #" + + fieldRef.value.first.cpIndex + ":#" + + fieldRef.value.second.cpIndex); + FieldData fd = getField(fieldRef); + if (fd == null) { + environment.traceln(" [ClassData.addFieldIfAbsent]: new field."); + fd = addField(access, fieldRef); + } + return fd; + } + + private FieldData getField(ConstantPool.ConstValue_FieldRef nameAndType) { + for (FieldData fd : fields) { + if (fd.getNameDesc().equals(nameAndType)) { + return fd; + } + } + return null; + } + + public FieldData addField(int access, ConstantPool.ConstValue_FieldRef fieldRef) { + environment.traceln(() -> " [ClassData.addField]: #" + + fieldRef.value.first.cpIndex + ":#" + + fieldRef.value.second.cpIndex); + FieldData res = new FieldData(this, access, fieldRef); + fields.add(res); + return res; + } + + public FieldData addField(int access, ConstCell name, ConstCell sig) { + return addField(access, makeFieldRef(name, sig)); + } + + public MethodData StartMethod(int access, ConstCell name, ConstCell sig, ArrayList exc_table) { + EndMethod(); + environment.traceln(() -> " [ClassData.StartMethod]: #" + name.cpIndex + ":#" + sig.cpIndex); + curMethod = new MethodData(this, access, name, sig, exc_table); + methods.add(curMethod); + return curMethod; + } + + public void EndMethod() { + curMethod = null; + } + + public ConstCell LocalMethodRef(ConstValue nape) { + return pool.findCell(ConstType.CONSTANT_METHODREF, coreClasses.this_class(), pool.findCell(nape)); + } + + public ConstCell LocalMethodRef(ConstCell name, ConstCell sig) { + return LocalMethodRef(makeFieldRef(name, sig)); + } + + void addLocVarData(int opc, Indexer arg) { + } + + public void addInnerClass(int access, ConstCell name, ConstCell innerClass, ConstCell outerClass) { + environment.traceln(() -> "addInnerClass (with indexes: Name (" + name.toString() + + "), Inner (" + innerClass.toString() + "), Outer (" + outerClass.toString() + ")."); + if (innerClasses == null) { + innerClasses = new DataVectorAttr<>(pool, EAttribute.ATT_InnerClasses); + } + innerClasses.add(new InnerClassData(access, name, innerClass, outerClass)); + } + + public void addBootstrapMethod(BootstrapMethodData bsmData) { + if (bootstrapMethodsAttr == null) { + bootstrapMethodsAttr = new DataVectorAttr<>(pool, EAttribute.ATT_BootstrapMethods); + } + bootstrapMethodsAttr.add(bsmData); + environment.traceln(() -> "addBootstrapMethod: " + bsmData.toString()); + } + + public void addNestHost(ConstCell hostClass) { + environment.traceln("addNestHost"); + nestHostAttr = new CPXAttr(pool, EAttribute.ATT_NestHost, hostClass); + } + + public void addNestMembers(List classes) { + environment.traceln("addNestMembers"); + nestMembersAttr = new NestMembersAttr(pool, classes); + } + + public void addPermittedSubclasses(List classes) { + environment.traceln("addPermittedSubclasses"); + permittedSubclassesAttr = new PermittedSubclassesAttr(pool, classes); + } + + public void addLoadableDescriptors(List utf8List) { + environment.traceln("addLoadableDescriptors"); + loadableDescriptorsAttr = new LoadableDescriptorsAttr(pool, utf8List); + } + + public void addEnclosingMethod(ConstCell classCell, ConstCell methodRefCell) { + environment.traceln("addEnclosingMethod"); + enclosingMethodAttr = new EnclosingMethodAttr(pool, classCell, methodRefCell); + } + + + public void endClass() { + if (coreClasses.super_class() == null) { + coreClasses.super_class(pool.findClassCell("java/lang/Object")); + } + pool.itemizePool(); + coreClasses.specifyClasses(pool); + coreClasses.cleanConstantPool(pool); + pool.checkGlobals(); + pool.fixIndexesInPool(); + itemizeAttributes(new DataVectorAttr<>(pool, EAttribute.ATT_ConstantValue). + addAll(fields.stream().map(f -> f.getInitialValue())), + annotAttrInv, annotAttrVis); + uniquifyBootstrapMethods(); + try { + myClassName = coreClasses.getFileName(); + if (environment.isTraceFlag()) { + environment.traceln("ClassFileName = " + myClassName); + environment.traceln("this_class = " + coreClasses.this_class()); + environment.traceln("super_class = " + coreClasses.super_class()); + environment.traceln("-- Constant Pool ---"); + environment.traceln("--------------------"); + pool.printPool(); + environment.traceln("--------------------"); + environment.traceln("-- Inner Classes ---"); + environment.traceln("--------------------"); + printInnerClasses(); + environment.traceln("--------------------"); + } + } catch (Throwable e) { + environment.traceln(() -> "check name:" + e); + environment.error("err.no.classname"); + e.printStackTrace(); + } + } + + public void endPackageInfo() { + coreClasses.this_class(pool.findClassCell(this.myClassName)); + // super_class: class "java/lang/Object" + coreClasses.super_class(pool.findClassCell("java/lang/Object")); + pool.itemizePool(); + coreClasses.super_class(pool.specifyCell(coreClasses.super_class())); + coreClasses.this_class(pool.specifyCell(coreClasses.this_class())); + pool.checkGlobals(); + } + + public void endModule(ModuleAttr moduleAttr) { + moduleAttribute = moduleAttr.build(); + this.myClassName = "module-info"; + coreClasses.this_class(pool.findClassCell(this.myClassName)); + pool.itemizePool(); + coreClasses.this_class(pool.specifyCell(coreClasses.this_class())); + pool.checkGlobals(); + // a module is annotated + itemizeAttributes(annotAttrInv, annotAttrVis); + } + + /** + * Scans all attributes that + * 1. only have cpIndex != 0 and undefined values, types if they are found the method sets their values and types. + * It applies to DataVectorAttr + * 2. only have values and undefined cpIndex if they are found the method finds the identical values in CP and + * assigns their cpIndexes instead of undefined indexes. + * It works for DataVectorAttr + * + * @param attributeList list of attribute's list + */ + private void itemizeAttributes(A... attributeList) { + for (A attributes : attributeList) { + if (attributes != null) { + if (attributes instanceof DataVectorAttr) { + ((DataVectorAttr) attributes).getElements().stream(). + map(e -> (ConstantPoolDataVisitor) e).forEach(v -> v.visit(pool)); + } else if (attributes instanceof AttrData) { + attributes.visit(pool); + } + } + } + } + + private void printInnerClasses() { + if (innerClasses != null) { + int i = 1; + for (InnerClassData entry : innerClasses) { + environment.trace(" InnerClass[" + i++ + "]: (" + EModifier.asNames(entry.access, INNER_CLASS) + "), "); + environment.trace("Name: " + entry.name.toString() + " "); + environment.trace("InnerClass_info: " + entry.innerClass.toString() + " "); + environment.traceln("OuterClass_info: " + entry.outerClass.toString() + " "); + } + } else { + environment.traceln("<< NO INNER CLASSES >>"); + } + } + + public void write(CheckedDataOutputStream out) throws IOException { + // Write the header + out.writeInt(JAVA_MAGIC); + out.writeShort(cfv.minor_version()); + out.writeShort(cfv.major_version()); + + pool.write(out); + out.writeShort(access); // & MM_CLASS; // Q + out.writeShort(coreClasses.this_class().cpIndex); + out.writeShort(coreClasses.super_class().cpIndex); + + // Write the interface names + if (interfaces != null) { + out.writeShort(interfaces.size()); + for (Indexer intf : interfaces) { + out.writeShort(intf.cpIndex); + } + } else { + out.writeShort(0); + } + + // Write the fields + if (fields != null) { + out.writeShort(fields.size()); + for (FieldData field : fields) { + field.write(out); + } + } else { + out.writeShort(0); + } + + // Write the methods + if (methods != null) { + out.writeShort(methods.size()); + for (MethodData method : methods) { + method.write(out); + } + } else { + out.writeShort(0); + } + + // Write the attributes + DataVector attrs = getAttrVector(); + attrs.write(out); + } // end ClassData.write() + + @Override + protected DataVector getAttrVector() { + if (moduleAttribute != null) { + return populateAttributesList(annotAttrVis, annotAttrInv, moduleAttribute); + } else { + return populateAttributesList( + sourceFileAttr, + sourceDebugExtensionAttr, + recordData, // JEP 359 since class file 58.65535 + innerClasses, syntheticAttr, deprecatedAttr, signatureAttr, + annotAttrVis, annotAttrInv, + type_annotAttrVis, type_annotAttrInv, + bootstrapMethodsAttr, + nestHostAttr, nestMembersAttr, // since class version 55.0 + permittedSubclassesAttr, // since class version 59.65535 (JEP 360) + enclosingMethodAttr, + loadableDescriptorsAttr // Valhalla + ); + } + } + + private DataVector populateAttributesList(T... attributes) { + DataVector attrVector = new DataVector(); + for (T attribute : attributes) { + if (attribute != null) { + attrVector.add(attribute); + } + } + return attrVector; + } + + /** + * Writes to the directory passed with -d/-w options + */ + public void write(ToolOutput toolOutput) throws IOException { + try (DataOutputStream dos = toolOutput.getDataOutputStream()) { + cdos.setDataOutputStream(dos); + write(cdos); + } catch (Exception ex) { + if (toolOutput instanceof NamedToolOutput output) { + environment.error("err.cannot.write", output.getName()); + } else { + environment.error("err.cannot.write", "output stream"); + } + throw new IOException(ex); + } + } + + public void setByteLimit(int bytelimit) { + cdos.enable(); + cdos.setLimit(bytelimit); + } + + protected boolean checkExistence(EAttribute attribute) { + return switch (attribute) { + case ATT_Signature -> signatureAttr != null; + case ATT_SourceFile -> sourceFileAttr != null; + case ATT_SourceDebugExtension -> sourceDebugExtensionAttr != null; + case ATT_NestHost -> nestHostAttr != null; + case ATT_NestMembers -> nestMembersAttr != null && nestMembersAttr.size() != 0; + case ATT_PermittedSubclasses -> permittedSubclassesAttr != null && permittedSubclassesAttr.size() != 0; + case ATT_LoadableDescriptors -> loadableDescriptorsAttr != null && loadableDescriptorsAttr.size() != 0; + case ATT_Record -> recordData != null; + case ATT_EnclosingMethod -> enclosingMethodAttr != null; + default -> throw new IllegalStateException("Unexpected attribute: %s in %s". + formatted(attribute.parseKey(), attributeLocation.name())); + }; + } + + protected ClassData checkExistence(EAttribute attribute, long position) { + checkExistence(attribute, + () -> environment.throwErrorException(position, "err.extra.attribute", + attribute.parseKey(), attributeLocation.name())); + return this; + } + + /** + * This is a wrapper for DataOutputStream, used for debugging purposes. it allows + * writing the byte-stream of a class up to a given byte number. + */ + static private class CDOutputStream implements CheckedDataOutputStream { + + public boolean enabled = false; + private int byteLimit; + private DataOutputStream dos; + + public CDOutputStream() { + dos = null; + } + + public CDOutputStream(OutputStream out) { + setOutputStream(out); + } + + public final void setOutputStream(OutputStream out) { + dos = new DataOutputStream(out); + } + + public void setDataOutputStream(DataOutputStream dos) { + this.dos = dos; + } + + public void setLimit(int limit) { + byteLimit = limit; + } + + public void enable() { + enabled = true; + } + + private synchronized void check(String loc) throws IOException { + if (enabled && dos.size() >= byteLimit) { + throw new IOException(loc); + } + } + + @Override + public synchronized void write(int b) throws IOException { + dos.write(b); + check("Writing byte: " + b); + } + + @Override + public synchronized void write(byte b[], int off, int len) throws IOException { + dos.write(b, off, len); + check("Writing byte-array: " + b); + } + + @Override + public final void writeBoolean(boolean v) throws IOException { + dos.writeBoolean(v); + check("Writing writeBoolean: " + (v ? "true" : "false")); + } + + @Override + public final void writeByte(int v) throws IOException { + dos.writeByte(v); + check("Writing writeByte: " + v); + } + + @Override + public void writeShort(int v) throws IOException { + dos.writeShort(v); + check("Writing writeShort: " + v); + } + + @Override + public void writeChar(int v) throws IOException { + dos.writeChar(v); + check("Writing writeChar: " + v); + } + + @Override + public void writeInt(int v) throws IOException { + dos.writeInt(v); + check("Writing writeInt: " + v); + } + + @Override + public void writeLong(long v) throws IOException { + dos.writeLong(v); + check("Writing writeLong: " + v); + } + + @Override + public void writeFloat(float v) throws IOException { + dos.writeFloat(v); + check("Writing writeFloat: " + v); + } + + @Override + public void writeDouble(double v) throws IOException { + dos.writeDouble(v); + check("Writing writeDouble: " + v); + } + + @Override + public void writeBytes(String s) throws IOException { + dos.writeBytes(s); + check("Writing writeBytes: " + s); + } + + @Override + public void writeChars(String s) throws IOException { + dos.writeChars(s); + check("Writing writeChars: " + s); + } + + @Override + public void writeUTF(String s) throws IOException { + dos.writeUTF(s); + check("Writing writeUTF: " + s); + } + } + + /** + * Container holds 2 pairs of core classes: this_class, super_class, and functionality to get output file name. + * jasm supports the values: + * [CLASS_MODIFIERS] class|interface CLASSNAME [ extends SUPERCLASSNAME ] { // HEADER + * this_class[:] (#ID | IDENT); // CLASSNAME CLASSFILE + * super_class[:] (#ID | IDENT); // SUPERCLASSNAME CLASSFILE + */ + public static class CoreClasses { + public enum PLACE { + // A place where this_class, super_class pair is defined. + HEADER, CLASSFILE + } + + private String fileName; + + // This and Super classes are defined on the top in the header: + // [CLASS_MODIFIERS] class|interface CLASSNAME [ extends SUPERCLASSNAME ] { // HEADER + // + // public super class #11 extends #14 version 66:0 + // public super class package/ClassName extends package/SuperClassName version 66:0 + Pair, ConstCell> header = new Pair<>(null, null); + // This and Super classes are defined in a class file: + // this_class[:] (#ID | IDENT); // CLASSNAME CLASSFILE + // super_class[:] (#ID | IDENT); // SUPERCLASSNAME CLASSFILE + // + // this_class #7; // package/ClassName + // super_class java/lang/Object; // java/lang/Object + Pair, ConstCell> classfile = new Pair<>(null, null); + + public void this_class(PLACE where, ConstCell this_class) { + if (where == PLACE.CLASSFILE) { + classfile.first = this_class; + } else { + header.first = this_class; + } + } + + public void super_class(PLACE where, ConstCell super_class) { + if (where == PLACE.CLASSFILE) { + classfile.second = super_class; + } else { + header.second = super_class; + } + } + + public void this_class(ConstCell this_class) { + if (classfile.first != null) { + classfile.first = this_class; + } else { + header.first = this_class; + } + } + + public void super_class(ConstCell super_class) { + if (classfile.second != null) { + classfile.second = super_class; + } else { + header.second = super_class; + } + } + + public ConstCell this_class() { + return (classfile.first != null) ? classfile.first : header.first; + } + + public ConstCell super_class() { + return (classfile.second != null) ? classfile.second : header.second; + } + + public String getFileName() { + if (fileName == null) { + fileName = calculateFileName(); + } + return fileName; + } + + private String calculateFileName() { + if (header.first != null) { + ConstantPool.ConstValue_Class this_class_value = (ConstantPool.ConstValue_Class) header.first.ref; + ConstantPool.ConstValue_UTF8 this_class_name = this_class_value.value.ref; + this.fileName = this_class_name.value; + return this_class_name.value; + } + return null; + } + + /** + * If jasm file contains this_class/super_class value then this value overwrites the class/super class defined on the top: + * "public super class ClassName extends #9 version 66:0 {" + * ie just added to ConstantPool classes: ClassName && #9 should be removed + * + * @param constantPool constant pool + */ + public void cleanConstantPool(ConstantPool constantPool) { + if (classfile.first != null && classfile.first.cpIndex != header.first.cpIndex) { + calculateFileName(); + constantPool.removeClassCell((ConstCell) header.first); + } + if (classfile.second != null && header.second != null && + classfile.second.cpIndex != header.second.cpIndex) { + constantPool.removeClassCell((ConstCell) header.second); + } + } + + public void specifyClasses(ConstantPool constantPool) { + if (header.first != null) + header.first = constantPool.specifyCell(header.first); + if (header.second != null) + header.second = constantPool.specifyCell(header.second); + if (classfile.first != null) + classfile.first = constantPool.specifyCell(classfile.first); + if (classfile.second != null) + classfile.second = constantPool.specifyCell(classfile.second); + } + } +}// end class ClassData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassFileConst.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassFileConst.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassFileConst.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ClassFileConst.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,381 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.PrintWriter; +import java.util.HashMap; + +/** + * ClassFileConst + *

+ * The classes in Tables are following a Singleton Pattern. These classes are Enums, and + * they are contained in private hash maps (lookup tables and reverse lookup tables). + * These hash maps all have public accessors, which clients use to look-up enums. + *

+ * Tokens in this table carry no external state, and are typically treated as constants. + * They do not need to be reset. + */ +public final class ClassFileConst { + + public static final int JAVA_MAGIC = 0xCAFEBABE; + /** + * Lookup-tables for various types. + */ + private static final HashMap NameToSubTag = new HashMap<>(9); + private static final HashMap SubTags = new HashMap<>(9); + + private static final HashMap NameToBasicType = new HashMap<>(10); + private static final HashMap BasicTypes = new HashMap<>(10); + + private static final HashMap AnnotationElementTypes = new HashMap<>(10); + + private static final HashMap NameToConstantType = new HashMap<>(ConstType.maxTag); + private static final HashMap BSMArgumentNameToConstantType = new HashMap<>(ConstType.maxTag); + private static final HashMap ConstantTypes = new HashMap<>(ConstType.maxTag); + + static { + // register all the tokens + for (ConstType ct : ConstType.values()) { + registerConstantType(ct); + } + + /* Type codes for SubTags */ + for (SubTag st : SubTag.values()) { + registerSubtag(st); + } + + /* Type codes for BasicTypes */ + for (BasicType bt : BasicType.values()) { + registerBasicType(bt); + } + + /* Type codes for BasicTypes */ + for (AnnotationElementType aet : AnnotationElementType.values()) { + registerAnnotationElementType(aet); + } + } + + static public ConstType getByTag(int i) { + ConstType constType = ConstantTypes.get(i); + return constType == null ? ConstType.CONSTANT_UNKNOWN : constType; + } + + static public ConstType getByParseKey(String parseKey) { + return NameToConstantType.get(parseKey); + } + + static public ConstType getBSMArgumentTypeByParseKey(String parseKey) { + return BSMArgumentNameToConstantType.get(parseKey); + } + + private static void registerConstantType(ConstType constType) { + NameToConstantType.put(constType.parseKey, constType); + if (constType.isBsmType) { + BSMArgumentNameToConstantType.put(constType.parseKey, constType); + } + if (!ConstantTypes.containsKey(constType.tag)) { + // only first CONSTANT_INTEGER(3, "CONSTANT_INTEGER", "int", AnnotationElementType.AE_INT) + ConstantTypes.put(constType.tag, constType); + } + } + + private static void registerSubtag(SubTag tg) { + NameToSubTag.put(tg.printValue, tg); + SubTags.put(tg.value, tg); + } + + public static SubTag subTag(String subtag) { + return NameToSubTag.get(subtag); + } + + public static SubTag subTag(int subtag) { + return SubTags.get(subtag); + } + + private static void registerBasicType(BasicType basicType) { + NameToBasicType.put(basicType.printValue, basicType); + BasicTypes.put(basicType.value, basicType); + } + + public static BasicType getBasicType(String idValue) { + return NameToBasicType.get(idValue); + } + + public static BasicType getBasicType(int subtag) { + return BasicTypes.get(subtag); + } + + public static int basicTypeValue(String idValue) { + int retval = -1; + BasicType tg = NameToBasicType.get(idValue); + if (tg != null) { + retval = tg.value; + } + return retval; + } + + private static void registerAnnotationElementType(AnnotationElementType annotationElementType) { + // NameToAnnotationElementType.put(annotationElementType.printValue, annotationElementType); + AnnotationElementTypes.put(annotationElementType.value.charAt(0), annotationElementType); + } + + public static AnnotationElementType getAnnotationElementType(char subTag) { + AnnotationElementType elementType = AnnotationElementTypes.get(subTag); + if (elementType == null) { + elementType = AnnotationElementType.AE_UNKNOWN; + } + return elementType; + } + + /** + * A (typed) tag (constant) representing the type of Constant in the Constant Pool. + */ + public enum ConstType { + CONSTANT_UNKNOWN(-1, "CONSTANT_UNKNOWN", "", AnnotationElementType.AE_NOT_APPLICABLE, false), + // + CONSTANT_ZERO(0, "CONSTANT_ZERO", "", AnnotationElementType.AE_NOT_APPLICABLE, false), + CONSTANT_UTF8(1, "CONSTANT_UTF8", "Utf8", AnnotationElementType.AE_STRING, true), + CONSTANT_ASCIZ(1, "CONSTANT_UTF8", "Asciz", AnnotationElementType.AE_STRING, true), // supports previous version + // Constant 2 reserved + CONSTANT_INTEGER(3, "CONSTANT_INTEGER", "Integer", AnnotationElementType.AE_INT, true), + CONSTANT_INT(3, "CONSTANT_INTEGER", AnnotationElementType.AE_INT.printValue, AnnotationElementType.AE_INT, true), + CONSTANT_BYTE(3, "CONSTANT_INTEGER", AnnotationElementType.AE_BYTE.printValue, AnnotationElementType.AE_BYTE, true), + CONSTANT_C_BYTE(3, "CONSTANT_INTEGER", "Byte", AnnotationElementType.AE_BYTE, true), + CONSTANT_CHAR(3, "CONSTANT_INTEGER", AnnotationElementType.AE_CHAR.printValue, AnnotationElementType.AE_CHAR, true), + CONSTANT_C_CHAR(3, "CONSTANT_INTEGER", "Char", AnnotationElementType.AE_CHAR, true), + CONSTANT_SHORT(3, "CONSTANT_INTEGER", AnnotationElementType.AE_SHORT.printValue, AnnotationElementType.AE_SHORT, true), + CONSTANT_C_SHORT(3, "CONSTANT_INTEGER", "Short", AnnotationElementType.AE_SHORT, true), + CONSTANT_BOOLEAN(3, "CONSTANT_INTEGER", AnnotationElementType.AE_BOOLEAN.printValue, AnnotationElementType.AE_BOOLEAN, true), + CONSTANT_C_BOOLEAN(3, "CONSTANT_INTEGER", "Boolean", AnnotationElementType.AE_BOOLEAN, true), + + CONSTANT_C_FLOAT(4, "CONSTANT_FLOAT", "Float", AnnotationElementType.AE_FLOAT, true), + CONSTANT_FLOAT(4, "CONSTANT_FLOAT", "float", AnnotationElementType.AE_FLOAT, true), + + CONSTANT_C_LONG(5, "CONSTANT_LONG", "Long", AnnotationElementType.AE_LONG, true), + CONSTANT_LONG(5, "CONSTANT_LONG", "long", AnnotationElementType.AE_LONG, true), + + CONSTANT_C_DOUBLE(6, "CONSTANT_DOUBLE", "Double", AnnotationElementType.AE_DOUBLE, true), + CONSTANT_DOUBLE(6, "CONSTANT_DOUBLE", "double", AnnotationElementType.AE_DOUBLE, true), + + CONSTANT_C_CLASS(7, "CONSTANT_CLASS", "Class", AnnotationElementType.AE_CLASS, true), + CONSTANT_CLASS(7, "CONSTANT_CLASS", "class", AnnotationElementType.AE_CLASS, true), + + CONSTANT_STRING(8, "CONSTANT_STRING", "String", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_L_STRING(8, "CONSTANT_STRING", "string", AnnotationElementType.AE_NOT_APPLICABLE, false), + + CONSTANT_FIELD(9, "CONSTANT_FIELD", "Field", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_FIELDREF(9, "CONSTANT_FIELDREF", "Fieldref", AnnotationElementType.AE_NOT_APPLICABLE, true), + + CONSTANT_METHOD(10, "CONSTANT_METHOD", "Method", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_METHODREF(10, "CONSTANT_METHODREF", "Methodref", AnnotationElementType.AE_NOT_APPLICABLE, true), + + CONSTANT_INTERFACEMETHOD(11, "CONSTANT_INTERFACEMETHOD", "InterfaceMethod", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_INTERFACEMETHODREF(11, "CONSTANT_INTERFACEMETHODREF", "InterfaceMethodref", AnnotationElementType.AE_NOT_APPLICABLE, true), + + CONSTANT_NAMEANDTYPE(12, "CONSTANT_NAMEANDTYPE", "NameAndType", AnnotationElementType.AE_NOT_APPLICABLE, true), + // Constant 13 reserved + // Constant 14 reserved + CONSTANT_METHODHANDLE(15, "CONSTANT_METHODHANDLE", "MethodHandle", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_METHODTYPE(16, "CONSTANT_METHODTYPE", "MethodType", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_DYNAMIC(17, "CONSTANT_DYNAMIC", "Dynamic", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_INVOKEDYNAMIC(18, "CONSTANT_INVOKEDYNAMIC", "InvokeDynamic", AnnotationElementType.AE_NOT_APPLICABLE, true), + + CONSTANT_MODULE(19, "CONSTANT_MODULE", "Module", AnnotationElementType.AE_NOT_APPLICABLE, true), + CONSTANT_PACKAGE(20, "CONSTANT_PACKAGE", "Package", AnnotationElementType.AE_NOT_APPLICABLE, true); + + static final public int maxTag = 20; + + private final int tag; + private final String printVal; + private final String parseKey; + private final AnnotationElementType annotationElementType; + private final boolean isBsmType; + + public boolean equals(ConstType other) { + if (other != null) { + return this.tag == other.tag; + } + return false; + } + + ConstType(int tag, String printVal, String parseKey, AnnotationElementType annotationElementType, boolean isBsmType) { + this.tag = tag; + this.printVal = printVal; + this.parseKey = parseKey; + this.annotationElementType = annotationElementType; + this.isBsmType = isBsmType; + } + + public boolean oneOf(ConstType... constTypes) { + for (ConstType constType : constTypes) { + if (this.tag == constType.tag) { + return true; + } + } + return false; + } + + /** + * The tag item uses a single ASCII character to indicate the type of the value of the element-value pair. + * This determines which item of the value union is in use. Table 4.7.16.1-A shows the valid characters + * for the tag item. + * + * @return a single ASCII character + */ + public char getAnnotationElementTypeValue() { + return annotationElementType.tag(); + } + + public byte getTag() { + return (byte) tag; + } + + public String parseKey() { + return parseKey; + } + + public String printVal() { + return printVal; + } + + public void print(PrintWriter out) { + out.print(parseKey); + } + + @Override + public String toString() { + return printVal + "." + tag; + } + } + + /** + * Annotation Element Type enums + * Table 4.7.16.1-A. Interpretation of tag values as types + */ + public enum AnnotationElementType { + AE_BYTE("B", "byte"), + AE_CHAR("C", "char"), + AE_SHORT("S", "short"), + AE_INT("I", "int"), + AE_LONG("J", "long"), + AE_FLOAT("F", "float"), + AE_DOUBLE("D", "double"), + AE_BOOLEAN("Z", "boolean"), + AE_STRING("s", "string"), + AE_ENUM("e", "enum"), + AE_CLASS("c", "class"), + AE_ANNOTATION("@", "annotation"), + AE_ARRAY("[", "array"), + AE_UNKNOWN("U", "unknown"), + AE_NOT_APPLICABLE("N", "not applicable"); + + private final String value; + private final String printValue; + + AnnotationElementType(String value, String printValue) { + this.value = value; + this.printValue = printValue; + } + + public String value() { + return value; + } + + public String printValue() { + return printValue; + } + + /** + * The tag item uses a single ASCII character to indicate the type of the value of the element-value pair. + * This determines which item of the value union is in use. Table 4.7.16.1-A shows the valid characters + * for the tag item. + * + * @return a single ASCII character + */ + public char tag() { + return value.charAt(0); + } + + public static boolean isSet(char tagChar) { + return AE_NOT_APPLICABLE.tag() != tagChar && AE_UNKNOWN.tag() != tagChar; + } + } + + /** + * SubTag enums + */ + public enum SubTag { + REF_GETFIELD(1, "REF_getField"), + REF_GETSTATIC(2, "REF_getStatic"), + REF_PUTFIELD(3, "REF_putField"), + REF_PUTSTATIC(4, "REF_putStatic"), + REF_INVOKEVIRTUAL(5, "REF_invokeVirtual"), + REF_INVOKESTATIC(6, "REF_invokeStatic"), + REF_INVOKESPECIAL(7, "REF_invokeSpecial"), + REF_NEWINVOKESPECIAL(8, "REF_newInvokeSpecial"), + REF_INVOKEINTERFACE(9, "REF_invokeInterface"); + + private final Integer value; + private final String printValue; + + SubTag(Integer val, String print) { + value = val; + printValue = print; + } + + public String printValue() { + return printValue; + } + + public Integer value() { + return value; + } + } + + /** + * BasicType enums + */ + public enum BasicType { + T_INT(0x0000000a, "int"), + T_LONG(0x0000000b, "long"), + T_FLOAT(0x00000006, "float"), + T_DOUBLE(0x00000007, "double"), + T_CLASS(0x00000002, "class"), + T_BOOLEAN(0x00000004, "boolean"), + T_CHAR(0x00000005, "char"), + T_BYTE(0x00000008, "byte"), + T_SHORT(0x00000009, "short"); + + private final Integer value; + private final String printValue; + + BasicType(Integer value, String printValue) { + this.value = value; + this.printValue = printValue; + } + + public String printValue() { + return printValue; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CodeAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CodeAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CodeAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/CodeAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,547 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + + +import org.openjdk.asmtools.common.SyntaxError; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.jasm.OpcodeTables.Opcode; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import static java.lang.Math.max; +import static org.openjdk.asmtools.common.structure.EAttribute.ATT_StackMap; +import static org.openjdk.asmtools.common.structure.EAttribute.ATT_StackMapTable; +import static org.openjdk.asmtools.jasm.OpcodeTables.MAX_LOOKUPSWITCH_LENGTH; +import static org.openjdk.asmtools.jasm.OpcodeTables.MAX_TABLESWITCH_LENGTH; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode.opc_lookupswitch; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode.opc_tableswitch; + +/** + * 4.7.3. The Code Attribute + *

+ * Code_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 max_stack; + * u2 max_locals; + * u4 code_length; + * u1 code[code_length]; + * u2 exception_table_length; + * { u2 start_pc; + * u2 end_pc; + * u2 handler_pc; + * u2 catch_type; + * } exception_table[exception_table_length]; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + * } + */ +class CodeAttr extends AttrData { + protected final List locVarSlots; + protected final List locVarTypeSlots; + private final LocalVariableData VACANT = null; + // reference to the surrounding data containers + protected ClassData classData; + protected MethodData methodData; + protected JasmEnvironment environment; + + protected Indexer max_stack, max_locals; + protected Instr zeroInstr, lastInstr; + protected int curPC = 0; + protected DataVector exceptionTable; + protected DataVectorAttr lineNumberTable; + protected long lastLineNumber = 0; + protected DataVectorAttr localVariableTable; + protected DataVectorAttr localVariableTypeTable; + + protected DataVector> attributes; + protected HashMap labelsHash; + protected HashMap trapsHash; + protected List stackMapEntries = new ArrayList<>(); + protected DataVectorAttr stackMapTable; + // type annotations + protected DataVectorAttr visTypeAnnotations = null; + protected DataVectorAttr inVisTypeAnnotations = null; + + public CodeAttr(MethodData methodData, int paramCount, Indexer max_stack, Indexer max_locals) { + super(methodData.pool, EAttribute.ATT_Code); + this.methodData = methodData; + this.classData = methodData.classData; + this.environment = methodData.getEnvironment(); + this.max_stack = max_stack; + this.max_locals = max_locals; + this.locVarSlots = new ArrayList<>(Collections.nCopies(max_locals != null ? max_locals.value() : paramCount, VACANT)); + this.locVarTypeSlots = new ArrayList<>(Collections.nCopies(max_locals != null ? max_locals.value() : paramCount, VACANT)); + lastInstr = zeroInstr = new Instr(methodData, environment); + exceptionTable = new DataVector<>(0); // TrapData + attributes = new DataVector<>(); + if (environment.getVerboseFlag()) { + lineNumberTable = new DataVectorAttr<>(methodData.pool, EAttribute.ATT_LineNumberTable); + attributes.add(lineNumberTable); + } + } + + void endCode() { + checkTraps(); + checkLocVars(Opcode.opc_var); + checkLocVars(Opcode.opc_type); + checkLabels(); + // + if (visTypeAnnotations != null) { + attributes.add(visTypeAnnotations); + } + if (inVisTypeAnnotations != null) { + attributes.add(inVisTypeAnnotations); + } + } + + public void addAnnotations(ArrayList list) { + for (AnnotationData item : list) { + boolean invisible = item.invisible; + if (item instanceof TypeAnnotationData typeAnnotationData) { + // Type Annotations + if (invisible) { + if (inVisTypeAnnotations == null) { + inVisTypeAnnotations = new DataVectorAttr<>(methodData.pool, EAttribute.ATT_RuntimeInvisibleTypeAnnotations); + } + inVisTypeAnnotations.add(typeAnnotationData); + } else { + if (this.visTypeAnnotations == null) { + this.visTypeAnnotations = new DataVectorAttr<>(methodData.pool, EAttribute.ATT_RuntimeVisibleTypeAnnotations); + } + this.visTypeAnnotations.add(typeAnnotationData); + } + } + } + } + + public void fillLineTable(List list) { + if (lineNumberTable != null) { + // Remove the automatically generated LineTable by jasm and instead, + // include a table inline within the jasm source. + lineNumberTable.clear(); + } else { + lineNumberTable = new DataVectorAttr<>(methodData.pool, EAttribute.ATT_LineNumberTable); + attributes.add(lineNumberTable); + } + lineNumberTable.addAll(list); + } + + /** + * Fills either localVariableTable or localVariableTypeTable according to the boolean parameter isTypeTable + * + * @param isTypeTable defines which localVariableTypeTable or localVariableTable is filled + * @param list list of local_variable_table[i] or local_variable_type_table[i] entries + */ + public void fillLocalVariableTable(boolean isTypeTable, List list) { + DataVectorAttr vector = (isTypeTable) ? localVariableTypeTable : localVariableTable; + if (vector == null) { + vector = new DataVectorAttr<>(methodData.pool, (isTypeTable) ? EAttribute.ATT_LocalVariableTypeTable : EAttribute.ATT_LocalVariableTable); + attributes.add(vector); + } + vector.addAll(list); + } + + public void fillStackMapTable(List list) { + if (stackMapTable == null) { + DataVectorAttr table = (DataVectorAttr) attributes. + findFirst(item -> item.getAttribute(). + isOneOf(ATT_StackMapTable, ATT_StackMap)).orElse(null); + if (table == null) { + stackMapTable = new DataVectorAttr<>(classData.pool, classData.cfv.isTypeCheckingVerifier() ? ATT_StackMapTable : ATT_StackMap); + attributes.add(stackMapTable); + } else { + stackMapTable = table; + } + } + stackMapTable.addAll(list); + } + + /* -------------------------------------- Traps */ + RangePC trapDecl(long pos, String name) { + RangePC local; + if (trapsHash == null) { + trapsHash = new HashMap<>(10); + local = null; + } else { + local = trapsHash.get(name); + } + if (local == null) { + local = new RangePC(pos, name); + trapsHash.put(name, local); + } + return local; + } + + void beginTrap(long pos, String name) { + RangePC rangePC = trapDecl(pos, name); + if (rangePC.start_pc != Indexer.NotSet) { + environment.error("err.trap.tryredecl", name); + return; + } + rangePC.start_pc = curPC; + } + + void endTrap(long pos, String name) { + RangePC rangePC = trapDecl(pos, name); + if (rangePC.end_pc != Indexer.NotSet) { + environment.error("err.trap.endtryredecl", name); + return; + } + rangePC.end_pc = curPC; + } + + void trapHandler(long pos, String name, Indexer type) { + RangePC rangePC = trapDecl(pos, name); + rangePC.isReferred = true; + ExceptionData exceptionData = new ExceptionData(pos, rangePC, curPC, type); + exceptionTable.addElement(exceptionData); + } + + void checkTraps() { + if (trapsHash == null) { + return; + } + for (RangePC rangePC : trapsHash.values()) { + if (!rangePC.isReferred) { + environment.warning(rangePC.pos, "warn.trap.notref", rangePC.name); + } + } + + for (ExceptionData exceptionData : exceptionTable) { + RangePC rangePCLabel = exceptionData.rangePC; + if (rangePCLabel.start_pc == Indexer.NotSet) { + environment.error(exceptionData.pos, "err.trap.notry", rangePCLabel.name); + } + if (rangePCLabel.end_pc == Indexer.NotSet) { + environment.error(exceptionData.pos, "err.trap.noendtry", rangePCLabel.name); + } + } + } + + // Labels + Label labelDecl(String name) { + Label local; + if (labelsHash == null) { + labelsHash = new HashMap<>(10); + local = null; + } else { + local = labelsHash.get(name); + } + if (local == null) { + local = new Label(name); + labelsHash.put(name, local); + } + return local; + } + + public Label LabelDef(long pos, String name) { + Label label = labelDecl(name); + if (label.isDefined) { + environment.error(pos, "err.label.redecl", name); + return null; + } + label.isDefined = true; + label.cpIndex = curPC; + return label; + } + + public Label LabelRef(String name) { + Label label = labelDecl(name); + label.isReferred = true; + return label; + } + + void checkLabels() { + if (labelsHash == null) { + return; + } + for (Label local : labelsHash.values()) { + // check that every label is defined + if (!local.isDefined) { + environment.error("err.label.undecl", local.name); + } + } + } + +// LocalVariables + + /** + * Constructs the local variable nameCell:descriptorCell assigned to the slot index. + * + * @param opcode var or type opcode that defines type of filled table -LocalVariableTypeTable or LocalVariableTable + * @param position scanners' position to navigate where a syntax error happened if any + * @param index a valid index into the local variable array of the current frame + * @param nameCell valid unqualified name denoting a local variable + * @param descriptorCell a field descriptor which encodes a type of local variable in the source program + */ + public void LocVarDataDef(OpcodeTables.Opcode opcode, long position, int index, ConstCell nameCell, ConstCell descriptorCell) { + FieldType fieldType = null; + List slots; + LocalVariableData localVariableData = new LocalVariableData((short) index, (short) curPC, nameCell, descriptorCell); + if (opcode == Opcode.opc_var) { + slots = locVarSlots; + fieldType = localVariableData.getFieldType(); + if (localVariableTable == null) { + localVariableTable = new DataVectorAttr<>(methodData.pool, EAttribute.ATT_LocalVariableTable); + attributes.add(localVariableTable); + } + localVariableTable.add(localVariableData); + } else { + slots = locVarTypeSlots; + if (localVariableTable != null) { + LocalVariableData lvd = localVariableTable.findFirst(lv -> lv.getIndex() == index).orElse(null); + if (lvd != null) { + fieldType = lvd.getFieldType(); + } + } + if (localVariableTypeTable == null) { + localVariableTypeTable = new DataVectorAttr<>(methodData.pool, EAttribute.ATT_LocalVariableTypeTable); + attributes.add(localVariableTypeTable); + } + localVariableTypeTable.add(localVariableData); + } + if (fieldType == null) { + environment.throwErrorException(position, "err.fieldType.undecl", index); + } else { + localVariableData.setFieldType(fieldType); + // check slot availability + //If the given local variable is of type double or long, it occupies both index and index + 1 + for (int i = 0; i < fieldType.getSlotsCount(); i++) { + if (!max_locals.inRange(index + i)) { + environment.throwErrorException(position, "err.locvar.wrong.index", index + i, max_locals.value() - 1); + } + + if (slots.get(index + i) != VACANT) { + environment.throwErrorException(position, "err.locvar.slot.occupied", index + i); + } + slots.set(index + i, localVariableData); // OCCUPIED + } + } + } + + /** + * Marks the end of Local Variable (Type) presented in the form endVar index: locVarSlots[slot] = VACANT + * and sets the Length of the Local Var + * + * @param position the position of the scanner + * @param slot The value of the index item is a valid index into the local variable array of the current frame. + */ + public void LocVarDataEnd(OpcodeTables.Opcode opcode, short slot, long position) { + if (!max_locals.inRange(slot)) { + environment.throwErrorException(position, "err.locvar.wrong.index", slot, max_locals.value() - 1); + } + final LocalVariableData localVariableData = (opcode == Opcode.opc_var) ? locVarSlots.get(slot) : locVarTypeSlots.get(slot); + if (localVariableData == VACANT) { + environment.throwErrorException(position, "err.locvar.undecl", slot); + } else { + localVariableData.setLength(curPC); + // Check slot availability and clean up appropriate locVarSlots[slot{,slot+1}] or locVarTypeSlots[slot{,slot+1}] + // If the given local variable is of type double or long, it occupies both index and index + 1 + List slots = (opcode == Opcode.opc_var) ? locVarSlots : locVarTypeSlots; + + for (int i = 0; i < localVariableData.getSlotsCount(); i++) { + if (i > 0 && !max_locals.inRange(slot + i)) { + environment.error(position, "err.locvar.wrong.index", slot + i, max_locals.value() - 1); + throw new SyntaxError(); + } + if (i > 0 && slots.get(slot + i) == VACANT) { + environment.error(position, "err.locvar.undecl", slot + i); + throw new SyntaxError(); + } + slots.set(slot + i, VACANT); + } + } + } + + void checkLocVars(OpcodeTables.Opcode opcode) { + List slots = (opcode == Opcode.opc_var) ? locVarSlots : locVarTypeSlots; + for (int i = 0; i < slots.size(); i++) { + if (slots.get(i) != VACANT) { + slots.get(i).setLength(curPC); + environment.warning(environment.getPosition(), (opcode == Opcode.opc_var) ? "warn.locvar.ambiqous" : + "warn.loctype.ambiqous", i); + } + } + } + + // The StackMap + public StackMapData getStackMapTable() { + StackMapData entry; + int len = stackMapEntries.size(); + if (len == 0) { + entry = new StackMapData(environment, isTypeCheckingVerifier()); + stackMapEntries.add(entry); + } else { + entry = stackMapEntries.get(len - 1); + } + return entry; + } + + public StackMapData getNextStackMapTable() { + StackMapData entry = new StackMapData(environment, isTypeCheckingVerifier()); + stackMapEntries.add(entry); + return entry; + } + + // A class file whose version number is 50.0 or above (§4.1) must be verified using the type checking rules given + // in the section 4.10.1. Verification by Type Checking + public boolean isTypeCheckingVerifier() { + return classData.cfv.isTypeCheckingVerifier(); + } + + // Instructions + void addInstr(long mnenoc_pos, Opcode opcode, Indexer arg, Object arg2) { + Instr newInstr = new Instr(methodData, environment).set(curPC, environment.getPosition(), opcode, arg, arg2); + lastInstr.next = newInstr; + lastInstr = newInstr; + int len = opcode.length(); + switch (opcode) { + case opc_tableswitch: + len = ((SwitchTable) arg2).recalcTableSwitch(curPC); + if (len >= MAX_TABLESWITCH_LENGTH) { + environment.error(mnenoc_pos, "err.instr.oversize", + opc_tableswitch.parseKey(), len, MAX_TABLESWITCH_LENGTH); + } + break; + case opc_lookupswitch: + len = ((SwitchTable) arg2).calcLookupSwitch(curPC); + if (len >= MAX_LOOKUPSWITCH_LENGTH) { + environment.error(mnenoc_pos, "err.instr.oversize", + opc_lookupswitch.parseKey(), len, MAX_LOOKUPSWITCH_LENGTH); + } + break; + case opc_ldc: + ((ConstCell) arg).setRank(ConstantPool.ReferenceRank.LDC); + break; + default: + if (arg instanceof ConstCell) { + ConstantPool.ReferenceRank rank = ((ConstCell) arg).rank; + if (rank != ConstantPool.ReferenceRank.LDC) { + ((ConstCell) arg).setRank(ConstantPool.ReferenceRank.ANY); + } + } + } + if (environment.getVerboseFlag()) { + long ln = environment.lineNumber(mnenoc_pos); + if (ln != lastLineNumber) { // only one entry in lineNumberTable per line + lineNumberTable.add(new LineNumberData(curPC, ln)); + lastLineNumber = ln; + } + } + if (!stackMapEntries.isEmpty()) { + StackMapData prevStackFrame = getPreviousStackMapEntry(); + for (StackMapData entry : stackMapEntries) { + if (!entry.isWrapper()) { + entry.setPC(curPC); + entry.setOffset(prevStackFrame); + } + } + stackMapTable.addAll(stackMapEntries); + stackMapEntries.clear(); + } + curPC += len; + } + + private StackMapData getPreviousStackMapEntry() { + if (stackMapTable == null) { + stackMapTable = new DataVectorAttr<>(classData.pool, + classData.cfv.isTypeCheckingVerifier() ? ATT_StackMapTable : ATT_StackMap); + attributes.add(stackMapTable); + } else if (!stackMapTable.isEmpty()) { + for (int i = stackMapTable.size() - 1; i >= 0; i--) { + StackMapData entry = stackMapTable.get(i); + if (!entry.isWrapper()) { + return entry; + } + } + } + return null; + } + + + @Override + public int attrLength() { + return 2 + 2 + 4 // for max_stack, max_locals, and cur_pc + + curPC // + 2+trap_table.size()*8 + + exceptionTable.getLength() + attributes.getLength(); + } + + @Override + public void write(CheckedDataOutputStream out) + throws IOException, Parser.CompilerError { + int maxStack = (max_stack != null) ? max_stack.cpIndex : 0; + int maxLocals = (max_locals != null) ? max_locals.cpIndex : max(locVarSlots.size(), locVarTypeSlots.size()); + super.write(out); // attr name, attr len + out.writeShort(maxStack); + out.writeShort(maxLocals); + out.writeInt(curPC); + for (Instr instr = zeroInstr.next; instr != null; instr = instr.next) { + instr.write(out); + } + exceptionTable.write(out); + attributes.write(out); + } + + /** + * Checks if the code attribute is empty, i.e., it contains no instructions. + * + * @return true if the code attribute is empty, false otherwise + */ + public boolean isEmpty() { + return curPC == 0; + } + + /* CodeAttr inner classes */ + static public class Local extends Indexer { + String name; + boolean isDefined = false, isReferred = false; + + public Local(String name) { + this.name = name; + } + } + + static public class Label extends Local { + public Label(String name) { + super(name); + } + } + + static class RangePC extends Local { + int start_pc = Indexer.NotSet; + int end_pc = Indexer.NotSet; + long pos; + + RangePC(long pos, String name) { + super(name); + this.pos = pos; + } + } + +} // end CodeAttr diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstCell.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstCell.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstCell.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstCell.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; +import java.util.Objects; + +/** + * ConstantCell is a type of data that can be in a constant pool. + */ +public class ConstCell extends Indexer implements ConstantPoolDataVisitor { + + V ref; + // 0 - highest - ref from ldc, 1 - any ref, 2 - no ref + ConstantPool.ReferenceRank rank = ConstantPool.ReferenceRank.NO; + // status flag + private int flag; + + ConstCell(int id, V ref) { + this.cpIndex = id; + this.ref = ref; + } + + ConstCell(V ref) { + this(NotSet, ref); + } + + ConstCell(int id) { + this(id, null); + } + + public int getFlag() { + return flag; + } + public ConstCell setFlag(int flag) { + this.flag = flag; + return this; + } + + @Override + public final boolean isSet() { + return super.isSet() && + ((this.ref != null && this.ref.value != null) || + (ref instanceof ConstantPool.ConstValue_Zero)); + } + + public ClassFileConst.ConstType getType() { + return ref == null ? ClassFileConst.ConstType.CONSTANT_UNKNOWN : ref.tag; + } + + public char getAnnotationElementTypeValue() { + return ref == null ? ClassFileConst.AnnotationElementType.AE_NOT_APPLICABLE.tag() : + ref.tag.getAnnotationElementTypeValue(); + } + + @Override + public int getLength() { + return 2; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(cpIndex); + } + + public void setRank(ConstantPool.ReferenceRank rank) { + // don't change a short ref to long due to limitation of ldc - max 256 indexes allowed + // ConstantPool.ReferenceRank.LDC has high priority + if (this.rank.priority > rank.priority) { + this.rank = rank; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstCell)) return false; + ConstCell constCell = (ConstCell) obj; + return (Objects.equals(ref, constCell.ref) && rank == constCell.rank && cpIndex == constCell.cpIndex); + } + + public boolean equalsByValue(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstCell)) return false; + ConstCell constCell = (ConstCell) obj; + // (a == b) || (a != null && a.equals(b)) + if (this.ref == constCell.ref) return true; + if (this.ref != null && ref instanceof ConstValue) { + if (constCell.ref instanceof ConstValue) { + return this.ref.equalsByValue(constCell.ref); + } + return false; + } else { + return Objects.equals(ref, constCell.ref); + } + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * (result + (ref != null ? ref.hashCode() : 0)); + return result; + } + + @Override + public String toString() { + return "#" + ((cpIndex == NotSet) ? "?" : cpIndex) + "=" + ref; + } + + @Override + public T visit(ConstantPool pool) { + return visitConstCell(this, pool); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstValue.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstValue.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstValue.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstValue.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; + +/** + * A (typed) tagged value in the constant pool like ConstCell + */ +public abstract class ConstValue { + + protected T value; + protected final ClassFileConst.ConstType tag; + + public ConstValue(ClassFileConst.ConstType tag, T value) { + this.tag = tag; + this.value = value; + } + + public int size() { + return 1; + } + + public boolean isSet() { return value != null; } + + public ConstValue setValue(T value) { + this.value = value; + return this; + } + + @Override + public int hashCode() { + int result = value != null ? value.hashCode() : 0; + result = 31 * result + tag.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue)) return false; + ConstValue that = (ConstValue) obj; + return (this.value.equals(that.value) && this.tag == that.tag); + } + + public boolean equalsByValue(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue)) return false; + ConstValue that = (ConstValue) obj; + if( this.value instanceof ConstCell ) { + if( that.value instanceof ConstCell ) { + return (((ConstCell)this.value).equalsByValue(that.value) && this.tag == that.tag); + } + return false; + } + return (this.value.equals(that.value) && this.tag == that.tag); + } + + @Override + public String toString() { + return String.format("[%s : '%s']", tag.toString(), asString() ) ; + } + + /** + * @return String presentation of the value. + */ + public String asString() { + return (value == null) ? "?" : value.toString(); + } + + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(tag.getTag()); + } +} // end ConstValue diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,1071 @@ +/* + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.asmutils.Range; +import org.openjdk.asmtools.jasm.ClassFileConst.ConstType; + +import java.io.IOException; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static java.lang.Math.max; +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.*; + +/** + * ConstantPool is the class responsible for maintaining constants for a given class file. + */ +public class ConstantPool implements Iterable> { + + static final int PROCESSED = 2; + static final int NON_PROCESSED = 0; + + private final ConstValue_UTF8 emptyConstValue = new ConstValue_UTF8(""); + private final ConstCell nullConst = new ConstCell(null); + private final ConstCell zeroConst = new ConstCell(new ConstValue_Zero()); + // For hashing by value + private final ArrayList> pool = new ArrayList<>(40); + public JasmEnvironment environment; + public LinkedHashMap, ConstCell> ConstantPoolHashByValue = new LinkedHashMap<>(40); + + private final CPVisitor indexFixerConstantPool = new CPVisitor() { + @Override + public void visitConstValueCell(ConstValue_Cell constValue) { + handleClassIndex(constValue); + } + + @Override + public void visitConstValueRefCell(ConstValue_Pair constValue) { + handleMemberIndex(constValue); + } + + @Override + public void visitMethodHandle(ConstValue_MethodHandle constValue) { + handleIndexCell((ConstCell) constValue.value); + } + }, referenceFixerConstantPool = new CPVisitor() { + @Override + public void visitConstValueCell(ConstValue_Cell constValue) { + handleClassRef(constValue); + } + + @Override + public void visitConstValueRefCell(ConstValue_Pair constValue) { + handleMemberRef(constValue); + } + + @Override + public void visitMethodHandle(ConstValue_MethodHandle constValue) { + handleRefCell((ConstCell) constValue.value); + } + }; + + /** + * Main constructor + * + * @param environment The error reporting environment + */ + public ConstantPool(JasmEnvironment environment) { + this.environment = environment; + pool.add(zeroConst); + } + + @Override + public Iterator> iterator() { + return pool.iterator(); + } + + protected void handleClassRef(ConstValue_Cell cell) { + ConstCell refCell = (ConstCell) cell.value; + if (handleRefCell(refCell)) { + environment.traceln(() -> "FIXED ConstPool[" + refCell.cpIndex + "](" + cell.tag.toString() + ") = " + cell.value); + } + } + + protected void handleMemberRef(ConstValue_Pair cv) { + Pair pair = (Pair) cv.value; + if (handleRefCell(pair.first)) { + environment.traceln(() -> "FIXED Left:ConstPool[" + pair.first.cpIndex + "](" + cv.tag.toString() + ") = " + pair.first.ref); + } + if (handleRefCell(pair.second)) { + environment.traceln(() -> "FIXED Right:ConstPool[" + pair.second.cpIndex + "](" + cv.tag.toString() + ") = " + pair.second.ref); + } + } + + /** + * Updates reference cell if there is cpIndex but a cell is not attached. + * + * @param refCell a constant cell + * @return true if the cell is fixed + */ + private boolean handleRefCell(ConstCell refCell) { + if (refCell.ref == null) { + ConstCell refVal = getConstPollCellByIndex(refCell.cpIndex); + if (refVal != null) { + checkAndFixCPRef(refVal); + refCell.ref = refVal.ref; + return true; + } + } + return false; + } + + protected void handleClassIndex(ConstValue_Cell cell) { + ConstCell refCell = (ConstCell) cell.value; + if (handleIndexCell(refCell)) { + environment.traceln(() -> "FIXED Index of ConstPool[" + refCell.cpIndex + "](" + cell.tag.toString() + ") = " + cell.value); + } + } + + protected void handleMemberIndex(ConstValue_Pair cv) { + Pair pair = (Pair) cv.value; + if (handleIndexCell(pair.first)) { + environment.traceln(() -> "FIXED Index of Left:ConstPool[" + pair.first.cpIndex + "](" + cv.tag.toString() + ") = " + pair.first.ref); + } + if (handleIndexCell(pair.second)) { + environment.traceln(() -> "FIXED Index of Right:ConstPool[" + pair.second.cpIndex + "](" + cv.tag.toString() + ") = " + pair.second.ref); + } + } + + /** + * Updates reference cell if there is an attached cell but cpIndex is missing. + * + * @param refCell a constant cell + * @return true if the cell is fixed + */ + private boolean handleIndexCell(ConstCell refCell) { + if (refCell.ref != null && !refCell.isSet()) { + Optional> cell = getItemizedCell(refCell); + if (cell.isPresent()) { + refCell.cpIndex = cell.get().cpIndex; + return true; + } + } + return false; + } + + /* + * Fix Refs in constant pool. + * + * This is used when scanning JASM files produced from JDis with the verbose + * option (eg. where the constant pool is declared in the jasm itself). In + * this scenario, we need two passes - the first pass to scan the entries + * (which creates constant references with indexes, but no reference values); + * and the second pass, which links references to existing constants. + */ + public void fixRefsInPool() { + // Simply iterating through the pool the method is used to fix CP refs + // when a constant pool is constructed by refs alone. + environment.traceln("fixRefsInPool: Fixing CP for %d explicit Constant Entries", pool.size()); + for (ConstCell item : pool) { + checkAndFixCPRef(item); + } + } + + /* + * Fix Indexes in constant pool. + */ + public void fixIndexesInPool() { + // Simply iterate through the pool the method is used to fix CP Indexes + // when a constant pool is constructed by values alone. + environment.traceln("fixIndexesInPool: Fixing CP for %d explicit Constant Entries.", pool.size()); + for (ConstCell item : pool) { + checkAndFixCPIndexes(item); + } + } + + protected void checkGlobals() { + environment.traceln("Checking Globals"); + // This fn will put empty UTF8 string entries on any unset + // CP entries - before the last CP entry. + for (int cpx = 1; cpx < pool.size(); cpx++) { + ConstCell cell = pool.get(cpx); + if (cell == nullConst) { // gap + cell = new ConstCell(cpx, emptyConstValue); + pool.set(cpx, cell); + } + if (!cell.isSet()) { + String name = Integer.toString(cpx); + environment.error("err.const.undecl", name); + } + } + } + + /* + * Helper function for "fixRefsInPool" + * Does recursive checking of references, using a locally-defined visitor. + */ + private void checkAndFixCPRef(ConstCell item) { + ConstValue cv = item.ref; + if (cv != null) { + referenceFixerConstantPool.visit(cv); + } + } + + /* + * Helper function for "fixIndexesInPool" + * Does recursive checking of indexes, using a locally-defined visitor. + */ + private void checkAndFixCPIndexes(ConstCell item) { + ConstValue cv = item.ref; + if (cv != null) { + indexFixerConstantPool.visit(cv); + } + } + + /* + * Help debug Constant Pools + */ + public void printPool() { + int i = 0; + for (ConstCell item : pool) { + environment.traceln(" const #%4d: %s".formatted(i++, item)); + } + } + + public Range getBounds() { + return new Range<>(1, pool.size() - 1); + } + + public ConstCell getConstPollCellByIndex(int cpIndex) { + if (cpIndex >= pool.size()) { + return null; + } + return pool.get(cpIndex); + } + + private void cpool_set(int cpx, ConstCell cell, int sz) { + environment.traceln(() -> "cpool_set1: " + cpx + " " + cell); + environment.traceln(() -> "param_size: " + sz); + environment.traceln(() -> "pool_size : " + pool.size()); + cell.cpIndex = cpx; + if (cpx + sz >= pool.size()) { + environment.traceln(() -> "calling ensureCapacity( " + (cpx + sz + 1) + " )"); + int low = pool.size(); + int high = cpx + sz; + if (high - low > sz) { + String msg = (low == high - sz - 1) ? "#%d".formatted(low) : "#%d-#%d".formatted(low, high - sz - 1); + environment.warning("warn.const.fill", msg); + } + for (int i = 0; i < high - low; i++) { + pool.add(nullConst); + } + } + pool.set(cpx, cell); + if (sz == 2) { + pool.set(cpx + 1, new ConstCell(cpx + 1, emptyConstValue)); + } + environment.traceln(() -> "cpool_set2: " + cpx + " " + cell); + } + + private void delete(int cpx) { + environment.traceln(() -> "delete cell(" + cpx + ")"); + Consumer> op = cell -> { + if (cell.getFlag() == NON_PROCESSED) { + if (cell.cpIndex > cpx) { + cell.cpIndex--; + environment.traceln(() -> "\tcell from " + (cell.cpIndex + 1) + " to " + cell); + } + cell.setFlag(PROCESSED); + } + }; + for (int i = 1; i < pool.size(); i++) { + if (i != cpx) { + ConstCell constCell = uncheckedGetCell(i); + this.traverseConstantCell(constCell, op); + } + } + pool.remove(cpx); + pool.forEach(cell -> cell.setFlag(NON_PROCESSED)); + } + + private void traverseConstantCell(ConstCell constCell, Consumer> op) { + if (constCell != null && constCell instanceof ConstCell) { + if (constCell instanceof ConstCell) { + if (op != null) + op.accept(constCell); + ConstValue constValue = constCell.ref; + if (constValue != null) { + switch (constValue.tag) { + case CONSTANT_CLASS, CONSTANT_STRING, CONSTANT_MODULE, CONSTANT_PACKAGE, CONSTANT_METHODTYPE, + CONSTANT_DYNAMIC, CONSTANT_INVOKEDYNAMIC -> { + traverseConstantCell((ConstCell) constValue.value, op); + } + case CONSTANT_METHODHANDLE, CONSTANT_NAMEANDTYPE, CONSTANT_FIELDREF, CONSTANT_METHODREF, + CONSTANT_INTERFACEMETHODREF -> { + Pair, ConstCell> pair = (Pair, ConstCell>) constValue.value; + traverseConstantCell(pair.first, op); + traverseConstantCell(pair.second, op); + } + } + } + } + } + } + + protected ConstCell uncheckedGetCell(int cpx) { // by index + return pool.get(cpx); + } + + public ConstCell getCell(int cpx) { // by index + ConstCell cell = getConstPollCellByIndex(cpx); + if (cell != null) { + return cell; + } + cell = new ConstCell(cpx, null); + return cell; + } + + public void setCell(int cpx, ConstCell cell) { + ConstValue value = cell.ref; + if (value == null) { + environment.throwErrorException("err.constcell.null.val", cpx); + } + int sz = value.size(); + + if (cpx == 0) { + // It is correct to warn about redeclaring constant zero, + // since this value is never written out to a class file. + environment.warning("warn.const0.redecl"); + } else { + if ((getConstPollCellByIndex(cpx) != null) || ((sz == 2) && (getConstPollCellByIndex(cpx + 1) != null))) { + environment.error("err.const.redecl", "#" + cpx, "#" + max(cpx - 1, 0)); + return; + } + if (cell.isSet() && (cell.cpIndex != cpx)) { + cell = new ConstCell(value); + environment.traceln("setCell: new ConstCell " + cell); + } + } + cpool_set(cpx, cell, sz); + } + + public Optional> getItemizedCell(ConstCell cell) { + final ConstValue value = cell.ref; + if (value == null) { + if (getBounds().in(cell.cpIndex)) { + return Optional.ofNullable(getConstPollCellByIndex(cell.cpIndex)); + } else if (cell.isSet()) { + environment.throwErrorException("err.constcell.null.val", cell.cpIndex); + } else { + environment.throwErrorException("err.constcell.is.undef"); + } + } + return ConstantPoolHashByValue.values().stream(). + filter(v -> v.isSet() && + v.getType() == value.tag && + v.ref.equalsByValue(value)). + findFirst(); + } + + private ConstCell itemizeCell(ConstCell cell) { + Optional> optionalCell = getItemizedCell(cell); + if (optionalCell.isPresent()) { + ConstCell cpCell = optionalCell.get(); + if (cpCell.rank != cell.rank) { + cpCell.setRank(cell.rank); + } + return cpCell; + } else { + final int cellSize = cell.ref.size(); + final int cpIndex = findVacantSlot(cellSize); + cpool_set(cpIndex, cell, cellSize); + return uncheckedGetCell(cpIndex); + } + } + + protected void itemizePool() { + environment.traceln("itemizePool"); + for (ReferenceRank rank : ReferenceRank.values()) { + for (ConstCell cell : ConstantPoolHashByValue.values().stream().filter(v -> !v.isSet() && rank.equals(v.rank)).toList()) { + // find already set ConstCell having cpIndex.isSet && value == value of ConstCell where cpIndex is not set. + // they should be equal by value i.e. cpIndex should not be taken into account + itemizeCell(cell); + } + } + ConstCell firstCell = getConstPollCellByIndex(0); + firstCell.cpIndex = 0; + } + + protected ConstCell specifyCell(ConstCell cell) { + environment.traceln("itemizeCell"); + return cell.isSet() ? cell : itemizeCell(cell); + } + + private int findVacantSlot(int cellSize) { + int index = 1; + for (; index < pool.size(); index++) { + if (pool.get(index) == nullConst && ((cellSize == 1) || pool.get(index + 1) == nullConst)) { + break; + } + } + return index; + } + + public boolean cellFound(final T ref) { + if (ref == null) { + environment.throwErrorException("err.constcell.is.null"); + } + ConstCell cell = ConstantPoolHashByValue.get(ref); + if (cell != null) { + // If we found a cached ConstValue + ConstValue value = cell.ref; + if (value.equals(ref)) { + return true; + } + } + return false; + } + + public ConstCell findCell(final T ref) { + if (ref == null) { + environment.throwErrorException("err.constcell.is.null"); + } + ConstCell cell = ConstantPoolHashByValue.get(ref); + if (cell != null) { + // If we found a cached ConstValue + ConstValue value = cell.ref; + if (!value.equals(ref)) { + environment.throwErrorException("err.values.not.eq", ref.toString(), value.toString()); + } + environment.traceln(format("ConstantPoolHashByValue.got ('%s') for '%s'", cell, ref)); + } else { + // If we didn't find a cached ConstValue add it to the cache + cell = new ConstCell(ref); + ConstantPoolHashByValue.put(ref, cell); + environment.traceln("ConstantPoolHashByValue.put ('%s','%s')", ref, cell); + } + return cell; + } + + public ConstCell findNameAndTypeCell(ConstantPool.ConstValue_NameAndType ref) { + return findCell(ref); + } + + public ConstCell findIntegerCell(Integer value) { + return findCell(new ConstValue_Integer(CONSTANT_INTEGER, value)); + } + + public ConstCell findFloatCell(Integer value) { + return findCell(new ConstValue_Float(value)); + } + + public ConstCell findLongCell(Long value) { + return findCell(new ConstValue_Long(value)); + } + + public ConstCell findDoubleCell(Long value) { + return findCell(new ConstValue_Double(value)); + } + + public ConstCell findUTF8Cell(String value) { + return findCell(new ConstValue_UTF8(value)); + } + + public ConstCell lookupUTF8Cell(Function rule) { + return ConstantPoolHashByValue.entrySet().stream(). + filter(entry -> entry.getKey().tag == CONSTANT_UTF8 && rule.apply((String) (entry.getKey().value))). + findFirst().map(entry -> entry.getValue()). + orElse(null); + } + + public ConstCell findClassCell(NameInfo nameInfo) { + return findCell(CONSTANT_CLASS, nameInfo); + } + + public ConstCell findClassCell(String name) { + return findCell(CONSTANT_CLASS, findUTF8Cell(name)); + } + + public ConstCell findModuleCell(NameInfo nameInfo) { + return findCell(CONSTANT_MODULE, nameInfo); + } + + public ConstCell findModuleCell(String name) { + return findCell(CONSTANT_MODULE, findUTF8Cell(name)); + } + + public ConstCell findPackageCell(String name) { + return findCell(CONSTANT_PACKAGE, findUTF8Cell(name)); + } + + public ConstCell findPackageCell(NameInfo nameInfo) { + return findCell(CONSTANT_PACKAGE, nameInfo); + } + + public ConstCell findCell(ConstType tag, ConstCell value) { + return findCell(new ConstValue_Cell(tag, value)); + } + + public ConstCell findCell(ConstType tag, ConstCell left, ConstCell right) { + return findCell(new ConstValue_Pair(tag, left, right)); + } + + public ConstCell findCell(ConstType tag, NameInfo nameInfo) { + if (nameInfo.isEmpty()) { + // throw exception if empty nameInfo + environment.throwErrorException("err.constcell.empty.nameInfo", "ConstantPool::FindCell"); + } else if (nameInfo.cpIndex() > 0) { + // find and check that cpIndex refers to the cell with tag + ConstCell cell = getConstPollCellByIndex(nameInfo.cpIndex()); + if (cell != null && cell.ref.tag == tag) { + return cell; + } + environment.throwErrorException("err.cpindex.notfound", nameInfo.cpIndex()); + } + return findCell(tag, findUTF8Cell(nameInfo.name())); + } + + public void write(CheckedDataOutputStream out) throws IOException { + // Write the constant pool + int length = pool.size(); + out.writeShort(length); + int i; + environment.traceln(() -> "wr.pool:size=" + length); + for (i = 1; i < length; ) { + ConstCell cell = pool.get(i); + ConstValue value = cell.ref; + if (cell.cpIndex != i) { + environment.throwErrorException("err.constcell.invarg", Integer.toString(i), cell.cpIndex); + } + value.write(out); + i += value.size(); + } + } + + public ArrayList> getPoolCellsByType(ClassFileConst.ConstType... types) { + return pool.stream().filter(c -> c.getType().oneOf(types)).collect(Collectors.toCollection(ArrayList::new)); + } + + public ArrayList> getPoolValuesByRefType(ClassFileConst.ConstType... types) { + return pool.stream().filter(c -> c.ref != null && c.getType().oneOf(types)). + collect(Collectors.toCollection(ArrayList::new)); + } + + /** + * Removes ClassCell entry from the Constant Pool + * + * @param cell the Constant Pool cell ConstCell + */ + public void removeClassCell(ConstCell cell) { + int indCls, indUtf8 = 0; + if (cell != null) { + if (cell.getType() == CONSTANT_CLASS) { + if (cell.ref != null) { + ConstCell utf8Cell = cell.ref.value; + if (!isAllowedToBeDelete(utf8Cell)) + return; + indUtf8 = utf8Cell.cpIndex; + } + indCls = cell.cpIndex; + this.delete(indCls); + this.delete(indCls > indUtf8 ? indUtf8 : indUtf8 - 1); + } else { + environment.warning("warn.cannot.delete.class.cell", cell); + } + } + } + + /** + * @return true if the class name belongs to JDK public API + */ + private boolean isAllowedToBeDelete(ConstCell utf8Cell) { + if (utf8Cell.ref.value != null) { + String className = utf8Cell.ref.value; + if (className.startsWith("java/") || className.startsWith("javax/")) + // className.startsWith("jdk/") || className.startsWith("com/sun/tools/") || className.startsWith("org/w3c")) + return false; + } + return true; + } + + public enum ReferenceRank { + LDC(0), // 0 - highest - ref from ldc + ANY(1), // 1 - any ref + NO(2); // 2 - no ref + final int priority; + + ReferenceRank(int priority) { + this.priority = priority; + } + } + + /** + * CONSTANT_ZERO: Zero Constant Value presents Constant 0. + */ + static public class ConstValue_Zero extends ConstValue { + + public ConstValue_Zero() { + super(CONSTANT_ZERO, (Void) null); + } + + @Override + public boolean isSet() { + return true; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + throw new RuntimeException("Trying to write Constant 0."); + } + } + + /** + * CONSTANT_UTF8(1) is used to represent constant objects of the type: String + */ + static public class ConstValue_UTF8 extends ConstValue { + + public ConstValue_UTF8(String value) { + super(CONSTANT_UTF8, value); + } + + @Override + public String asString() { + return value; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeUTF(value); + } + } + + /** + * CONSTANT_Integer(3) structure represents 4-byte numeric (int) constants + */ + static public class ConstValue_Integer extends ConstValue { + + public ConstValue_Integer(ClassFileConst.ConstType tag, Integer value) { + super(tag, value); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeInt(value); + } + } + + /** + * CONSTANT_Float(4) structure represents 4-byte numeric (float) constants + */ + static public class ConstValue_Float extends ConstValue { + + public ConstValue_Float(Integer value) { + super(CONSTANT_FLOAT, value); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeInt(value); + } + } + + /** + * The CONSTANT_Long_info(5) represents 8-byte numeric (long) constants + */ + static public class ConstValue_Long extends ConstValue { + + public ConstValue_Long(Long value) { + super(CONSTANT_LONG, value); + } + + @Override + public int size() { + return 2; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeLong(value); + } + } + + /** + * The CONSTANT_Double(6) represents 8-byte numeric (double) constants + */ + static public class ConstValue_Double extends ConstValue { + public ConstValue_Double(Long value) { + super(CONSTANT_DOUBLE, value); + } + + @Override + public int size() { + return 2; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeLong(value); + } + } + + /** + * CONSTANT_Cell represents CONSTANT_Class(7), CONSTANT_String(8), CONSTANT_MethodType(16), + * CONSTANT_Module(19), CONSTANT_Package(20) constants + */ + static public class ConstValue_Cell> extends ConstValue> { + + public ConstValue_Cell(ConstType tag, ConstCell constCell) { + super(tag, constCell); + } + + @Override + public String toString() { + return format("[%s %s]", super.tag.toString(), value.toString()); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + value.write(out); + } + + @Override + public boolean isSet() { + return super.isSet() && value.isSet() && value.ref.isSet(); + } + + @Override + public int hashCode() { + int result = value != null ? value.hashCode() : 0; + result = 31 * result + tag.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue_Cell)) return false; + ConstValue_Cell that = (ConstValue_Cell) obj; + return (Objects.equals(this.value, that.value) && this.tag == that.tag); + } + } + + /** + * The CONSTANT_Class(7) structure represents constant objects of the type String + */ + static public class ConstValue_Class extends ConstValue_Cell { + public ConstValue_Class(ConstCell value) { + super(CONSTANT_CLASS, value); + } + } + + /** + * The CONSTANT_Module(19) structure represents a module + */ + static public class ConstValue_Module extends ConstValue_Cell { + public ConstValue_Module(ConstCell value) { + super(CONSTANT_MODULE, value); + } + } + + /** + * The CONSTANT_Package(20) structure represents a method type + */ + static public class ConstValue_Package extends ConstValue_Cell { + public ConstValue_Package(ConstCell value) { + super(CONSTANT_PACKAGE, value); + } + } + + /** + * The CONSTANT_String(8) structure represents a class or an interface + */ + static public class ConstValue_String extends ConstValue_Cell { + public ConstValue_String(ConstCell value) { + super(CONSTANT_STRING, value); + } + } + + /** + * The CONSTANT_MethodType(16) structure represents a method type + */ + static public class ConstValue_MethodType extends ConstValue_Cell { + public ConstValue_MethodType(ConstCell value) { + super(CONSTANT_METHODTYPE, value); + } + } + + /** + * ConstValue_Pair represents CONSTANT_NameAndType(12), CONSTANT_Fieldref(9), CONSTANT_Methodref(10), and + * CONSTANT_InterfaceMethodref(11) structures + */ + static public class ConstValue_Pair extends ConstValue, ConstCell>> { + + public ConstValue_Pair(ConstType tag, Pair, ConstCell> pair) { + super(tag, pair); + } + + public ConstValue_Pair(ConstType tag, ConstCell left, ConstCell right) { + this(tag, new Pair(left, right)); + } + + @Override + public boolean isSet() { + return super.isSet() && + value.first.isSet() & + value.second.isSet(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue_Pair)) return false; + ConstValue_Pair that = (ConstValue_Pair) obj; + if (this.tag == that.tag) { + if ((this.value.first).equals(that.value.first) && + (this.value.second).equals(that.value.second)) { + return true; + } + } + return false; + } + + @Override + public boolean equalsByValue(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue_Pair)) return false; + ConstValue_Pair that = (ConstValue_Pair) obj; + if (this.tag == that.tag) { + if ((this.value.first).equalsByValue(that.value.first) && + (this.value.second).equalsByValue(that.value.second)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return format("%s[%s,%s]", super.tag.toString(), value.first.toString(), value.second.toString()); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + if (tag == CONSTANT_METHODHANDLE) { + out.writeByte(value.first.cpIndex); // write subtag value + } else { + out.writeShort(value.first.cpIndex); + } + out.writeShort(value.second.cpIndex); + } + } + + /** + * The CONSTANT_NameAndType(12) structure is used to represent a field or method, without indicating which class or + * interface type it belongs to + */ + static public class ConstValue_NameAndType extends ConstValue_Pair { + public ConstValue_NameAndType(ConstCell name, ConstCell descriptor) { + super(CONSTANT_NAMEANDTYPE, name, descriptor); + } + } + + /** + * The CONSTANT_Methodref(10) structure is used to represent a method + */ + static public class ConstValue_MethodRef extends ConstValue_Pair { + public ConstValue_MethodRef(ConstCell classCell, ConstCell nameAndType) { + super(CONSTANT_METHODREF, classCell, nameAndType); + } + } + + /** + * The CONSTANT_InterfaceMethodref(11) structure is used to represent an interface method + */ + static public class ConstValue_InterfaceMethodRef extends ConstValue_Pair { + public ConstValue_InterfaceMethodRef(ConstCell interfaceCell, ConstCell nameAndType) { + super(CONSTANT_INTERFACEMETHODREF, interfaceCell, nameAndType); + } + } + + /** + * The CONSTANT_Fieldref(9) structure is used to represent a field + */ + static public class ConstValue_FieldRef extends ConstValue_Pair { + public ConstValue_FieldRef(ConstCell classCell, ConstCell nameAndType) { + super(CONSTANT_FIELDREF, classCell, nameAndType); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + + @Override + public boolean equalsByValue(Object obj) { + return super.equalsByValue(obj); + } + } + + /** + * The CONSTANT_MethodHandle(15) structure is used to represent a method handle + * T : ConstValue_MethodRef, ConstValue_InterfaceMethodRef or ConstValue_FieldRef + */ + static public class ConstValue_MethodHandle

> + extends ConstValue> { + + final ClassFileConst.SubTag kind; + + public ConstValue_MethodHandle(ClassFileConst.SubTag kind, ConstCell

value) { + super(CONSTANT_METHODHANDLE, value); + this.kind = kind; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeByte(kind.value()); + value.write(out); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue_MethodHandle)) return false; + if (!super.equals(obj)) return false; + ConstValue_MethodHandle that = (ConstValue_MethodHandle) obj; + return kind == that.kind; + } + + @Override + public boolean equalsByValue(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue_MethodHandle)) return false; + if (!super.equalsByValue(obj)) return false; + ConstValue_MethodHandle that = (ConstValue_MethodHandle) obj; + return kind == that.kind; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + kind.hashCode(); + return result; + } + } + + static public class ConstValue_BootstrapMethod extends ConstValue { + + private BootstrapMethodData bsmData; + + public ConstValue_BootstrapMethod(ConstType tag, BootstrapMethodData bsmdata, ConstCell value) { + super(tag, value); + this.bsmData = bsmdata; + } + + public BootstrapMethodData bsmData() { + return bsmData; + } + + public void setBsmData(BootstrapMethodData bsmData, int methodAttrIndex) { + this.bsmData = bsmData; + this.bsmData.cpIndex = methodAttrIndex; + } + + public void setBsmData(BootstrapMethodData bsmData) { + this.bsmData = bsmData; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue_BootstrapMethod)) return false; + if (!super.equals(obj)) return false; + ConstValue_BootstrapMethod that = (ConstValue_BootstrapMethod) obj; + return bsmData.equals(that.bsmData); + } + + @Override + public boolean equalsByValue(Object obj) { + if (this == obj) return true; + if (!(obj instanceof ConstValue_BootstrapMethod)) return false; + if (!super.equalsByValue(obj)) return false; + ConstValue_BootstrapMethod that = (ConstValue_BootstrapMethod) obj; + return bsmData.equalsByValue(that.bsmData); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + bsmData.hashCode(); + return result; + } + + @Override + public boolean isSet() { + return super.isSet() && bsmData != null; + } + + @Override + public String toString() { + return super.toString() + "{" + bsmData + "," + value + "}"; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeShort(bsmData.cpIndex); + out.writeShort(value.cpIndex); + } + } + + /** + * The CONSTANT_Dynamic (17) structure is used to represent a dynamically-computed constant, an arbitrary value + * that is produced by invocation of a bootstrap method in the course of a ldc instruction, among others. + * The auxiliary type specified by the structure constrains the type of the dynamically-computed constant. + */ + static public class ConstValue_Dynamic extends ConstValue_BootstrapMethod { + public ConstValue_Dynamic(BootstrapMethodData bsmData, ConstCell napeCell) { + super(CONSTANT_DYNAMIC, bsmData, napeCell); + assert (tag == CONSTANT_DYNAMIC && ConstValue_Dynamic.class.isAssignableFrom(getClass())) || + tag == CONSTANT_INVOKEDYNAMIC && ConstValue_InvokeDynamic.class.isAssignableFrom(getClass()); + } + } + + /** + * The CONSTANT_InvokeDynamic_info(18) structure is used to represent a dynamically-computed call site, an instance of + * java.lang.invoke.CallSite that is produced by invocation of a bootstrap method in the course of an invokedynamic instruction. + * The auxiliary type specified by the structure constrains the method type of the dynamically-computed call site. + */ + static public class ConstValue_InvokeDynamic extends ConstValue_BootstrapMethod { + public ConstValue_InvokeDynamic(BootstrapMethodData bsmData, ConstCell napeCell) { + super(CONSTANT_INVOKEDYNAMIC, bsmData, napeCell); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolDataVisitor.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolDataVisitor.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolDataVisitor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolDataVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.*; + +/** + * Writable data could be undefined until Constant Pool is filled in + */ +public interface ConstantPoolDataVisitor extends DataWriter { + + T visit(ConstantPool pool); + + default T visitData(T cpData, ConstantPool pool) { + T data = ((ConstantPoolDataVisitor) cpData).visit(pool); + if (data.getClass().isAssignableFrom(ConstCell.class)) { + ConstCell cell = (ConstCell) data; + ClassFileConst.ConstType type = cell.getType(); + if (type.oneOf(CONSTANT_INTEGER, CONSTANT_FLOAT, + CONSTANT_LONG, CONSTANT_DOUBLE, + CONSTANT_UTF8)) { + data = (T) new ParseAnnotation.ConstElemValue(type.getAnnotationElementTypeValue(), cell); + + } else { + data = (T) new ParseAnnotation.ClassElemValue(cell); + } +// } else if (type.oneOf(CONSTANT_CLASS)) { +// data = (T) new ParserAnnotation.ClassElemValue(cell); +// } else { +// data = (T) new ParserAnnotation.ClassElemValue(refCell); +// } +/// annotation value refers to unknown data type +// pool.env.error("unknown.annotation.data", cpData.getClass().getSimpleName()); +// throw new Scanner.SyntaxError().Fatal(); + } + return data; + } + + default T visitConstCell(ConstCell cell, ConstantPool pool) { + ConstCell refCell; + if (!cell.isSet()) { + refCell = pool.uncheckedGetCell(cell.cpIndex); + } else { + refCell = new ConstCell(cell.cpIndex, cell.ref); + } + cell.ref = refCell.ref; + return (T) cell; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolIndexData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolIndexData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolIndexData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ConstantPoolIndexData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; + +import static org.openjdk.asmtools.jdis.Indenter.UNDEFINED; + +/** + * Writable element of the DataVector u2 vector[elements]; + *

+ * u2 unset_fields[number_of_unset_fields]; + * Each entry in the unset_fields array must be a valid index into the constant_pool table. + * The constant_pool entry at that index must be a CONSTANT_NameAndType_info structure with a field descriptor. + */ +public class ConstantPoolIndexData implements DataWriter { + + ConstCell nameAndType = null; + ConstantPool pool = null; + int cpIndex = UNDEFINED; + + public ConstantPoolIndexData(ConstCell nameAndType, ConstantPool pool) { + this.nameAndType = nameAndType; + this.pool = pool; + } + + + public ConstantPoolIndexData(int cpIndex) { + this.cpIndex = cpIndex; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + if (cpIndex == UNDEFINED) { + cpIndex = nameAndType.cpIndex; + } + if (cpIndex == UNDEFINED) { + throw new IOException("a file due to implementation issue:\n\t\t \"Can't retrieve CP Index for %s\"". + formatted(nameAndType == null ? "null" : nameAndType.toString())); + } + out.writeShort(cpIndex); + } + + @Override + public int getLength() { + // u2 + return 2; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVector.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVector.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVector.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVector.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +public class DataVector implements Iterable { + + ArrayList elements; + + public DataVector(int initSize) { + elements = new ArrayList<>(initSize); + } + + public DataVector() { + this(12); + } + + public Iterator iterator() { + return elements.iterator(); + } + + public void add(T element) { + elements.add(element); + } + + public void addAll(List collection) { + elements.addAll(collection); + } + + public Optional findFirst(Predicate filter) { + return elements.stream().filter(filter).findFirst(); + } + + // full length of the attribute conveyor + // declared in Data + public int getLength() { + int length = 0; + // calculate overall size here rather than in add() + // because it may not be available at the time of invoking of add() + for (T element : elements) { + length += element.getLength(); + } + + return 2 + length; // add the length of number of elements + } + + public void write(CheckedDataOutputStream out) + throws IOException { + out.writeShort(elements.size()); + writeElements(out); + } + + public void writeElements(CheckedDataOutputStream out) + throws IOException { + for (DataWriter element : elements) { + element.write(out); + } + } + + /* for compatibility with Vector */ + public void addElement(T element) { + elements.add(element); + } + + public int size() { + return elements.size(); + } + + public DataWriter elementAt(int k) { + return elements.get(k); + } +}// end class DataVector diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVectorAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVectorAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVectorAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataVectorAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * Container for attributes having inline tables: + * InnerClasses, BootstrapMethods, LineNumberTable, Runtime(In)Visible(Type|Parameter)Annotations, + * LocalVariableTable, StackMapTable + */ +class DataVectorAttr extends AttrData implements Collection { + + private final ArrayList elements; + private boolean byteIndex; + + /** + * @param pool Constant pool + * @param eAttribute the attribute name @see org.openjdk.asmtools.common.content.EAttribute + * @param byteIndex indicates 1 or two bytes is used to keep number of table elements: + * u2 StackMapTable_attribute.number_of_entries + * u1 RuntimeVisibleParameterAnnotations_attribute.num_parameters + * @param initialData initial elements of table + */ + private DataVectorAttr(ConstantPool pool, EAttribute eAttribute, boolean byteIndex, ArrayList initialData) { + super(pool, eAttribute); + this.elements = initialData; + this.byteIndex = byteIndex; + } + + DataVectorAttr(ConstantPool pool, EAttribute attribute, ArrayList initialData) { + this(pool, attribute, false, initialData); + } + + DataVectorAttr(ConstantPool pool, EAttribute attribute) { + this(pool, attribute, false, new ArrayList<>()); + + } + + DataVectorAttr(ConstantPool pool, EAttribute attribute, boolean byteIndex) { + this(pool, attribute, byteIndex, new ArrayList<>()); + } + + public T get(int index) { + return elements.get(index); + } + + public Optional findFirst(Predicate filter) { + return elements.stream().filter(filter).findFirst(); + } + + @Override + public boolean add(T element) { + return elements.add(element); + } + + @Override + public boolean remove(Object o) { + return elements.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return elements.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return elements.addAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return elements.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return elements.retainAll(c); + } + + @Override + public void clear() { + elements.clear(); + } + + public DataVectorAttr addAll(Stream s) { + s.filter(e -> e != null).forEach(elements::add); + return this; + } + + public T set(int i, T element) { + return elements.set(i, element); + } + + public int size() { return elements.size(); } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object o) { + return false; + } + + public void replaceAll(Collection collection) { + elements.clear(); + elements.addAll(collection); + } + + public ArrayList getElements() { + return elements; + } + + @Override + public Iterator iterator() { + return elements.iterator(); + } + + @Override + public Object[] toArray() { + return elements.toArray(); + } + + @Override + public V[] toArray(V[] a) { + return elements.toArray(a); + } + + public Stream stream() { return elements.stream(); } + + @Override + public int attrLength() { + // calculate overall size + int length = elements.stream().mapToInt(DataWriter::getLength).sum(); + // add the length of number of elements + length += (byteIndex) ? 1 : 2; + return length; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + int size = (int)elements.stream().filter(DataWriter::isCountable).count(); + if (byteIndex) { + out.writeByte(size); + } else { + out.writeShort(size); + } // number of elements + for (T elem : elements) { + elem.write(out); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataWriter.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataWriter.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataWriter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DataWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; + +/** + * Base contract for writeable structures + */ +interface DataWriter { + + default boolean isCountable() { + return true; + } + + void write(CheckedDataOutputStream out) throws IOException; + int getLength(); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DefaultAnnotationAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DefaultAnnotationAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DefaultAnnotationAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/DefaultAnnotationAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; + +/** + * DefaultAnnotationAttr + * + * Used to represent Default Annotation Attributes + * + */ +public class DefaultAnnotationAttr extends AttrData { + + DataWriter element; // Data + + public DefaultAnnotationAttr(ConstantPool pool, EAttribute attribute, DataWriter element) { + super(pool, attribute); + this.element = element; + } + + public void add(DataWriter element) { + this.element = element; + } + + @Override + public int attrLength() { + return element.getLength(); // add the length of number of elements + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); // attr name, attr len + element.write(out); + } +}// end class DataVectorAttr + diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/EnclosingMethodAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/EnclosingMethodAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/EnclosingMethodAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/EnclosingMethodAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; + +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.CONSTANT_METHODREF; + +/** + * EnclosingMethod_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 class_index; + * u2 method_index; + * } + * If the current class is not immediately enclosed by a method or constructor, + * then the value of the method_index item must be zero. + */ +public class EnclosingMethodAttr extends AttrData { + private ConstantPool pool; + private ConstCell classCell; + // methodCell is null if the current class is not immediately enclosed by a method or constructor. + private ConstCell methodCell; + + /** + * @param pool ConstantPool + * @param classCell class_index to be written to class file + * @param methodCell method_index If the current class is not immediately enclosed by a method or constructor, + * then the value of the method_index item must be zero. + */ + EnclosingMethodAttr(ConstantPool pool, ConstCell classCell, ConstCell methodCell) { + super(pool, EAttribute.ATT_EnclosingMethod); + this.pool = pool; + this.classCell = classCell; + this.methodCell = methodCell; + } + + @Override + public int attrLength() { + // attribute_length: The value of the attribute_length item must be four. + return 4; + } + + @Override + protected ConstCell classifyConstCell(ConstantPool pool, ConstCell cell) { + return pool.findCell(CONSTANT_METHODREF, cell); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + if (!classCell.isSet()) { + classCell = pool.specifyCell(classCell); + if (!pool.getBounds().in(classCell.cpIndex)) { + pool.environment.throwErrorException("err.entity.not.in.cp", classCell); + } + } + out.writeShort(classCell.cpIndex); + if (methodCell != null && !methodCell.isSet()) { + methodCell = pool.specifyCell(methodCell); + if (!pool.getBounds().in(methodCell.cpIndex)) { + pool.environment.throwErrorException("err.entity.not.in.cp", methodCell); + } + } + + // if methodCell is null then method_index is 0 + out.writeShort(methodCell != null ? methodCell.cpIndex : 0); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ExceptionData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ExceptionData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ExceptionData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ExceptionData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; + +/** + * 4.7.3. The Code Attribute + *

+ *Code_attribute { + * + * { u2 start_pc; + * u2 end_pc; + * u2 handler_pc; + * u2 catch_type; + * } + * + * } + */ +class ExceptionData implements DataWriter { + + long pos; + CodeAttr.RangePC rangePC; + int handler_pc; + Indexer catchType; + + public ExceptionData(long pos, CodeAttr.RangePC rangePC, int handler_pc, Indexer catchType) { + this.pos = pos; + this.rangePC = rangePC; + this.handler_pc = handler_pc; + this.catchType = catchType; + } + + @Override + public int getLength() { + return 8; // add the length of number of elements + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(rangePC.start_pc); + out.writeShort(rangePC.end_pc); + out.writeShort(handler_pc); + if (catchType.isSet()) { + out.writeShort(catchType.cpIndex); + } else { + out.writeShort(0); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.ELocation; +import org.openjdk.asmtools.common.structure.EModifier; + +import java.io.IOException; + +/** + * field_info + */ +class FieldData extends MemberData { + + + /* FieldData Fields */ + private ConstantPool.ConstValue_FieldRef fieldRef; + private AttrData initialValue; + + public FieldData(ClassData classData, int access, ConstantPool.ConstValue_FieldRef fieldRef) { + super(classData.pool, classData.getEnvironment(), access); + this.attributeLocation = ELocation.field_info; + this.fieldRef = fieldRef; + if (EModifier.hasPseudoMod(access)) { + createPseudoMod(); + } + } + + protected boolean checkExistence(EAttribute attribute) { + return switch (attribute) { + case ATT_Signature -> signatureAttr != null; + default -> throw new IllegalStateException("Unexpected attribute: %s in %s". + formatted(attribute.parseKey(), attributeLocation.name())); + }; + } + + public ConstantPool.ConstValue_FieldRef getNameDesc() { + return fieldRef; + } + + public void SetInitialValue(ConstCell cell) { + initialValue = new CPXAttr(pool, EAttribute.ATT_ConstantValue, cell); + } + + public AttrData getInitialValue() { + return initialValue; + } + + @Override + protected DataVector getAttrVector() { + return getDataVector(initialValue, syntheticAttr, deprecatedAttr, signatureAttr); + } + + public void write(CheckedDataOutputStream out) throws IOException, Parser.CompilerError { + out.writeShort(access); + out.writeShort(fieldRef.value.first.cpIndex); + out.writeShort(fieldRef.value.second.cpIndex); + DataVector attrs = getAttrVector(); + attrs.write(out); + } +} // end FieldData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldType.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldType.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldType.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/FieldType.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +public enum FieldType { + Array('[', "reference", 1), + Boolean('Z', "boolean", 1), + Byte('B', "byte", 1), + Char('C', "char", 1), + Double('D', "double", 2), + Float('F', "float", 1), + Int('I', "int", 1), + LReference('L', "reference", 1), + Long('J', "long", 2), + QReference('Q', "reference", 1), + Short('S', "short", 1); + + private final char term; + private final String type; + private final int slotsCount; + + FieldType(char term, String type, int slotsCount) { + this.term = term; + this.type = type; + this.slotsCount = slotsCount; + } + + public static FieldType getFieldType(char term) { + for (FieldType ft : FieldType.values()) { + if ( ft.term == term ) { + return ft; + } + } + return null; + } + + public int getSlotsCount() { + return slotsCount; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Indexer.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Indexer.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Indexer.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Indexer.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +/** + * Indexer a position starting from 0 of a constant cell in the Constant Pool. + * Also, the class is used to hold uninitialized (isSet == false) and initialized (isSet == true) indexes,counters: + * max_stack, max_locals, Trap.start_pc, Trap.end_pc + */ +public class Indexer { + + public static final int NotSet = -1; + protected int cpIndex; + + Indexer() { + cpIndex = NotSet; + } + + Indexer(int cpIndex) { + this.cpIndex = cpIndex; + } + + public int hashCode() { return isSet() ? cpIndex : 0; } + + boolean isSet() { return cpIndex != NotSet; } + + boolean inRange(int index){ + return index >=0 && index < cpIndex; + } + + // Alias for max_stack, max_locals + public int value() { + return cpIndex; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/InnerClassData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/InnerClassData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/InnerClassData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/InnerClassData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; + +/** + * + */ +class InnerClassData implements DataWriter { + + int access; + ConstCell name, innerClass, outerClass; + + public InnerClassData(int access, ConstCell name, ConstCell innerClass, ConstCell outerClass) { + this.access = access; + this.name = name; + this.innerClass = innerClass; + this.outerClass = outerClass; + } + + @Override + public int getLength() { + return 8; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(innerClass.cpIndex); + if (outerClass.isSet()) { + out.writeShort(outerClass.cpIndex); + } else { + out.writeShort(0); + } + if (name.isSet()) { + out.writeShort(name.cpIndex); + } else { + out.writeShort(0); + } + out.writeShort(access); + } +}// end class InnerClassData + diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Instr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Instr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Instr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Instr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,233 @@ +/* + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; +import java.util.Optional; + +import static org.openjdk.asmtools.asmutils.HexUtils.toHex; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode; +import static org.openjdk.asmtools.jasm.OpcodeTables.OpcodeType; + +// +class Instr { + + // environment is needed to fix CP references and show error(s)/message(s) + private final JasmEnvironment environment; + private final ConstantPool pool; + + // References to Method's name,signature CP cells + // that will be used to build a warning message while writing a binary if necessary + private final ConstCell nameCell, sigCell; + + private long pos; + // + Instr next = null; + int pc; + Opcode opc; + Indexer arg; + Object arg2; // second or unusual argument + + public Instr(MethodData methodData, JasmEnvironment environment) { + this.environment = environment; + this.pool = methodData.getPool(); + // for message purposes only + this.nameCell = methodData.nameCell; + this.sigCell = methodData.sigCell; + } + + public Instr set(int pc, long pos, Opcode opc, Indexer arg, Object arg2) { + this.pc = pc; + this.pos = pos; + this.opc = opc; + this.arg = arg; + this.arg2 = arg2; + return this; + } + + private Indexer fixReference(Indexer arg) { + if( arg != null && arg instanceof ConstCell) { + ConstCell cell = (ConstCell) arg; + if( cell.ref == null || arg.cpIndex == 0) { + // Corner case cell[0] has value but its reference is wrong + // For negative testing: when instruction refers to a wrong Constant Pool cell + // asm just shows a warning. + environment.warning(pos - String.valueOf(arg.cpIndex).length()-1, + "warn.instr.wrong.arg", opc.parseKey(), arg.cpIndex); + return arg; + } + if( !arg.isSet()) { + Optional> optionalCell = pool.getItemizedCell((ConstCell) arg); + if (optionalCell.isPresent()) { + arg = optionalCell.get(); + } else { + environment.throwErrorException(pos - String.valueOf(arg.cpIndex).length()-1, + "err.instr.wrong.arg", opc.parseKey(), arg.cpIndex); + } + } + } + return arg; + } + + public void write(CheckedDataOutputStream out) throws IOException { + OpcodeType type = opc.type(); + arg = fixReference(arg); + switch (type) { + case NORMAL: { + if (opc == Opcode.opc_bytecode) { + out.writeByte(arg.cpIndex); + return; + } + out.writeByte(opc.value()); + int opcLen = opc.length(); + if (opcLen == 1) { + return; + } + + switch (opc) { + case opc_tableswitch: + ((SwitchTable) arg2).writeTableSwitch(out); + return; + case opc_lookupswitch: + ((SwitchTable) arg2).writeLookupSwitch(out); + return; + } + + int iarg = 0; + try { + iarg = arg.cpIndex; + } catch (NullPointerException e) { + environment.throwErrorException("err.instr.null.arg", opc.parseKey()); + } + //env.traceln("instr:"+opcNamesTab[opc]+" len="+opcLen+" arg:"+iarg); + switch (opc) { + case opc_jsr: + case opc_goto: + case opc_ifeq: + case opc_ifge: + case opc_ifgt: + case opc_ifle: + case opc_iflt: + case opc_ifne: + case opc_if_icmpeq: + case opc_if_icmpne: + case opc_if_icmpge: + case opc_if_icmpgt: + case opc_if_icmple: + case opc_if_icmplt: + case opc_if_acmpeq: + case opc_if_acmpne: + case opc_ifnull: + case opc_ifnonnull: + case opc_jsr_w: + case opc_goto_w: + iarg = iarg - pc; + break; + case opc_iinc: + iarg = (iarg << 8) | (((Indexer) arg2).cpIndex & 0xFF); + break; + case opc_invokeinterface: + iarg = ((iarg << 8) | (((Indexer) arg2).cpIndex & 0xFF)) << 8; + break; + case opc_invokedynamic: // JSR-292 + iarg = (iarg << 16); + break; + case opc_ldc: + if ((iarg & 0xFFFFFF00) != 0) { + environment.throwErrorException("err.instr.arg.long", opc.parseKey(), iarg); + } + break; + } + switch (opcLen) { + case 1: + return; + case 2: + if(iarg > 0xff) { // unsigned byte + environment.warning("warn.instruction.operand.value.overflow", + getMethodSignature(), opc.parseKey(), + toHex(iarg), + "unsigned 8-bit value 0xFF"); + } + out.writeByte(iarg); + return; + case 3: + if( iarg > Short.MAX_VALUE ) { // signed short + environment.warning("warn.instruction.operand.value.overflow", + getMethodSignature(), opc.parseKey(), + toHex(iarg), + "signed 16-bit value " + toHex(Short.MAX_VALUE)); + } + out.writeShort(iarg); + return; + case 4: // opc_multianewarray only + if( iarg > Short.MAX_VALUE ) { // signed short + environment.warning("warn.instruction.operand.value.overflow", + getMethodSignature(), opc.parseKey(), + toHex(iarg), + "signed 16-bit value " + toHex(Short.MAX_VALUE)); + } + out.writeShort(iarg); + iarg = ((Indexer) arg2).cpIndex; + out.writeByte(iarg); + return; + case 5: + if( iarg > Integer.MAX_VALUE ) { // signed int + environment.warning("warn.instruction.operand.value.overflow", + getMethodSignature(), opc.parseKey(), + toHex(iarg), + "signed 32-bit value " + toHex(Integer.MAX_VALUE)); + } + out.writeInt(iarg); + return; + default: + environment.throwErrorException("err.instr.opc.len", opc.parseKey(), opcLen); + } + } + case WIDE: + out.writeByte(Opcode.opc_wide.value()); + out.writeByte(opc.value() & 0xFF); + out.writeShort(arg.cpIndex); + if (opc == Opcode.opc_iinc_w) { + out.writeShort(((Indexer) arg2).cpIndex); + } + return; + case PRIVELEGED: + case NONPRIVELEGED: + out.writeByte(opc.value() >> 8); + out.writeByte(opc.value() & 0xFF); + return; + default: + environment.throwErrorException("err.instr.opc.unknown", opc.parseKey()); + } // end writeSpecCode + } + + /** + * @return the current method signature in the form "MethodName""MethodSignature" like testMethod(II)V + * for using in warning messages + */ + private String getMethodSignature() { + String res = this.nameCell.ref.value != null ? this.nameCell.ref.value.toString() : "#" + this.nameCell.cpIndex; + return res + (this.sigCell.ref.value != null ? this.sigCell.ref.value.toString() : ":#" + this.sigCell.cpIndex); + } + +} // end Instr diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmEnvironment.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmEnvironment.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmEnvironment.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmEnvironment.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.CompilerLogger; +import org.openjdk.asmtools.common.EMessageKind; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.inputs.TextInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.io.DataInputStream; +import java.io.IOException; +import java.net.URISyntaxException; + +import static org.openjdk.asmtools.common.CompilerConstants.EOF; +import static org.openjdk.asmtools.common.CompilerConstants.OFFSET_BITS; + +public class JasmEnvironment extends Environment { + + InputFile inputFile; + + /** + * @param builder the jasm environment builder + */ + private JasmEnvironment(Builder builder) { + super(builder); + } + + @Override + public void setToolInput(ToolInput toolInput) throws IOException, URISyntaxException { + try { + // content of the jasm input file + super.setToolInput(toolInput); + this.inputFile = new InputFile(getDataInputStream()); + } catch (IOException ioe) { + error("err.cannot.read", toolInput); + throw ioe; + } + } + + // proxy methods + @Override + public void warning(long where, String id, Object... args) { + getLogger().warning(where, id, args); + } + + @Override + public void error(long where, String id, Object... args) { + getLogger().error(where, id, args); + } + + @Override + public void warning(String id, Object... args) { + getLogger().warning(NOWHERE, id, args); + } + + @Override + public void error(String id, Object... args) { + getLogger().error(NOWHERE, id, args); + } + + // Jasm specific methods + @Override + public long getCount(EMessageKind kind) { + return getLogger().getCount(kind); + } + + public boolean hasMessages() { + return !super.getLogger().noMessages(); + } + + // get line number by scanner position + public long lineNumber(long where) { + return getLogger().lineNumber(where); + } + + // get line number by scanner position + public long lineOffset(long lineNumber, long where) { + return getLogger().lineOffset(lineNumber, where); + } + + /** + * Throws an error not associated with scanner position in an input file + * + * @param id id of a string resource in I18NResourceBundle + * @param args arguments referenced by the format specifiers in the resource string + * @throws Error exception + */ + public void throwErrorException(String id, Object... args) throws Error { + error(id, args); + throw new Error(); + } + + /** + * Throws an error associated with scanner position in an input file + * + * @param where position in an input file + * @param id id of a string resource in I18NResourceBundle + * @param args arguments referenced by the format specifiers in the resource string + * @throws Error exception + */ + public void throwErrorException(long where, String id, Object... args) throws Error { + error(where, id, args); + throw new Error(); + } + + + /** + * @param printTotals whether to print the total line: N warning(s), K error(s) + * @return 0 if there are no errors otherwise a count of errors + */ + public int flush(boolean printTotals) { + return super.getLogger().flush(printTotals); + } + + public long getPosition() { + return inputFile == null ? 0 : inputFile.position; + } + + public int read() { + return inputFile.readUTF(); + } + + public int lookForward() { + return inputFile.lookForwardUTF(); + } + + public int convertUnicode() { + return inputFile.convertUnicodeUTF(); + } + + static class JasmBuilder extends Environment.Builder { + + public JasmBuilder(ToolOutput toolOutput, DualStreamToolOutput logger) { + super(toolOutput, new CompilerLogger("jasm", JasmEnvironment.class, logger)); + } + + @Override + public JasmEnvironment build() { + return new JasmEnvironment(this); + } + } + + private class InputFile extends TextInput { + + InputFile(DataInputStream dataInputStream) throws IOException { + super(dataInputStream); + } + + int lookForwardUTF() { + try { + return strData.charAt(charPos); + } catch (StringIndexOutOfBoundsException e) { + return EOF; + } + } + + @Override + public int readUTF() { + char ch; + position = ((long) linepos << OFFSET_BITS) | charPos; + try { + ch = strData.charAt(charPos); + charPos++; + // parse special characters + switch (ch) { + case '\n' -> linepos++; + case '\r' -> { + if (strData.charAt(charPos) == '\n') { + charPos++; + } + linepos++; + } + } + } catch (StringIndexOutOfBoundsException e) { + return EOF; + } + return ch; + } + + int convertUnicodeUTF() { + char ch; + try { + while ((ch = strData.charAt(charPos)) == 'u') { + charPos++; + } + int d = 0; + for (int i = 0; i < 4; i++) { + switch (ch) { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> d = (d << 4) + ch - '0'; + case 'a', 'b', 'c', 'd', 'e', 'f' -> d = (d << 4) + 10 + ch - 'a'; + case 'A', 'B', 'C', 'D', 'E', 'F' -> d = (d << 4) + 10 + ch - 'A'; + default -> { + error(position, "err.invalid.escape.char"); + return d; + } + } + ch = strData.charAt(++charPos); + } + return d; + } catch (StringIndexOutOfBoundsException e) { + error(position, "err.invalid.escape.char"); + return EOF; + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTokens.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTokens.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTokens.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTokens.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,547 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * JasmTokens + *

+ * This class contains tokens specific to parsing JASM syntax. + *

+ * The classes in JasmTokens are following a Singleton Pattern. These classes are Enums, + * and they are contained in private hash maps (lookup tables and reverse lookup tables). + * These hash maps all have public accessors, which clients use to look-up enums. + *

+ * Tokens in this table carry no external state, and are typically treated as constants. + * They do not need to be reset. + */ +public class JasmTokens { + + /*-------------------------------------------------------- */ + /* Marker: describes the type of Keyword */ + public enum KeywordType { + TOKEN("TOKEN"), + VALUE("VALUE"), + JASMIDENTIFIER("JASM"), + KEYWORD("KEYWORD"); + + private final String printValue; + + KeywordType(String printValue) { + this.printValue = printValue; + } + + public String printValue() { + return printValue; + } + } + + /*-------------------------------------------------------- */ + /* Marker - describes the type of token */ + /* this is rather cosmetic, no function currently. */ + public enum TokenType { + MODIFIER("Modifier"), + OPERATOR("Operator"), + VALUE("Value"), + TYPE("Type"), + EXPRESSION("Expression"), + STATEMENT("Statement"), + DECLARATION("Declaration"), + PUNCTUATION("Punctuation"), + SPECIAL("Special"), + JASM("Jasm"), + MISC("Misc"), + JASM_IDENT("Jasm identifier"), + MODULE_NAME("Module Name"), // The token can be used as Module Name + TYPE_PATH_KIND("Type path kind"), // Table 4.7.20.2-A Interpretation of type_path_kind values + CLASS_NAME("Class Name"); // The token can be used as Class Name + + private final String printValue; + + TokenType(String printValue) { + this.printValue = printValue; + } + + public String printValue() { + return printValue; + } + } + + public enum AnnotationType { + Visible("@+"), + Invisible("@-"), + VisibleType("@T+"), + InvisibleType("@T-"); + + private final String jasmPrefix; + + AnnotationType(String jasmPrefix) { + this.jasmPrefix = jasmPrefix; + } + + /** + * isAnnotationToken + *

+ * examines the beginning of a string to see if it starts with an annotation + * characters ('@+' = visible annotation, '@-' = invisible). + * + * @param str String to be analyzed + * @return True if the string starts with an annotation char. + */ + static public boolean isAnnotationToken(String str) { + return (str.startsWith(AnnotationType.Invisible.jasmPrefix) || + str.startsWith(AnnotationType.Visible.jasmPrefix)); + } + + /** + * isTypeAnnotationToken + *

+ * examines the beginning of a string to see if it starts with type annotation + * characters ('@T+' = visible type annotation, '@T-' = invisible). + * + * @param str String to be analyzed + * @return True if the string starts with an annotation char. + */ + static public boolean isTypeAnnotationToken(String str) { + return (str.startsWith(AnnotationType.InvisibleType.jasmPrefix) || + str.startsWith(AnnotationType.VisibleType.jasmPrefix)); + } + + /** + * isAnnotation + *

+ * examines the beginning of a string to see if it starts with an annotation character + * + * @param str String to be analyzed + * @return True if the string starts with an annotation char. + */ + static public boolean isAnnotation(String str) { + return (str.startsWith("@")); + } + + /** + * isInvisibleAnnotationToken + *

+ * examines the end of an annotation token to determine visibility ('+' = visible + * annotation, '-' = invisible). + * + * @param str String to be analyzed + * @return True if the token implies invisible annotation. + */ + static public boolean isInvisibleAnnotationToken(String str) { + return (str.endsWith("-")); + } + } + + /** + * Scanner Tokens (Definitive List) + */ + public enum Token { + EOF(-1, "EOF", "EOF", EnumSet.of(TokenType.MISC, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + COMMA(0, "COMMA", ",", EnumSet.of(TokenType.OPERATOR)), + ASSIGN(1, "ASSIGN", "=", EnumSet.of(TokenType.OPERATOR)), + + ASGMUL(2, "ASGMUL", "*=", EnumSet.of(TokenType.OPERATOR)), + ASGDIV(3, "ASGDIV", "/=", EnumSet.of(TokenType.OPERATOR)), + ASGREM(4, "ASGREM", "%=", EnumSet.of(TokenType.OPERATOR)), + ASGADD(5, "ASGADD", "+=", EnumSet.of(TokenType.OPERATOR)), + ASGSUB(6, "ASGSUB", "-=", EnumSet.of(TokenType.OPERATOR)), + ASGLSHIFT(7, "ASGLSHIFT", "<<=", EnumSet.of(TokenType.OPERATOR)), + ASGRSHIFT(8, "ASGRSHIFT", ">>=", EnumSet.of(TokenType.OPERATOR)), + ASGURSHIFT(9, "ASGURSHIFT", "<<<=", EnumSet.of(TokenType.OPERATOR)), + ASGBITAND(10, "ASGBITAND", "&=", EnumSet.of(TokenType.OPERATOR)), + ASGBITOR(11, "ASGBITOR", "|=", EnumSet.of(TokenType.OPERATOR)), + ASGBITXOR(12, "ASGBITXOR", "^=", EnumSet.of(TokenType.OPERATOR)), + + COND(13, "COND", "?:", EnumSet.of(TokenType.OPERATOR)), + OR(14, "OR", "||", EnumSet.of(TokenType.OPERATOR)), + AND(15, "AND", "&&", EnumSet.of(TokenType.OPERATOR)), + BITOR(16, "BITOR", "|", EnumSet.of(TokenType.OPERATOR)), + BITXOR(17, "BITXOR", "^", EnumSet.of(TokenType.OPERATOR)), + BITAND(18, "BITAND", "&", EnumSet.of(TokenType.OPERATOR)), + NE(19, "NE", "!=", EnumSet.of(TokenType.OPERATOR)), + EQ(20, "EQ", "==", EnumSet.of(TokenType.OPERATOR)), + GE(21, "GE", ">=", EnumSet.of(TokenType.OPERATOR)), + GT(22, "GT", ">", EnumSet.of(TokenType.OPERATOR)), + LE(23, "LE", "<=", EnumSet.of(TokenType.OPERATOR)), + LT(24, "LT", "<", EnumSet.of(TokenType.OPERATOR)), + INSTANCEOF(25, "INSTANCEOF", "instanceof", EnumSet.of(TokenType.OPERATOR)), + LSHIFT(26, "LSHIFT", "<<", EnumSet.of(TokenType.OPERATOR)), + RSHIFT(27, "RSHIFT", ">>", EnumSet.of(TokenType.OPERATOR)), + URSHIFT(28, "URSHIFT", "<<<", EnumSet.of(TokenType.OPERATOR)), + ADD(29, "ADD", "+", EnumSet.of(TokenType.OPERATOR)), + SUB(30, "SUB", "-", EnumSet.of(TokenType.OPERATOR)), + DIV(31, "DIV", "/", EnumSet.of(TokenType.OPERATOR)), + REM(32, "REM", "%", EnumSet.of(TokenType.OPERATOR)), + MUL(33, "MUL", "*", EnumSet.of(TokenType.OPERATOR)), + CAST(34, "CAST", "cast", EnumSet.of(TokenType.OPERATOR, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + POS(35, "POS", "+", EnumSet.of(TokenType.OPERATOR)), + NEG(36, "NEG", "-", EnumSet.of(TokenType.OPERATOR)), + NOT(37, "NOT", "!", EnumSet.of(TokenType.OPERATOR)), + BITNOT(38, "BITNOT", "~", EnumSet.of(TokenType.OPERATOR)), + PREINC(39, "PREINC", "++", EnumSet.of(TokenType.OPERATOR)), + PREDEC(40, "PREDEC", "--", EnumSet.of(TokenType.OPERATOR)), + NEWARRAY(41, "NEWARRAY", "new", EnumSet.of(TokenType.OPERATOR)), + NEWINSTANCE(42, "NEWINSTANCE", "new", EnumSet.of(TokenType.OPERATOR)), + NEWFROMNAME(43, "NEWFROMNAME", "new", EnumSet.of(TokenType.OPERATOR)), + POSTINC(44, "POSTINC", "++", EnumSet.of(TokenType.OPERATOR)), + POSTDEC(45, "POSTDEC", "--", EnumSet.of(TokenType.OPERATOR)), + FIELD(46, "FIELD", "field", EnumSet.of(TokenType.OPERATOR, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + METHOD(47, "METHOD", "method", EnumSet.of(TokenType.OPERATOR, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + ARRAYACCESS(48, "ARRAYACCESS", "[]", EnumSet.of(TokenType.OPERATOR)), + NEW(49, "NEW", "new", EnumSet.of(TokenType.OPERATOR)), + INC(50, "INC", "++", EnumSet.of(TokenType.OPERATOR)), + DEC(51, "DEC", "--", EnumSet.of(TokenType.OPERATOR)), + // 52, 53 are reserved for FILE, CLASSFILE + + CONVERT(55, "CONVERT", "convert", EnumSet.of(TokenType.OPERATOR, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + EXPR(56, "EXPR", "expr", EnumSet.of(TokenType.OPERATOR, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + ARRAY(57, "ARRAY", "array", EnumSet.of(TokenType.OPERATOR, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + GOTO(58, "GOTO", "goto", EnumSet.of(TokenType.OPERATOR)), + /* + * Value tokens + */ + IDENT(60, "IDENT", "Identifier", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME, TokenType.JASM_IDENT), KeywordType.VALUE), + BOOLEANVAL(61, "BOOLEANVAL", "Boolean", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.VALUE), + BYTEVAL(62, "BYTEVAL", "Byte", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + CHARVAL(63, "CHARVAL", "Char", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + SHORTVAL(64, "SHORTVAL", "Short", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + INTVAL(65, "INTVAL", "Integer", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.VALUE), + LONGVAL(66, "LONGVAL", "Long", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.VALUE), + FLOATVAL(67, "FLOATVAL", "Float", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.VALUE), + DOUBLEVAL(68, "DOUBLEVAL", "Double", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.VALUE), + STRINGVAL(69, "STRINGVAL", "String", EnumSet.of(TokenType.VALUE, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.VALUE), + /* + * Type keywords + */ + BYTE(70, "BYTE", "byte", EnumSet.of(TokenType.TYPE)), + CHAR(71, "CHAR", "char", EnumSet.of(TokenType.TYPE)), + SHORT(72, "SHORT", "short", EnumSet.of(TokenType.TYPE)), + INT(73, "INT", "int", EnumSet.of(TokenType.TYPE)), + LONG(74, "LONG", "long", EnumSet.of(TokenType.TYPE)), + FLOAT(75, "FLOAT", "float", EnumSet.of(TokenType.TYPE)), + DOUBLE(76, "DOUBLE", "double", EnumSet.of(TokenType.TYPE)), + VOID(77, "VOID", "void", EnumSet.of(TokenType.TYPE)), + BOOLEAN(78, "BOOLEAN", "boolean", EnumSet.of(TokenType.TYPE)), + /* + * Expression keywords + */ + TRUE(80, "TRUE", "true", EnumSet.of(TokenType.EXPRESSION, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + FALSE(81, "FALSE", "false", EnumSet.of(TokenType.EXPRESSION, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + THIS(82, "THIS", "this", EnumSet.of(TokenType.EXPRESSION)), + SUPER(83, "SUPER", "super", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + NULL(84, "NULL", "null", EnumSet.of(TokenType.EXPRESSION, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + + THIS_CLASS(85, "this_class", "this_class", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + SUPER_CLASS(86, "super_class", "super_class", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + /* + * Statement keywords + */ + IF(90, "IF", "if", EnumSet.of(TokenType.STATEMENT)), + ELSE(91, "ELSE", "else", EnumSet.of(TokenType.STATEMENT)), + FOR(92, "FOR", "for", EnumSet.of(TokenType.STATEMENT)), + WHILE(93, "WHILE", "while", EnumSet.of(TokenType.STATEMENT)), + DO(94, "DO", "do", EnumSet.of(TokenType.STATEMENT)), + SWITCH(95, "SWITCH", "switch", EnumSet.of(TokenType.STATEMENT)), + CASE(96, "CASE", "case", EnumSet.of(TokenType.STATEMENT)), + DEFAULT(97, "DEFAULT", "default", EnumSet.of(TokenType.STATEMENT), KeywordType.KEYWORD), + BREAK(98, "BREAK", "break", EnumSet.of(TokenType.STATEMENT)), + CONTINUE(99, "CONTINUE", "continue", EnumSet.of(TokenType.STATEMENT)), + RETURN(100, "RETURN", "return", EnumSet.of(TokenType.STATEMENT)), + TRY(101, "TRY", "try", EnumSet.of(TokenType.STATEMENT)), + + CATCH(102, "CATCH", "catch", EnumSet.of(TokenType.STATEMENT)), + FINALLY(103, "FINALLY", "finally", EnumSet.of(TokenType.STATEMENT)), + THROW(104, "THROW", "throw", EnumSet.of(TokenType.STATEMENT)), + STAT(105, "STAT", "stat", EnumSet.of(TokenType.STATEMENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + EXPRESSION(106, "EXPRESSION", "expression", EnumSet.of(TokenType.STATEMENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + DECLARATION(107, "DECLARATION", "declaration", EnumSet.of(TokenType.STATEMENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + VARDECLARATION(108, "VARDECLARATION", "vdeclaration", EnumSet.of(TokenType.STATEMENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + /* + * Declaration keywords + */ + IMPORT(110, "IMPORT", "import", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + CLASS(111, "CLASS", "class", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + FILE(52, "FILE", "file", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + CLASS_FILE(53, "CLASSFILE", "classfile", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + EXTENDS(112, "EXTENDS", "extends", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + IMPLEMENTS(113, "IMPLEMENTS", "implements", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + INTERFACE(114, "INTERFACE", "interface", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + PACKAGE(115, "PACKAGE", "package", EnumSet.of(TokenType.DECLARATION), KeywordType.KEYWORD), + ENUM(116, "ENUM", "enum", EnumSet.of(TokenType.DECLARATION), KeywordType.KEYWORD), + MANDATED(117, "MANDATED", "mandated", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME), KeywordType.KEYWORD), + THROWS(118, "THROWS", "throws", EnumSet.of(TokenType.DECLARATION), KeywordType.KEYWORD), + + /* + * Modifier keywords + */ + ANNOTATION_ACCESS(119, "ANNOTATION_ACCESS", "annotation", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + PRIVATE(120, "PRIVATE", "private", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + PUBLIC(121, "PUBLIC", "public", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + PROTECTED(122, "PROTECTED", "protected", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + CONST(123, "CONST", "const", EnumSet.of(TokenType.DECLARATION), KeywordType.KEYWORD), + STATIC(124, "STATIC", "static", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + TRANSIENT(125, "TRANSIENT", "transient", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + SYNCHRONIZED(126, "SYNCHRONIZED", "synchronized", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + NATIVE(127, "NATIVE", "native", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + FINAL(128, "FINAL", "final", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + VOLATILE(129, "VOLATILE", "volatile", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + ABSTRACT(130, "ABSTRACT", "abstract", EnumSet.of(TokenType.MODIFIER), KeywordType.KEYWORD), + TRANSITIVE(131, "TRANSITIVE", "transitive", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME), KeywordType.KEYWORD), + OPEN(132, "OPEN", "open", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME), KeywordType.KEYWORD), + + /* + * Punctuation + */ + AT_SIGN(133, "AT", "@", EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE), + SEMICOLON(134, "SEMICOLON", ";", EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE), + COLON(135, "COLON", ":", EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE), + QUESTIONMARK(136, "QUESTIONMARK", "?", EnumSet.of(TokenType.PUNCTUATION)), + LBRACE(137, "LBRACE", "{", EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE), + RBRACE(138, "RBRACE", "}", EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE), + LPAREN(139, "LPAREN", "(", EnumSet.of(TokenType.PUNCTUATION)), + RPAREN(140, "RPAREN", ")", EnumSet.of(TokenType.PUNCTUATION)), + LSQBRACKET(141, "LSQBRACKET", "[", EnumSet.of(TokenType.PUNCTUATION)), + RSQBRACKET(142, "RSQBRACKET", "]", EnumSet.of(TokenType.PUNCTUATION)), + + ESCAPED_COLON(201, "ESCCOLON", "\\:", EnumSet.of(TokenType.PUNCTUATION)), + ESCAPED_ATSIGH(202, "ESCATSIGH", "\\@", EnumSet.of(TokenType.PUNCTUATION)), + ESCAPED_BACKSLASH(203, "ESCBACKSLASH", "\\\\", EnumSet.of(TokenType.PUNCTUATION)), + /* + * Special tokens + */ + ERROR(145, "ERROR", "error", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + COMMENT(146, "COMMENT", "comment", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + TYPE(147, "TYPE", "type", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + LENGTH(148, "LENGTH", "Length", "length", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + INLINERETURN(149, "INLINERETURN", "inline-return", EnumSet.of(TokenType.MODIFIER)), + INLINEMETHOD(150, "INLINEMETHOD", "inline-method", EnumSet.of(TokenType.MODIFIER)), + INLINENEWINSTANCE(151, "INLINENEWINSTANCE", "inline-new", EnumSet.of(TokenType.MODIFIER)), + + /* + * Added for jasm + */ + METHODREF(152, "METHODREF", "Method", "Methodref", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + FIELDREF(153, "FIELD", "Field", "Fieldref", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + STACK(154, "STACK", "stack", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + LOCAL(155, "LOCAL", "locals", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + CPINDEX(156, "CPINDEX", "CPINDEX", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + CPNAME(157, "CPNAME", "CPName", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + SIGN(158, "SIGN", "SIGN", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME)), + BITS(159, "BITS", "bits", EnumSet.of(TokenType.MISC, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + + INF(160, "INF", "Inf", "Infinity", EnumSet.of(TokenType.MISC, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + NAN(161, "NAN", "NaN", EnumSet.of(TokenType.MISC, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + + INNERCLASS(162, "INNERCLASS", "InnerClass", "InnerClasses", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + OF(163, "OF", "of", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + SYNTHETIC(164, "SYNTHETIC", "synthetic", EnumSet.of(TokenType.MODIFIER, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + STRICT(165, "STRICT", "strict", EnumSet.of(TokenType.MODIFIER, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + DEPRECATED(166, "DEPRECATED", "deprecated", EnumSet.of(TokenType.MODIFIER, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + VERSION(167, "VERSION", "version", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + MODULE(168, "MODULE", "module", EnumSet.of(TokenType.DECLARATION, TokenType.CLASS_NAME), KeywordType.KEYWORD), + ANNOTATION(169, "ANNOTATION", "@", EnumSet.of(TokenType.MISC)), + PARAM_NAME(170, "PARAM_NAME", "#", EnumSet.of(TokenType.MISC)), + + VARARGS(171, "VARARGS", "varargs", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + BRIDGE(172, "BRIDGE", "bridge", EnumSet.of(TokenType.MODIFIER, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + + // Declaration keywords + BOOTSTRAPMETHOD(173, "BOOTSTRAPMETHOD", "BootstrapMethod", "BootstrapMethods", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + NESTHOST(174, "NESTHOST", "NestHost", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + SIGNATURE(175, "SIGNATURE", "Signature", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + NESTMEMBERS(176, "NESTMEMBERS", "NestMembers", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + // + RECORD(177, "RECORD", "Record", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + COMPONENT(178, "COMPONENT", "Component", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + // + PERMITTEDSUBCLASSES(179, "PERMITTEDSUBCLASSES", "PermittedSubclasses", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + SOURCEFILE(180, "SOURCEFILE", "SourceFile", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + ENCLOSINGMETHOD(181, "ENCLOSINGMETHOD", "EnclosingMethod", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + SOURCEDEBUGEXTENSION(182, "SOURCEDEBUGEXTENSION", "SourceDebugExtension", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + //Module statements + REQUIRES(183, "REQUIRES", "requires", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + EXPORTS(184, "EXPORTS", "exports", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + TO(185, "TO", "to", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + USES(186, "USES", "uses", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + PROVIDES(187, "PROVIDES", "provides", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + WITH(188, "WITH", "with", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + OPENS(189, "OPENS", "opens", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME), KeywordType.KEYWORD), + // + + // Table 4.7.20.2-1 type_path_kind + ARRAY_TYPEPATH(190, TypeAnnotationTypes.EPathKind.ARRAY.parseKey(), TypeAnnotationTypes.EPathKind.ARRAY.parseKey(), + EnumSet.of(TokenType.TYPE_PATH_KIND, TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + INNER_TYPE_TYPEPATH(191, TypeAnnotationTypes.EPathKind.INNER_TYPE.parseKey(), TypeAnnotationTypes.EPathKind.INNER_TYPE.parseKey(), + EnumSet.of(TokenType.TYPE_PATH_KIND, TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + WILDCARD_TYPEPATH(192, TypeAnnotationTypes.EPathKind.WILDCARD.parseKey(), TypeAnnotationTypes.EPathKind.WILDCARD.parseKey(), + EnumSet.of(TokenType.TYPE_PATH_KIND, TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + TYPE_ARGUMENT_TYPEPATH(193, TypeAnnotationTypes.EPathKind.TYPE_ARGUMENT.parseKey(), TypeAnnotationTypes.EPathKind.TYPE_ARGUMENT.parseKey(), + EnumSet.of(TokenType.TYPE_PATH_KIND, TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + // Valhalla Declaration keyword(s) attribute + LOADABLEDESCRIPTORS(203, "LOADABLEDESCRIPTORS", "LoadableDescriptors", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + // + STACKMAPTABLE_HEADER(208, "STACKMAPTABLE", "StackMapTable", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + STACKMAP_HEADER(209, "STACKMAP", "StackMap", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + LINETABLE_HEADER(210, "LINETABLE", "LineTable", "LineNumberTable", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + LOCALVARIABLES_HEADER(211, "LOCALVARIABLES", "LocalVariables", "LocalVariableTable", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + LOCALVARIABLETYPES_HEADER(212, "LOCALVARIABLETYPES", "LocalVariableTypes", "LocalVariableTypeTable", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + /* + * Special tokens + */ + LINE(214, "LINE", "line", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + START(215, "START", "Start", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + SLOT(216, "SLOT", "Slot", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + NAME(217, "NAME", "Name", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + DESCRIPTOR(218, "DESCRIPTOR", "Descriptor", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + NUMBEROFENTRIES(219, "NUMBEROFENTRIES", "number_of_entries", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + FRAMETYPE(220, "FRAMETYPE", "frame_type", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + ENTRYTYPE(221, "ENTRYTYPE", "entry_type", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + OFFSETDELTA(222, "OFFSETDELTA", "offset_delta", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + BYTECODEOFFSET(223, "BYTECODEOFFSET", "offset", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + STACKMAP(224, "STACKMAP", "stack_map", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + LOCALSMAP(225, "LOCALSMAP", "locals_map", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + UNSETFIELDS(226, "UNSETFIELDS", "unset_fields", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + ARGUMENTS(227, "ARGUMENTS", "Arguments", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + // new keyword(s) + IDENTITY(228, "IDENTITY", "identity", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD), + VALUE(229, "VALUE", "value", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.CLASS_NAME, TokenType.MODULE_NAME), KeywordType.KEYWORD); + + final static EnumSet ALL_TOKENS = EnumSet.allOf(Token.class); + // Misc Keywords + final private Integer value; // 160 + final private String printValue; // INF + final private String parseKey; // inf + final private String alias; // Infinity + final private EnumSet tokenTypes; // TokenType.MISC, TokenType.MODULE_NAME + final private KeywordType keywordType; // KeywordType.KEYWORD + + public static Optional get(String parseKey, KeywordType keywordType) { + return ALL_TOKENS.stream(). + filter(t -> t.keywordType == keywordType). + filter(t -> t.parseKey.equals(parseKey) || (t.alias != null && t.alias.equals(parseKey))). + findFirst(); + } + + public static Set getTokenByType(TokenType type) { + return ALL_TOKENS.stream().filter(t -> t.tokenTypes.contains(type)). + collect(Collectors.toSet()); + } + + public static Set getTokenByKeywordType(KeywordType keywordType) { + return ALL_TOKENS.stream().filter(t -> t.keywordType.equals(keywordType)). + collect(Collectors.toSet()); + } + + /** + * Checks that this enum element is in an enum list + * + * @param tokens the list of enum elements for checking + * @return true if a tokens list contains this enum element + */ + public boolean in(Token... tokens) { + return tokens != null && Arrays.asList(tokens).contains(this); + } + + // By default, if a KeywordType is not specified, it has the value 'TOKEN' + Token(Integer val, String print, String parseKey, EnumSet tokenTypes) { + this(val, print, parseKey, null, tokenTypes, KeywordType.TOKEN); + } + + Token(Integer val, String print, String parseKey, EnumSet tokenTypes, KeywordType ktype) { + this(val, print, parseKey, null, tokenTypes, ktype); + } + + Token(Integer val, String print, String parseKey, String alias, EnumSet tokenTypes, KeywordType ktype) { + this.value = val; + this.printValue = print; + this.parseKey = parseKey; + this.tokenTypes = tokenTypes; + this.keywordType = ktype; + this.alias = alias; + } + + public String printValue() { + return printValue; + } + + public String parseKey() { + return parseKey; + } + + public String alias() { + return this.alias; + } + + public boolean hasType(TokenType type) { + return tokenTypes.contains(type); + } + + public int value() { + return value; + } + + public boolean isPossibleJasmIdentifier() { + return tokenTypes.contains(TokenType.JASM_IDENT); + } + + public boolean isPossibleModuleName() { + return tokenTypes.contains(TokenType.MODULE_NAME); + } + + public boolean isPossibleClassName() { + return tokenTypes.contains(TokenType.CLASS_NAME); + } + + /** + * Checks a token belonging to the table: Table 4.7.20.2-A. Interpretation of type_path_kind values + * + * @return true if token is ARRAY, INNER_TYPE, WILDCARD or TYPE_ARGUMENT + */ + public boolean possibleTypePathKind() { + return tokenTypes.contains(TokenType.TYPE_PATH_KIND); + } + + @Override + public String toString() { + return "<" + printValue + "> [" + value + "]"; + } + } + + public static Token keyword_token_ident(String idValue) { + return Token.get(idValue, KeywordType.KEYWORD).orElse(Token.IDENT); + } + + public static String asString(List tokens) { + StringBuilder sb = new StringBuilder(""); + for (Token token : tokens) { + if(sb .length() > 0) { + sb.append(", "); + } + sb.append('\'').append(token.parseKey()).append('\''); + } + return sb.toString(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/JasmTool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.Compiler; +import org.openjdk.asmtools.common.Tool; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; +import org.openjdk.asmtools.jasm.JasmEnvironment.JasmBuilder; + +public abstract class JasmTool extends Compiler { + + protected JasmTool(ToolOutput toolOutput) { + super(toolOutput, new StderrLog()); + } + + protected JasmTool(ToolOutput toolOutput, DualStreamToolOutput logger) { + super(toolOutput, logger); + } + + @Override + public JasmEnvironment getEnvironment(ToolOutput toolOutput, DualStreamToolOutput logger) { + JasmBuilder builder = new JasmBuilder(toolOutput, logger); + return builder.build(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LineNumberData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LineNumberData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LineNumberData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LineNumberData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; + +/** + * 4.7.12. The LineNumberTable Attribute + *

+ * LineNumberTable_attribute { + * + * { u2 start_pc; + * u2 line_number; + * } + * + * } + */ +class LineNumberData implements DataWriter { + + int start_pc; + long line_number; + + public LineNumberData(int start_pc, long line_number) { + this.start_pc = start_pc; + this.line_number = line_number; + } + + @Override + public int getLength() { + return 4; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(start_pc); + out.writeShort((int)line_number); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LoadableDescriptorsAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LoadableDescriptorsAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LoadableDescriptorsAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LoadableDescriptorsAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.util.List; + +/** + * Valhalla: + *

+ * LoadableDescriptors_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_descriptors; + * u2 descriptors[number_of_descriptors]; + * } + */ +public class LoadableDescriptorsAttr extends ArrayAttr { + public LoadableDescriptorsAttr(ConstantPool pool, List descriptors) { + super(pool, EAttribute.ATT_LoadableDescriptors, descriptors); + } + + @Override + protected ConstCell classifyConstCell(ConstantPool pool, ConstCell cell) { + return cell; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LocalVariableData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LocalVariableData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LocalVariableData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/LocalVariableData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.ToolLogger; +import org.openjdk.asmtools.jdis.notations.Signature; + +import java.io.IOException; + +/** + Class for entries: local_variable_table[i], local_variable_type_table[i] + * + * 4.7.13. The LocalVariableTable Entry: local_variable_table[i] + *

+ * LocalVariableTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 local_variable_table_length; + * { u2 start_pc; + * u2 length; + * u2 name_index; + * u2 descriptor_index; + * u2 index; + * } local_variable_table[local_variable_table_length]; + * } + *

+ * 4.7.13. The LocalVariableTypeTable Entry: local_variable_type_table[i] + * LocalVariableTypeTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 local_variable_type_table_length; + * { u2 start_pc; + * u2 length; + * u2 name_index; + * u2 signature_index; + * u2 index; + * } local_variable_type_table[local_variable_type_table_length]; + * } + */ +class LocalVariableData implements DataWriter { + private final short index; + + // assisting fields + FieldType fieldType; + Signature fieldSignature; + private short start_pc; + private short length; + private ConstCell nameCell; + private ConstCell descriptorCell; + + /** + * Creates an entry of Local Variable Table + * + * @param index The value of the index item must be a valid index into the local variable array of the current frame. + * The given local variable is at index in the local variable array of the current frame + * var is presented in the form: var index (#)name(_index):(#)descriptor(_index); + */ + public LocalVariableData(short index, short curPC, ConstCell nameCell, ConstCell descriptorCell) { + this.index = index; + this.start_pc = curPC; + this.nameCell = nameCell; + this.descriptorCell = descriptorCell; + } + + public LocalVariableData(short start_pc, short length, short slot, ConstCell nameCell, ConstCell descriptorCell) { + this.start_pc = start_pc; + this.length = length; + this.index = slot; + this.nameCell = nameCell; + this.descriptorCell = descriptorCell; + } + + public FieldType getFieldType() { + if( this.fieldType == null ) { + this.fieldType = FieldType.getFieldType(((String) descriptorCell.ref.value).charAt(0)); + } + return this.fieldType; + } + + public LocalVariableData setFieldType(FieldType fieldType) { + this.fieldType = fieldType; + return this; + } + + public Signature getSignature(ToolLogger logger) { + if ( this.fieldSignature == null) { + this.fieldSignature = new Signature<>(logger, (String) descriptorCell.ref.value); + } + return this.fieldSignature; + } + + public LocalVariableData setFieldSignature(Signature fieldSignature) { + this.fieldSignature = fieldSignature; + return this; + } + + public int getSlotsCount() { + return (getFieldType() == null) ? 0 : this.fieldType.getSlotsCount(); + } + + public short getIndex() { + return index; + } + + @Override + public int getLength() { + return 10; + } + + public void setLength(int CurrentPC) { + this.length = (short) (CurrentPC - start_pc); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(start_pc); + out.writeShort(length); + out.writeShort(nameCell.cpIndex); + out.writeShort(descriptorCell.cpIndex); + out.writeShort(index); + } + + public void setStartPc(short start_pc) { + this.start_pc = start_pc; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Main.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Main.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Main.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Main.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,337 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.inputs.FileInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.PrintWriterOutput; +import org.openjdk.asmtools.common.outputs.StdoutOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualOutputStreamOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; +import org.openjdk.asmtools.common.structure.CFVersion; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.regex.PatternSyntaxException; + +import static org.openjdk.asmtools.Main.*; +import static org.openjdk.asmtools.common.EMessageKind.ERROR; +import static org.openjdk.asmtools.common.Environment.FAILED; +import static org.openjdk.asmtools.common.Environment.OK; +import static org.openjdk.asmtools.common.outputs.FSOutput.FSDestination.DIR; +import static org.openjdk.asmtools.util.ProductInfo.FULL_VERSION; + +/** + * Jasm is an assembler that accepts a text file based on the JASM Specification, + * and produces a .class file for use with a Java Virtual Machine. + *

+ * Main entry point of the JASM assembler :: jasm to class + */ +public class Main extends JasmTool { + + private final CFVersion cfv = new CFVersion(); + + // tool options + private boolean noWriteFlag = false; // Do not write generated class files + + // hidden options + private int byteLimit = 0; + + // hidden options: Parser debug flags + private boolean debugScanner = false; + private boolean debugMembers = false; + private boolean debugCP = false; + private boolean debugAnnot = false; + private boolean debugInstr = false; + private boolean debugAttribute = false; + + public Main(ToolOutput toolOutput, String... argv) { + super(toolOutput); + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, String... argv) { + super(toolOutput, log); + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput, String... argv) { + super(toolOutput, log); + if (toolInput != null) { + fileList.add(toolInput); + } + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput... toolInputs) { + super(toolOutput, log); + Collections.addAll(fileList, toolInputs); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput) { + super(toolOutput, log); + fileList.add(toolInput); + } + + /** + * Deprecated method to support external tools having it + * + * @param ref A stream to which to write reference output + * @param toolName the tool's name (ignored) + */ + @Deprecated + public Main(PrintWriter ref, String toolName) { + super(new PrintWriterOutput(ref)); + } + + /** + * Deprecated method to support external tools having it + * + * @param out A stream to which to write reference output + * @param toolName the tool's name (ignored) + */ + @Deprecated + public Main(PrintStream out, String toolName) { + this(new PrintWriter(out), toolName); + } + + // jasm entry point + public static void main(String... argv) { + Main compiler = new Main(new StdoutOutput(), new StderrLog(), argv); + System.exit(compiler.compile()); + } + + // Run jasm compiler when args already parsed + @Override + public synchronized int compile() { + // compile all input files + int rc = OK; + try { + for (ToolInput inputFileName : fileList) { + environment.setToolInput(inputFileName); + Parser parser = new Parser(environment, cfv); + // Set hidden options: Parser debug flags + parser.setDebugFlags(debugScanner, debugMembers, debugCP, debugAnnot, debugInstr, debugAttribute); + parser.parseFile(); + if (environment.getCount(ERROR) > 0) { + break; + } + if (noWriteFlag) { + continue; + } + ClassData[] clsData = parser.getClassesData(); + for (ClassData cd : clsData) { + String fullyQualifiedName = cd.myClassName; + ToolOutput toolOutput = environment.getToolOutput(); + toolOutput.startClass(fullyQualifiedName, Optional.of(cd.fileExtension), environment); + if (byteLimit > 0) { + cd.setByteLimit(byteLimit); + } + cd.write(toolOutput); + toolOutput.finishClass(fullyQualifiedName); + } + if (environment.hasMessages()) { + rc += environment.flush(true); + } + } + } catch (IOException | URISyntaxException | Error exception) { + environment.printException(exception); + rc++; + } catch (Throwable exception) { + // all untrapped exception/errors that escaped CompilerLogger + environment.printException(exception); + environment.error(exception); + } + if (environment.hasMessages()) rc += environment.flush(true); + return rc; + } + + @Override + public void usage() { + environment.flush(false); + environment.usage(List.of( + "info.usage", + "info.opt.d", + "info.opt.w", + "info.opt.nowrite", + "info.opt.nowarn", + "info.opt.strict", + "info.opt.cv", + "info.opt.fixcv", + "info.opt.fixcv.full", + "info.opt.t", + "info.opt.v", + "info.opt.version" + )); + } + + @Override + protected void parseArgs(String... argv) { + try { + // Parse arguments + for (int i = 0; i < argv.length; i++) { + String arg = argv[i]; + switch (arg) { + // public options + case "-v" -> setVerboseFlag(true); + case "-t" -> { + setVerboseFlag(true); + setTraceFlag(true); + } + case "-strict" -> environment.setStrictWarningsOn(); + case "-nowarn" -> environment.setIgnoreWarningsOn(); + case "-nowrite" -> noWriteFlag = true; + case VERSION_SWITCH -> { + environment.println(FULL_VERSION); + System.exit(OK); + } + case WRITE_SWITCH -> { // -w + environment.setIgnorePackage(true); + setFSDestination(DIR, ++i, argv); + } + case DIR_SWITCH -> setFSDestination(DIR, ++i, argv); + case DUAL_LOG_SWITCH -> this.environment.setOutputs(new DualOutputStreamOutput()); + case "-h", "-help", "-?" -> { + usage(); + System.exit(OK); + } + // overrides cf version even if it's defined in the source file. + case "-fixcv", "-cv" -> { + boolean frozenCFV = (arg.startsWith("-fix")); + if ((i + 1) >= argv.length) { + if (frozenCFV) { + environment.error("err.fix_cv_requires_arg"); + } else { + environment.error("err.cv_requires_arg"); + } + usage(); + throw new IllegalArgumentException(); + } + try { + String cfvArg = argv[++i]; + if (cfvArg.contains("-")) { + if (!frozenCFV) { + throw new NumberFormatException(); + } + String[] versions = cfvArg.split("-", 2); + String[] versionsThreshold = versions[0].split("[.:]+", 2); + String[] versionsUpdate = versions[1].split("[.:]+", 2); + if (versionsThreshold.length != 2 || versionsUpdate.length != 2) { + throw new NumberFormatException(); + } + Pair versionsPair = new Pair<>(Integer.parseInt(versionsThreshold[0]), + Integer.parseInt(versionsThreshold[1])); + if (versionsPair.second > 0xFFFF || versionsPair.first > 0xFFFF) { + throw new NumberFormatException(); + } + cfv.setThreshold(versionsPair.first, versionsPair.second); + versionsPair = new Pair<>(Integer.parseInt(versionsUpdate[0]), Integer.parseInt(versionsUpdate[1])); + if (versionsPair.second > 0xFFFF || versionsPair.first > 0xFFFF) { + throw new NumberFormatException(); + } + cfv.setVersion(versionsPair.first, versionsPair.second).setByParameter(true).setFrozen(true); + } else { + String[] versions = cfvArg.split("[.:]+", 2); + if (versions.length == 2) { + Pair versionsPair = new Pair<>(Integer.parseInt(versions[0]), Integer.parseInt(versions[1])); + if (versionsPair.second > 0xFFFF || versionsPair.first > 0xFFFF) { + throw new NumberFormatException(); + } + cfv.setVersion(Integer.parseInt(versions[0]), Integer.parseInt(versions[1])). + setByParameter(true).setFrozen(frozenCFV); + } else { + throw new NumberFormatException(); + } + } + } catch (PatternSyntaxException | NumberFormatException exception) { + if (frozenCFV) { + environment.error("err.invalid_threshold_major_minor_param"); + } else { + environment.error("err.invalid_major_minor_param"); + } + usage(); + throw new IllegalArgumentException(); + } + } + // non-public options + case "-XdScanner" -> debugScanner = true; + case "-XdMember" -> debugMembers = true; + case "-XdCP" -> debugCP = true; + case "-XdInstr" -> debugInstr = true; + case "-XdAnnot" -> debugAnnot = true; + case "-XdAttr" -> debugAttribute = true; + case "-XdAll" -> { + debugScanner = true; + debugMembers = true; + debugCP = true; + debugInstr = true; + debugAnnot = true; + debugAttribute = true; + } + case "-Xdlimit" -> { + // parses file until the specified byte number + if (i + 1 > argv.length) { + environment.error("err.byte.limit"); + throw new IllegalArgumentException(); + } else { + try { + byteLimit = Integer.parseInt(argv[++i]); + } catch (NumberFormatException e) { + environment.error("err.byte.limit"); + throw new IllegalArgumentException(); + } + } + } + case org.openjdk.asmtools.Main.STDIN_SWITCH -> addStdIn(); + default -> { + if (arg.startsWith("-")) { + environment.error("err.invalid_option", arg); + usage(); + throw new IllegalArgumentException(); + } else { + fileList.add(new FileInput(argv[i])); + } + } + } + } + if (fileList.isEmpty()) { + usage(); + System.exit(FAILED); + } + } catch (IllegalArgumentException iae) { + if (environment.hasMessages()) { + environment.flush(false); + } + System.exit(FAILED); + } + + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MemberData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MemberData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MemberData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MemberData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.ToolLogger; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.ELocation; +import org.openjdk.asmtools.common.structure.EModifier; + +import java.util.ArrayList; + +import static org.openjdk.asmtools.common.structure.EModifier.*; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.SIGNATURE; + +/** + * The common base structure for field_info, method_info, and component_info + */ +abstract public class MemberData> { + + protected final ConstantPool pool; + private final T environment; + protected int access; + protected AttrData syntheticAttr, deprecatedAttr; + protected DataVectorAttr annotAttrVis = null; + protected DataVectorAttr annotAttrInv = null; + protected DataVectorAttr type_annotAttrVis = null; + protected DataVectorAttr type_annotAttrInv = null; + protected AttrData signatureAttr; + protected ELocation attributeLocation = ELocation.unknown; + + public MemberData(ConstantPool pool, T environment) { + this(pool, environment, 0); + } + + public MemberData(ConstantPool pool, T environment, int access) { + this.pool = pool; + this.environment = environment; + this.access = access; + } + + /** + * Checks for the existence of an attribute belonging to the MemberData. + * + * @param attribute the attribute to check for existence + * @return true if the attribute exists + */ + protected > boolean checkExistence(EAttribute attribute) { + throw new RuntimeException("Not implemented yet"); + } + + /** + * Checks for the existence of an attribute belonging to the MemberData. + * + * @param attribute the attribute to check for existence + * @param action the action to take if the attribute exists + * @param the type of the attribute owner + * @return the instance of the attribute owner + */ + protected > M checkExistence(EAttribute attribute, Runnable action) { + if (checkExistence(attribute)) { + action.run(); + } + return (M) this; + } + + protected > M andThenCheck(EAttribute attribute, Runnable action) { + return checkExistence(attribute, action); + } + + public void createPseudoMod() { + // If a member has a Pseudo-modifier + + // create the appropriate marker attributes, + // and clear the PseudoModifiers from the access flags. + if (EModifier.isSyntheticPseudoMod(access)) { + syntheticAttr = new AttrData(pool, EAttribute.ATT_Synthetic); + access &= ~SYNTHETIC_ATTRIBUTE.getFlag(); + } + if (EModifier.isDeprecatedPseudoMod(access)) { + deprecatedAttr = new AttrData(pool, EAttribute.ATT_Deprecated); + access &= ~DEPRECATED_ATTRIBUTE.getFlag(); + } + } + + public T getEnvironment() { + return environment; + } + + public ConstantPool getPool() { + return pool; + } + + public void setSignatureAttr(ConstCell value_cpx) { + if (this.signatureAttr != null) { + CPXAttr cpx = (CPXAttr) signatureAttr; + if (value_cpx.cpIndex != cpx.cell.cpIndex) { + environment.warning("warn.redeclared.attribute", SIGNATURE.parseKey(), + this.attributeLocation.getDescription()); + } + } + signatureAttr = new CPXAttr(pool, EAttribute.ATT_Signature, value_cpx); + } + + public void setSignatureAttr(ConstCell value_cpx, long position) { + if (signatureAttr != null) { + CPXAttr cpx = (CPXAttr) signatureAttr; + if (value_cpx.cpIndex != cpx.cell.cpIndex) { + environment.warning(position, "warn.redeclared.attribute", + SIGNATURE.parseKey(), this.attributeLocation.getDescription()); + } + } + signatureAttr = new CPXAttr(pool, EAttribute.ATT_Signature, value_cpx); + } + + /** + * Retrieves the signature attribute associated with this member. + * + * @return the signature attribute, or null if it has not been set + */ + public AttrData getSignatureAttr() { + return signatureAttr; + } + + + protected abstract DataVector getAttrVector(); + + @SafeVarargs + protected final DataVector getDataVector(D... extraAttrs) { + DataVector attrs = new DataVector(); + for (D extra : extraAttrs) { + if (extra != null) { + attrs.add(extra); + } + } + // common set for [ FieldData, MethodData, RecordData ] + if (annotAttrVis != null) { + attrs.add((D) annotAttrVis); + } + if (annotAttrInv != null) { + attrs.add((D) annotAttrInv); + } + if (type_annotAttrVis != null) { + attrs.add((D) type_annotAttrVis); + } + if (type_annotAttrInv != null) { + attrs.add((D) type_annotAttrInv); + } + return attrs; + } + + public MemberData addAnnotations(ArrayList list) { + if( list != null ) { + for (AnnotationData item : list) { + boolean invisible = item.invisible; + + if (item instanceof TypeAnnotationData typeAnnotationData) { + // Type Annotations + if (invisible) { + if (type_annotAttrInv == null) { + type_annotAttrInv = new DataVectorAttr<>(pool, + EAttribute.ATT_RuntimeInvisibleTypeAnnotations); + } + type_annotAttrInv.add(typeAnnotationData); + } else { + if (type_annotAttrVis == null) { + type_annotAttrVis = new DataVectorAttr<>(pool, + EAttribute.ATT_RuntimeVisibleTypeAnnotations); + } + type_annotAttrVis.add(typeAnnotationData); + } + } else { + // Regular Annotations + if (invisible) { + if (annotAttrInv == null) { + annotAttrInv = new DataVectorAttr<>(pool, + EAttribute.ATT_RuntimeInvisibleAnnotations); + } + annotAttrInv.add(item); + } else { + if (annotAttrVis == null) { + annotAttrVis = new DataVectorAttr<>(pool, + EAttribute.ATT_RuntimeVisibleAnnotations); + } + annotAttrVis.add(item); + } + } + } + } + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MethodData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MethodData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MethodData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/MethodData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.CompilerConstants; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.ELocation; +import org.openjdk.asmtools.common.structure.EModifier; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.TreeMap; + +class MethodData extends MemberData { + + // MethodParameterData Attribute + static class MethodParameterData implements DataWriter { + + int access; + ConstCell name; + + public MethodParameterData(int access, ConstCell name) { + this.access = access; + this.name = name; + } + + @Override + public int getLength() { + return 4; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort((name == null) ? 0 : name.cpIndex); + out.writeShort(access); + } + }// end class MethodParameterData + + /** + * Used to store Parameter Arrays (as attributes) + */ + static public class DataPArrayAttr extends AttrData implements CompilerConstants { + + TreeMap> elements; // Data + int paramsTotal; + + public DataPArrayAttr(ConstantPool pool, EAttribute attribute, int paramsTotal, TreeMap> elements) { + super(pool, attribute); + this.paramsTotal = paramsTotal; + this.elements = elements; + } + + public DataPArrayAttr(ConstantPool pool, EAttribute attribute, int paramsTotal) { + this(pool, attribute, paramsTotal, new TreeMap<>()); + } + + public void put(int paramNum, T element) { + ArrayList v = get(paramNum); + if (v == null) { + v = new ArrayList<>(); + elements.put(paramNum, v); + } + + v.add(element); + } + + public ArrayList get(int paramNum) { + return elements.get(paramNum); + } + + @Override + public int attrLength() { + int length = 1; // One byte for the parameter count + + // calculate overall size here rather than in add() + // because it may not be available at the time of invoking of add() + for (int i = 0; i < paramsTotal; i++) { + ArrayList attrarray = get(i); + if (attrarray != null) { + for (DataWriter item : attrarray) { + length += item.getLength(); + } + } + length += 2; // 2 bytes for the annotation count for each parameter + } + + return length; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); // attr name, attr len + out.writeByte(paramsTotal); // number of parameters(in byte) + + for (int i = 0; i < paramsTotal; i++) { + ArrayList list = get(i); + if (list != null) { + // write out the number of annotations for the current param + out.writeShort(list.size()); + for (T item : list) { + item.write(out); // write the current annotation + } + } else { + out.writeShort(0); + // No annotations to write out + } + } + } + }// end class DataPArrayAttr + + /* Method Data Fields */ + protected ClassData classData; + protected ConstCell nameCell, sigCell; + protected CodeAttr code; + protected DataVectorAttr> exceptions = null; + protected DataVectorAttr methodParameters = null; + protected DataPArrayAttr pannotAttrVis = null; + protected DataPArrayAttr pannotAttrInv = null; + protected DefaultAnnotationAttr defaultAnnot = null; + + public MethodData(ClassData classData, int access, ConstCell name, ConstCell signature, ArrayList> exc_table) { + super(classData.pool, classData.getEnvironment(), access); + this.classData = classData; + this.attributeLocation = ELocation.method_info; + this.addExceptions(exc_table); + nameCell = name; + sigCell = signature; + // Normalize the modifiers to access flags + if (EModifier.hasPseudoMod(access)) { + createPseudoMod(); + } + } + + public void addExceptions(ArrayList> exc_table) { + if ((exc_table != null) && (!exc_table.isEmpty())) { + if (exceptions == null) { + exceptions = new DataVectorAttr<>(classData.pool, EAttribute.ATT_Exceptions, exc_table); + } else { + exceptions.addAll(exc_table); + } + } + } + + public DataVectorAttr> getExceptions() { + return exceptions; + } + + public boolean hasExceptions() { + return (exceptions != null) && (!exceptions.isEmpty()); + } + + /** + * Retrieves the default annotation attribute associated with this method. + * The default annotation is used to store the default value of an annotation + * method. + * + * @return the default annotation attribute, or null if it has not been set + */ + public DefaultAnnotationAttr getDefaultAnnotation() { + return defaultAnnot; + } + + public void addMethodParameter(int totalParams, int paramNum, ConstCell name, int access) { + getEnvironment().traceln("addMethodParameter Param[" + paramNum + "] (name: " + name.toString() + ", Flags (" + access + ")."); + if (methodParameters == null) { + methodParameters = new DataVectorAttr<>(classData.pool, EAttribute.ATT_MethodParameters, true); + for (int i = 0; i < totalParams; i++) { + // initialize the paramName array (in case the name is not given in Jasm syntax) + methodParameters.add(new MethodParameterData(0, null)); + } + } + methodParameters.set(paramNum, new MethodParameterData(access, name)); + } + + public CodeAttr startCode(int paramCount, Indexer max_stack, Indexer max_locals) { + code = new CodeAttr(this, paramCount, max_stack, max_locals); + return code; + } + + public void setDefaultAnnotation(DefaultAnnotationAttr data) { + defaultAnnot = data; + } + + public void addParamAnnotation(int totalParams, int paramNum, AnnotationData data) { + if (!data.invisible) { + if (pannotAttrVis == null) { + pannotAttrVis = new DataPArrayAttr<>(classData.pool, + EAttribute.ATT_RuntimeVisibleParameterAnnotations,totalParams); + } + pannotAttrVis.put(paramNum, data); + + } else { + if (pannotAttrInv == null) { + pannotAttrInv = new DataPArrayAttr<>(classData.pool, + EAttribute.ATT_RuntimeInvisibleParameterAnnotations, totalParams); + } + pannotAttrInv.put(paramNum, data); + } + } + + @Override + protected DataVector getAttrVector() { + DataVector dv = getDataVector( exceptions, syntheticAttr, deprecatedAttr, signatureAttr, methodParameters, code, defaultAnnot); + if (pannotAttrVis != null) { + dv.add(pannotAttrVis); + } + if (pannotAttrInv != null) { + dv.add(pannotAttrInv); + } + return dv; + } + + public void write(CheckedDataOutputStream out) throws IOException, Parser.CompilerError { + out.writeShort(access); + out.writeShort(nameCell.cpIndex); + out.writeShort(sigCell.cpIndex); + getAttrVector().write(out); + } +} // end MethodData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ModuleAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ModuleAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ModuleAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ModuleAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.asmutils.Triplet; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.jdis.ModuleContent; + +import java.io.IOException; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +import static org.openjdk.asmtools.common.structure.EModifier.ACC_OPEN; + +/** + * The module attribute + */ +class ModuleAttr extends AttrData { + // shared data + private ModuleContent.Builder builder; + private final Function findUTF8Cell; + private final Function findClassCell; + private final Function findModuleCell; + private final Function findPackageCell; + + // entries to populate tables of the module attribute + Consumer requires = (d) -> + this.builder.require(d); + BiConsumer> exports = (e, ms) -> + this.builder.exports(new ModuleContent.Exported((ModuleContent.FlaggedTargetType) e), ms); + BiConsumer> opens = (o, ms) -> + this.builder.opens(new ModuleContent.Opened((ModuleContent.FlaggedTargetType) o), ms); + BiConsumer> + provides = (p, cs) -> this.builder.provides(new ModuleContent.Provided(p), cs); + Consumer uses = (u) -> + this.builder.uses(new ModuleContent.Uses(u)); + + ModuleAttr(ClassData classData) { + super(classData.pool, EAttribute.ATT_Module); + builder = new ModuleContent.Builder(); + findUTF8Cell = targetType -> classData.pool.findUTF8Cell(targetType); + findClassCell = targetType -> classData.pool.findClassCell(targetType); + findModuleCell = targetType -> classData.pool.findModuleCell(targetType); + findPackageCell = targetType -> classData.pool.findPackageCell(targetType); + } + + void openModule() { + builder.setModuleFlags(ACC_OPEN.getFlag()); + } + + void setModuleName(String value) { + builder.setModuleName(value); + } + + void setModuleNameCpIndex(int cpIndex) { + builder.setCpIndex(cpIndex); + } + + ModuleAttr build() { + ModuleContent moduleContent = builder.build(); + Content.instance.header = new HeaderStruct(moduleContent.header, findModuleCell, findUTF8Cell); + Content.instance.requiresStruct = new SetStruct<>(moduleContent.requires, findModuleCell, findUTF8Cell); + Content.instance.exportsMapStruct = new MapStruct<>(moduleContent.exports, findPackageCell, findModuleCell); + Content.instance.opensMapStruct = new MapStruct<>(moduleContent.opens, findPackageCell, findModuleCell); + Content.instance.usesStruct = new SetStruct<>(moduleContent.uses, findClassCell, null); + Content.instance.providesMapStruct = new MapStruct<>(moduleContent.provides, findClassCell, findClassCell); + return this; + } + + @Override + public int attrLength() { + return Content.instance.getLength(); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + Content.instance.write(out); + } + + private enum Content implements DataWriter { + instance { + @Override + public int getLength() { + return header.getLength() + + requiresStruct.getLength() + + exportsMapStruct.getLength() + + opensMapStruct.getLength() + + usesStruct.getLength() + + providesMapStruct.getLength(); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + // keep order! + header.write(out); + requiresStruct.write(out); + exportsMapStruct.write(out); + opensMapStruct.write(out); + usesStruct.write(out); + providesMapStruct.write(out); + } + }; + + HeaderStruct header; + SetStruct requiresStruct; + MapStruct exportsMapStruct; + MapStruct opensMapStruct; + SetStruct usesStruct; + MapStruct providesMapStruct; + } + + /** + * u2 {exports|opens}_count; + * { u2 {exports|opens}_index; + * u2 {exports|opens}_flags; + * u2 {exports|opens}_to_count; + * u2 {exports|opens}_to_index[{exports|opens}_to_count]; + * } {exports|opens}[{exports|opens}_count]; + * or + * u2 provides_count; + * { u2 provides_index; + * u2 provides_with_count; + * u2 provides_with_index[provides_with_count]; + * } provides[provides_count]; + */ + private static class MapStruct implements DataWriter { + final List>> exportsOpensList = new ArrayList<>(); + final List>> providesList = new ArrayList<>(); + + MapStruct(Map> source, + Function nameFinder, + Function targetFinder) { + Objects.requireNonNull(source); + source.entrySet().stream().forEach( + e -> { + ArrayList to = new ArrayList<>(); + e.getValue().forEach(mn -> to.add(targetFinder.apply(mn))); + if (e.getKey().isFlagged()) { + exportsOpensList.add(new Triplet<> + (nameFinder.apply(e.getKey()), + ((ModuleContent.FlaggedTargetType) e.getKey()).getFlags(), + to)); + } else { + providesList.add(new Pair<>(nameFinder.apply(e.getKey()), + to)); + } + } + ); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + if (providesList.isEmpty()) { + out.writeShort(exportsOpensList.size()); // u2 {exports|opens}_count; + for (Triplet> triplet : exportsOpensList) { + out.writeShort(triplet.first.cpIndex); // { u2 {exports|opens}_index; + out.writeShort(triplet.second); // u2 {exports|opens}_flags; + out.writeShort(triplet.third.size()); // u2 {exports|opens}_to_count; + for (ConstCell to : triplet.third) + out.writeShort(to.cpIndex); // u2 {exports|opens}_to_index[{exports|opens}_to_count]; } + } + } else { + out.writeShort(providesList.size()); // u2 provides_count; + for (Pair> pair : providesList) { + out.writeShort(pair.first.cpIndex); // { u2 provides_index; + out.writeShort(pair.second.size()); // u2 provides_with_count; + for (ConstCell to : pair.second) + out.writeShort(to.cpIndex); // u2 provides_with_index[provides_with_count]; } + } + } + } + + @Override + public int getLength() { + if (providesList.isEmpty()) { + // (u2:{exports|opens}_count) + (u2:{exports|opens}_index + u2:{exports|opens}_flags u2:{exports|opens}_to_count) * {exports|opens}_count + + return 2 + 6 * exportsOpensList.size() + + // (u2:{exports|opens}_to_index) * {exports|opens}_to_count + exportsOpensList.stream().mapToInt(p -> p.third.size()).filter(s -> s > 0).sum() * 2; + } else { + // (u2 : provides_count) + (u2:provides_index + u2:provides_with_count) * provides_count + + return 2 + 4 * providesList.size() + + // (u2:provides_with_index) * provides_with_count + providesList.stream().mapToInt(p -> p.second.size()).filter(s -> s > 0).sum() * 2; + } + } + } + + private static class HeaderStruct implements DataWriter { + final ConstCell index; + final int flags; + final ConstCell versionIndex; + + HeaderStruct(ModuleContent.Header source, + Function nameFinder, + Function versionFinder) { + index = nameFinder.apply(source); + versionIndex = (source.getModuleVersion() == null) ? null : versionFinder.apply(source.getModuleVersion()); + flags = source.getModuleFlags(); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(index.cpIndex); // u2 module_name_index; + out.writeShort(flags); // u2 module_flags; + out.writeShort(versionIndex == null ? 0 : versionIndex.cpIndex); // u2 module_version_index; + } + + @Override + public int getLength() { + // u2:module_name_index) + u2:module_flags +u2:module_version_index + return 6; + } + } + + /** + * u2 uses_count; + * u2 uses_index[uses_count]; + * or + * u2 requires_count; + * { u2 requires_index; + * u2 requires_flags; + * u2 requires_version_index; + * } requires[requires_count]; + */ + private static class SetStruct implements DataWriter { + final List usesList = new ArrayList<>(); + final List> requiresList = new ArrayList<>(); + + SetStruct(Set source, + Function nameFinder, + Function versionFinder) { + Objects.requireNonNull(source); + source.forEach(e -> { + if (e.isFlagged()) { + requiresList.add(new Triplet<>( + nameFinder.apply(e), + ((ModuleContent.FlaggedTargetType) e).getFlags(), + (((ModuleContent.VersionedFlaggedTargetType) e).getVersion() == null) ? + null : + versionFinder.apply(((ModuleContent.VersionedFlaggedTargetType) e).getVersion()))); + } else { + usesList.add(nameFinder.apply(e)); + } + }); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + if (usesList.isEmpty()) { + out.writeShort(requiresList.size()); // u2 requires_count; + for (Triplet r : requiresList) { + out.writeShort(r.first.cpIndex); // u2 requires_index; + out.writeShort(r.second); // u2 requires_flags; + out.writeShort(r.third == null ? 0 : r.third.cpIndex); // u2 requires_version_index; + } + } else { + out.writeShort(usesList.size()); // u2 uses_count; + for (ConstCell u : usesList) + out.writeShort(u.cpIndex); // u2 uses_index[uses_count]; + } + } + + @Override + public int getLength() { + return usesList.isEmpty() ? + // (u2:requires_count) + (u2:requires_index + u2:requires_flags + u2:requires_version_index) * requires_count + 2 + 6 * requiresList.size() : + // (u2:uses_count) + (u2:uses_index) * uses_count + 2 + 2 * usesList.size(); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NameInfo.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NameInfo.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NameInfo.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NameInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.asmutils.Pair; + +/** + * Wrapper for Pair class for keeping Name information that is the Constant Pool Index and Corresponding Name. + * Usually only one field is set if Option.CPX "CP index along with arguments" is used then cpIndex is set + * otherwise a name. Or manually changed jasm file has both Constant Pool entries and names + */ +public class NameInfo extends Pair { + + public NameInfo(Integer cpIndex, String name) { + super(cpIndex, name); + } + + public NameInfo() { + super(0, ""); + } + + public String name() { + return super.second; + } + + public NameInfo setName(String name) { + super.second = name; + return this; + } + + public int cpIndex() { + return super.first; + } + + public NameInfo setCpIndex(int index) { + super.first = index; + return this; + } + + public boolean isEmpty() { + return (first == 0 && (second == null || second.isEmpty())); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NestMembersAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NestMembersAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NestMembersAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/NestMembersAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.util.List; + +/** + * The "classes[]" data of attributes + * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + */ +public class NestMembersAttr extends ArrayAttr { + public NestMembersAttr(ConstantPool pool, List classes) { + super( pool, EAttribute.ATT_NestMembers, classes); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/OpcodeTables.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/OpcodeTables.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/OpcodeTables.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/OpcodeTables.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,555 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.util.HashMap; + +/** + * OpcodeTables + *

+ * The OpcodeTables class follows a Singleton Pattern. This class contains Enums, that are + * contained in private hash maps (lookup tables and reverse lookup tables). These hash + * maps all have public accessors, which clients use to look-up opcodes. + *

+ * Tokens in this table carry no external state, and are typically treated as constants. + * They do not need to be reset. + */ +public class OpcodeTables { + + public static int MAX_TABLESWITCH_LENGTH = 16384; // 2^14 in bytes + public static int MAX_LOOKUPSWITCH_LENGTH = 16384; // 2^14 in bytes + public static int MAX_LOOKUPSWITCH_PAIRS_COUNT = 2048; // count + + /** + * Initialized keyword and token Hash Maps (and Reverse Tables) + */ + static private final int MaxOpcodes = 301; + static private final HashMap IntToAllOpcodes = new HashMap<>(MaxOpcodes); + static private final HashMap Mnemocodes = new HashMap<>(MaxOpcodes); + + static { + // register all of the tokens + for (Opcode opc : Opcode.values()) { + registerOpcode(opc); + } + + } + + private static void registerOpcode(Opcode opc) { + IntToAllOpcodes.put(opc.value, opc); + Mnemocodes.put(opc.parseKey, opc); + if (opc.alias != null) { + Mnemocodes.put(opc.alias, opc); + } + } + + public static Opcode opcode(String mnemonic) { + return Mnemocodes.get(mnemonic); + } + + public static Opcode opcode(Integer mnem_code) { + return IntToAllOpcodes.get(mnem_code); + } + + /** + * Marker: describes the type of Opcode. + *

+ * certain types of Opcodes will be added to specific lookup tables. + */ + public enum OpcodeType { + NORMAL("Normal"), + NONPRIVELEGED("NonPriv"), + PRIVELEGED("Priv"), + WIDE("Wide"); + + private final String printVal; + + OpcodeType(String print) { + printVal = print; + } + + public String printVal() { + return printVal; + } + + } + + /* Opcode Enums */ + public enum Opcode { + /* Opcodes */ + opc_dead(-2, " opc_dead", 0), + opc_label(-1, "opc_label", 0), + opc_nop(0, "nop", 1), + opc_aconst_null(1, "aconst_null", 1), + opc_iconst_m1(2, "iconst_m1", 1), + opc_iconst_0(3, "iconst_0", 1), + opc_iconst_1(4, "iconst_1", 1), + opc_iconst_2(5, "iconst_2", 1), + opc_iconst_3(6, "iconst_3", 1), + opc_iconst_4(7, "iconst_4", 1), + opc_iconst_5(8, "iconst_5", 1), + opc_lconst_0(9, "lconst_0", 1), + opc_lconst_1(10, "lconst_1", 1), + opc_fconst_0(11, "fconst_0", 1), + opc_fconst_1(12, "fconst_1", 1), + opc_fconst_2(13, "fconst_2", 1), + opc_dconst_0(14, "dconst_0", 1), + opc_dconst_1(15, "dconst_1", 1), + opc_bipush(16, "bipush", 2), + opc_sipush(17, "sipush", 3), + opc_ldc(18, "ldc", 2), + opc_ldc_w(19, "ldc_w", 3), + opc_ldc2_w(20, "ldc2_w", 3), + opc_iload(21, "iload", 2), + opc_lload(22, "lload", 2), + opc_fload(23, "fload", 2), + opc_dload(24, "dload", 2), + opc_aload(25, "aload", 2), + opc_iload_0(26, "iload_0", 1), + opc_iload_1(27, "iload_1", 1), + opc_iload_2(28, "iload_2", 1), + opc_iload_3(29, "iload_3", 1), + opc_lload_0(30, "lload_0", 1), + opc_lload_1(31, "lload_1", 1), + opc_lload_2(32, "lload_2", 1), + opc_lload_3(33, "lload_3", 1), + opc_fload_0(34, "fload_0", 1), + opc_fload_1(35, "fload_1", 1), + opc_fload_2(36, "fload_2", 1), + opc_fload_3(37, "fload_3", 1), + opc_dload_0(38, "dload_0", 1), + opc_dload_1(39, "dload_1", 1), + opc_dload_2(40, "dload_2", 1), + opc_dload_3(41, "dload_3", 1), + opc_aload_0(42, "aload_0", 1), + opc_aload_1(43, "aload_1", 1), + opc_aload_2(44, "aload_2", 1), + opc_aload_3(45, "aload_3", 1), + opc_iaload(46, "iaload", 1), + opc_laload(47, "laload", 1), + opc_faload(48, "faload", 1), + opc_daload(49, "daload", 1), + opc_aaload(50, "aaload", 1), + opc_baload(51, "baload", 1), + opc_caload(52, "caload", 1), + opc_saload(53, "saload", 1), + opc_istore(54, "istore", 2), + opc_lstore(55, "lstore", 2), + opc_fstore(56, "fstore", 2), + opc_dstore(57, "dstore", 2), + opc_astore(58, "astore", 2), + opc_istore_0(59, "istore_0", 1), + opc_istore_1(60, "istore_1", 1), + opc_istore_2(61, "istore_2", 1), + opc_istore_3(62, "istore_3", 1), + opc_lstore_0(63, "lstore_0", 1), + opc_lstore_1(64, "lstore_1", 1), + opc_lstore_2(65, "lstore_2", 1), + opc_lstore_3(66, "lstore_3", 1), + opc_fstore_0(67, "fstore_0", 1), + opc_fstore_1(68, "fstore_1", 1), + opc_fstore_2(69, "fstore_2", 1), + opc_fstore_3(70, "fstore_3", 1), + opc_dstore_0(71, "dstore_0", 1), + opc_dstore_1(72, "dstore_1", 1), + opc_dstore_2(73, "dstore_2", 1), + opc_dstore_3(74, "dstore_3", 1), + opc_astore_0(75, "astore_0", 1), + opc_astore_1(76, "astore_1", 1), + opc_astore_2(77, "astore_2", 1), + opc_astore_3(78, "astore_3", 1), + opc_iastore(79, "iastore", 1), + opc_lastore(80, "lastore", 1), + opc_fastore(81, "fastore", 1), + opc_dastore(82, "dastore", 1), + opc_aastore(83, "aastore", 1), + opc_bastore(84, "bastore", 1), + opc_castore(85, "castore", 1), + opc_sastore(86, "sastore", 1), + opc_pop(87, "pop", 1), + opc_pop2(88, "pop2", 1), + opc_dup(89, "dup", 1), + opc_dup_x1(90, "dup_x1", 1), + opc_dup_x2(91, "dup_x2", 1), + opc_dup2(92, "dup2", 1), + opc_dup2_x1(93, "dup2_x1", 1), + opc_dup2_x2(94, "dup2_x2", 1), + opc_swap(95, "swap", 1), + opc_iadd(96, "iadd", 1), + opc_ladd(97, "ladd", 1), + opc_fadd(98, "fadd", 1), + opc_dadd(99, "dadd", 1), + opc_isub(100, "isub", 1), + opc_lsub(101, "lsub", 1), + opc_fsub(102, "fsub", 1), + opc_dsub(103, "dsub", 1), + opc_imul(104, "imul", 1), + opc_lmul(105, "lmul", 1), + opc_fmul(106, "fmul", 1), + opc_dmul(107, "dmul", 1), + opc_idiv(108, "idiv", 1), + opc_ldiv(109, "ldiv", 1), + opc_fdiv(110, "fdiv", 1), + opc_ddiv(111, "ddiv", 1), + opc_irem(112, "irem", 1), + opc_lrem(113, "lrem", 1), + opc_frem(114, "frem", 1), + opc_drem(115, "drem", 1), + opc_ineg(116, "ineg", 1), + opc_lneg(117, "lneg", 1), + opc_fneg(118, "fneg", 1), + opc_dneg(119, "dneg", 1), + opc_ishl(120, "ishl", 1), + opc_lshl(121, "lshl", 1), + opc_ishr(122, "ishr", 1), + opc_lshr(123, "lshr", 1), + opc_iushr(124, "iushr", 1), + opc_lushr(125, "lushr", 1), + opc_iand(126, "iand", 1), + opc_land(127, "land", 1), + opc_ior(128, "ior", 1), + opc_lor(129, "lor", 1), + opc_ixor(130, "ixor", 1), + opc_lxor(131, "lxor", 1), + opc_iinc(132, "iinc", 3), + opc_i2l(133, "i2l", 1), + opc_i2f(134, "i2f", 1), + opc_i2d(135, "i2d", 1), + opc_l2i(136, "l2i", 1), + opc_l2f(137, "l2f", 1), + opc_l2d(138, "l2d", 1), + opc_f2i(139, "f2i", 1), + opc_f2l(140, "f2l", 1), + opc_f2d(141, "f2d", 1), + opc_d2i(142, "d2i", 1), + opc_d2l(143, "d2l", 1), + opc_d2f(144, "d2f", 1), + opc_i2b(145, "i2b", 1), + opc_i2c(146, "i2c", 1), + opc_i2s(147, "i2s", 1), + opc_lcmp(148, "lcmp", 1), + opc_fcmpl(149, "fcmpl", 1), + opc_fcmpg(150, "fcmpg", 1), + opc_dcmpl(151, "dcmpl", 1), + opc_dcmpg(152, "dcmpg", 1), + opc_ifeq(153, "ifeq", 3), + opc_ifne(154, "ifne", 3), + opc_iflt(155, "iflt", 3), + opc_ifge(156, "ifge", 3), + opc_ifgt(157, "ifgt", 3), + opc_ifle(158, "ifle", 3), + opc_if_icmpeq(159, "if_icmpeq", 3), + opc_if_icmpne(160, "if_icmpne", 3), + opc_if_icmplt(161, "if_icmplt", 3), + opc_if_icmpge(162, "if_icmpge", 3), + opc_if_icmpgt(163, "if_icmpgt", 3), + opc_if_icmple(164, "if_icmple", 3), + opc_if_acmpeq(165, "if_acmpeq", 3), + opc_if_acmpne(166, "if_acmpne", 3), + opc_goto(167, "goto", 3), + opc_jsr(168, "jsr", 3), + opc_ret(169, "ret", 2), + opc_tableswitch(170, "tableswitch", 99), + opc_lookupswitch(171, "lookupswitch", 99), + opc_ireturn(172, "ireturn", 1), + opc_lreturn(173, "lreturn", 1), + opc_freturn(174, "freturn", 1), + opc_dreturn(175, "dreturn", 1), + opc_areturn(176, "areturn", 1), + opc_return(177, "return", 1), + opc_getstatic(178, "getstatic", 3), + opc_putstatic(179, "putstatic", 3), + opc_getfield(180, "getfield", 3), + opc_putfield(181, "putfield", 3), + opc_invokevirtual(182, "invokevirtual", 3), + opc_invokespecial(183, "invokespecial", "invokenonvirtual", 3), + opc_invokestatic(184, "invokestatic", 3), + opc_invokeinterface(185, "invokeinterface", 5), + opc_invokedynamic(186, "invokedynamic", 5), + opc_new(187, "new", 3), + opc_newarray(188, "newarray", 2), + opc_anewarray(189, "anewarray", 3), + opc_arraylength(190, "arraylength", 1), + opc_athrow(191, "athrow", 1), + opc_checkcast(192, "checkcast", 3), + opc_instanceof(193, "instanceof", 3), + opc_monitorenter(194, "monitorenter", 1), + opc_monitorexit(195, "monitorexit", 1), + // Wide Marker (not really an opcode) - Extend local variable index by additional bytes + opc_wide(196, null, "wide", 0), + opc_multianewarray(197, "multianewarray", 4), + opc_ifnull(198, "ifnull", 3), + opc_ifnonnull(199, "ifnonnull", 3), + opc_goto_w(200, "goto_w", 5), + opc_jsr_w(201, "jsr_w", 5), + // JVMS: The third reserved opcode, number 202 (0xca), has the mnemonic breakpoint and is intended to be used + // by debuggers to implement breakpoints. + opc_breakpoint(202, "breakpoint", 1), + + /* Pseudo-instructions */ + opc_bytecode(210, "bytecode", 1), + opc_try(211, "try", 0), + opc_endtry(212, "endtry", 0), + opc_catch(213, "catch", 0), + opc_var(214, "var", 0), + opc_endvar(215, "endvar", 0), + + opc_locals_map(216, "locals_map", 0), + opc_stack_map(217, "stack_map", 0), + opc_unset_fields(218, "unset_fields", 0), + // StackMap Attribute (Java 6.0) This entry point of the beginning of the record or nothing. + opc_stack_map_frame(219, "stack_map_frame", 0), + + // Always must be first record of any entry of the StackMapTable Attribute (Java 7.0 and above) + opc_stack_map_entry(220, "stack_map_entry", 0), + opc_stack_frame_type(221, "stack_frame_type", 0), + opc_frame_type(222, "frame_type", 0), + opc_entry_type(223, "entry_type", 0), + + opc_type(224, "type", 0), + opc_endtype(225, "endtype", 0), + + // JVMS: Two of the reserved opcodes, numbers 254 (0xfe) and 255 (0xff), have the mnemonics impdep1 and impdep2, respectively. + opc_nonpriv(254, "impdep1", 1), + opc_priv(255, "impdep2", 1), + + /* Wide instructions */ + opc_iload_w(opc_iload.value, "iload_w", 4, OpcodeType.WIDE), + opc_lload_w(opc_lload.value, "lload_w", 4, OpcodeType.WIDE), + opc_fload_w(opc_fload.value, "fload_w", 4, OpcodeType.WIDE), + opc_dload_w(opc_dload.value, "dload_w", 4, OpcodeType.WIDE), + opc_aload_w(opc_aload.value, "aload_w", 4, OpcodeType.WIDE), + opc_istore_w(opc_istore.value, "istore_w", 4, OpcodeType.WIDE), + opc_lstore_w(opc_lstore.value, "lstore_w", 4, OpcodeType.WIDE), + opc_fstore_w(opc_fstore.value, "fstore_w", 4, OpcodeType.WIDE), + opc_dstore_w(opc_dstore.value, "dstore_w", 4, OpcodeType.WIDE), + opc_astore_w(opc_astore.value, "astore_w", 4, OpcodeType.WIDE), + opc_ret_w(opc_ret.value, "ret_w", 4, OpcodeType.WIDE), + opc_iinc_w(opc_iinc.value, "iinc_w", 6, OpcodeType.WIDE), + + /* Privileged instructions */ + opc_load_ubyte(0, "load_ubyte", OpcodeType.NONPRIVELEGED), + opc_priv_load_ubyte(0, "priv_load_ubyte", OpcodeType.PRIVELEGED), + opc_load_byte(1, "load_byte", OpcodeType.NONPRIVELEGED), + opc_priv_load_byte(1, "priv_load_byte", OpcodeType.PRIVELEGED), + opc_load_char(2, "load_char", OpcodeType.NONPRIVELEGED), + opc_priv_load_char(2, "priv_load_char", OpcodeType.PRIVELEGED), + opc_load_short(3, "load_short", OpcodeType.NONPRIVELEGED), + opc_priv_load_short(3, "priv_load_short", OpcodeType.PRIVELEGED), + opc_load_word(4, "load_word", OpcodeType.NONPRIVELEGED), + opc_priv_load_word(4, "priv_load_word", OpcodeType.PRIVELEGED), + opc_load_char_oe(10, "load_char_oe", OpcodeType.NONPRIVELEGED), + opc_priv_load_char_oe(10, "priv_load_char_oe", OpcodeType.PRIVELEGED), + opc_load_short_oe(11, "load_short_oe", OpcodeType.NONPRIVELEGED), + opc_priv_load_short_oe(11, "priv_load_short_oe", OpcodeType.PRIVELEGED), + opc_load_word_oe(12, "load_word_oe", OpcodeType.NONPRIVELEGED), + opc_priv_load_word_oe(12, "priv_load_word_oe", OpcodeType.PRIVELEGED), + opc_ncload_ubyte(16, "ncload_ubyte", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_ubyte(16, "priv_ncload_ubyte", OpcodeType.PRIVELEGED), + opc_ncload_byte(17, "ncload_byte", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_byte(17, "priv_ncload_byte", OpcodeType.PRIVELEGED), + opc_ncload_char(18, "ncload_char", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_char(18, "priv_ncload_char", OpcodeType.PRIVELEGED), + opc_ncload_short(19, "ncload_short", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_short(19, "priv_ncload_short", OpcodeType.PRIVELEGED), + opc_ncload_word(20, "ncload_word", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_word(20, "priv_ncload_word", OpcodeType.PRIVELEGED), + opc_ncload_char_oe(26, "ncload_char_oe", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_char_oe(26, "priv_ncload_char_oe", OpcodeType.PRIVELEGED), + opc_ncload_short_oe(27, "ncload_short_oe", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_short_oe(27, "priv_ncload_short_oe", OpcodeType.PRIVELEGED), + opc_ncload_word_oe(28, "ncload_word_oe", OpcodeType.NONPRIVELEGED), + opc_priv_ncload_word_oe(28, "priv_ncload_word_oe", OpcodeType.PRIVELEGED), + opc_cache_flush(30, "cache_flush", OpcodeType.NONPRIVELEGED), + opc_priv_cache_flush(30, "priv_cache_flush", OpcodeType.PRIVELEGED), + opc_store_byte(32, "store_byte", OpcodeType.NONPRIVELEGED), + opc_priv_store_byte(32, "priv_store_byte", OpcodeType.PRIVELEGED), + opc_store_short(34, "store_short", OpcodeType.NONPRIVELEGED), + opc_priv_store_short(34, "priv_store_short", OpcodeType.PRIVELEGED), + opc_store_word(36, "store_word", OpcodeType.NONPRIVELEGED), + opc_priv_store_word(36, "priv_store_word", OpcodeType.PRIVELEGED), + opc_store_short_oe(42, "store_short_oe", OpcodeType.NONPRIVELEGED), + opc_priv_store_short_oe(42, "priv_store_short_oe", OpcodeType.PRIVELEGED), + opc_store_word_oe(44, "store_word_oe", OpcodeType.NONPRIVELEGED), + opc_priv_store_word_oe(44, "priv_store_word_oe", OpcodeType.PRIVELEGED), + opc_ncstore_byte(48, "ncstore_byte", OpcodeType.NONPRIVELEGED), + opc_priv_ncstore_byte(48, "priv_ncstore_byte", OpcodeType.PRIVELEGED), + opc_ncstore_short(50, "ncstore_short", OpcodeType.NONPRIVELEGED), + opc_priv_ncstore_short(50, "priv_ncstore_short", OpcodeType.PRIVELEGED), + opc_ncstore_word(52, "ncstore_word", OpcodeType.NONPRIVELEGED), + opc_priv_ncstore_word(52, "priv_ncstore_word", OpcodeType.PRIVELEGED), + opc_ncstore_short_oe(58, "ncstore_short_oe", OpcodeType.NONPRIVELEGED), + opc_priv_ncstore_short_oe(58, "priv_ncstore_short_oe", OpcodeType.PRIVELEGED), + opc_ncstore_word_oe(60, "ncstore_word_oe", OpcodeType.NONPRIVELEGED), + opc_priv_ncstore_word_oe(60, "priv_ncstore_word_oe", OpcodeType.PRIVELEGED), + opc_zero_line(62, "zero_line", OpcodeType.NONPRIVELEGED), + opc_priv_zero_line(62, "priv_zero_line", OpcodeType.PRIVELEGED), + opc_ret_from_sub(5, "ret_from_sub", OpcodeType.NONPRIVELEGED), + opc_enter_sync_method(63, "enter_sync_method", OpcodeType.NONPRIVELEGED), + opc_priv_ret_from_trap(5, "priv_ret_from_trap", OpcodeType.PRIVELEGED), + opc_priv_read_dcache_tag(6, "priv_read_dcache_tag", OpcodeType.PRIVELEGED), + opc_priv_read_dcache_data(7, "priv_read_dcache_data", OpcodeType.PRIVELEGED), + opc_priv_read_icache_tag(14, "priv_read_icache_tag", OpcodeType.PRIVELEGED), + opc_priv_read_icache_data(15, "priv_read_icache_data", OpcodeType.PRIVELEGED), + opc_priv_powerdown(22, "priv_powerdown", OpcodeType.PRIVELEGED), + opc_priv_read_scache_data(23, "priv_read_scache_data", OpcodeType.PRIVELEGED), + opc_priv_cache_index_flush(31, "priv_cache_index_flush", OpcodeType.PRIVELEGED), + opc_priv_write_dcache_tag(38, "priv_write_dcache_tag", OpcodeType.PRIVELEGED), + opc_priv_write_dcache_data(39, "priv_write_dcache_data", OpcodeType.PRIVELEGED), + opc_priv_write_icache_tag(46, "priv_write_icache_tag", OpcodeType.PRIVELEGED), + opc_priv_write_icache_data(47, "priv_write_icache_data", OpcodeType.PRIVELEGED), + opc_priv_reset(54, "priv_reset", OpcodeType.PRIVELEGED), + opc_priv_write_scache_data(55, "priv_write_scache_data", OpcodeType.PRIVELEGED), + opc_priv_read_reg_0(64, "priv_read_reg_0", OpcodeType.PRIVELEGED), + opc_priv_read_reg_1(65, "priv_read_reg_1", OpcodeType.PRIVELEGED), + opc_priv_read_reg_2(66, "priv_read_reg_2", OpcodeType.PRIVELEGED), + opc_priv_read_reg_3(67, "priv_read_reg_3", OpcodeType.PRIVELEGED), + opc_priv_read_reg_4(68, "priv_read_reg_4", OpcodeType.PRIVELEGED), + opc_priv_read_reg_5(69, "priv_read_reg_5", OpcodeType.PRIVELEGED), + opc_priv_read_reg_6(70, "priv_read_reg_6", OpcodeType.PRIVELEGED), + opc_priv_read_reg_7(71, "priv_read_reg_7", OpcodeType.PRIVELEGED), + opc_priv_read_reg_8(72, "priv_read_reg_8", OpcodeType.PRIVELEGED), + opc_priv_read_reg_9(73, "priv_read_reg_9", OpcodeType.PRIVELEGED), + opc_priv_read_reg_10(74, "priv_read_reg_10", OpcodeType.PRIVELEGED), + opc_priv_read_reg_11(75, "priv_read_reg_11", OpcodeType.PRIVELEGED), + opc_priv_read_reg_12(76, "priv_read_reg_12", OpcodeType.PRIVELEGED), + opc_priv_read_reg_13(77, "priv_read_reg_13", OpcodeType.PRIVELEGED), + opc_priv_read_reg_14(78, "priv_read_reg_14", OpcodeType.PRIVELEGED), + opc_priv_read_reg_15(79, "priv_read_reg_15", OpcodeType.PRIVELEGED), + opc_priv_read_reg_16(80, "priv_read_reg_16", OpcodeType.PRIVELEGED), + opc_priv_read_reg_17(81, "priv_read_reg_17", OpcodeType.PRIVELEGED), + opc_priv_read_reg_18(82, "priv_read_reg_18", OpcodeType.PRIVELEGED), + opc_priv_read_reg_19(83, "priv_read_reg_19", OpcodeType.PRIVELEGED), + opc_priv_read_reg_20(84, "priv_read_reg_20", OpcodeType.PRIVELEGED), + opc_priv_read_reg_21(85, "priv_read_reg_21", OpcodeType.PRIVELEGED), + opc_priv_read_reg_22(86, "priv_read_reg_22", OpcodeType.PRIVELEGED), + opc_priv_read_reg_23(87, "priv_read_reg_23", OpcodeType.PRIVELEGED), + opc_priv_read_reg_24(88, "priv_read_reg_24", OpcodeType.PRIVELEGED), + opc_priv_read_reg_25(89, "priv_read_reg_25", OpcodeType.PRIVELEGED), + opc_priv_read_reg_26(90, "priv_read_reg_26", OpcodeType.PRIVELEGED), + opc_priv_read_reg_27(91, "priv_read_reg_27", OpcodeType.PRIVELEGED), + opc_priv_read_reg_28(92, "priv_read_reg_28", OpcodeType.PRIVELEGED), + opc_priv_read_reg_29(93, "priv_read_reg_29", OpcodeType.PRIVELEGED), + opc_priv_read_reg_30(94, "priv_read_reg_30", OpcodeType.PRIVELEGED), + opc_priv_read_reg_31(95, "priv_read_reg_31", OpcodeType.PRIVELEGED), + opc_priv_write_reg_0(96, "priv_write_reg_0", OpcodeType.PRIVELEGED), + opc_priv_write_reg_1(97, "priv_write_reg_1", OpcodeType.PRIVELEGED), + opc_priv_write_reg_2(98, "priv_write_reg_2", OpcodeType.PRIVELEGED), + opc_priv_write_reg_3(99, "priv_write_reg_3", OpcodeType.PRIVELEGED), + opc_priv_write_reg_4(100, "priv_write_reg_4", OpcodeType.PRIVELEGED), + opc_priv_write_reg_5(101, "priv_write_reg_5", OpcodeType.PRIVELEGED), + opc_priv_write_reg_6(102, "priv_write_reg_6", OpcodeType.PRIVELEGED), + opc_priv_write_reg_7(103, "priv_write_reg_7", OpcodeType.PRIVELEGED), + opc_priv_write_reg_8(104, "priv_write_reg_8", OpcodeType.PRIVELEGED), + opc_priv_write_reg_9(105, "priv_write_reg_9", OpcodeType.PRIVELEGED), + opc_priv_write_reg_10(106, "priv_write_reg_10", OpcodeType.PRIVELEGED), + opc_priv_write_reg_11(107, "priv_write_reg_11", OpcodeType.PRIVELEGED), + opc_priv_write_reg_12(108, "priv_write_reg_12", OpcodeType.PRIVELEGED), + opc_priv_write_reg_13(109, "priv_write_reg_13", OpcodeType.PRIVELEGED), + opc_priv_write_reg_14(110, "priv_write_reg_14", OpcodeType.PRIVELEGED), + opc_priv_write_reg_15(111, "priv_write_reg_15", OpcodeType.PRIVELEGED), + opc_priv_write_reg_16(112, "priv_write_reg_16", OpcodeType.PRIVELEGED), + opc_priv_write_reg_17(113, "priv_write_reg_17", OpcodeType.PRIVELEGED), + opc_priv_write_reg_18(114, "priv_write_reg_18", OpcodeType.PRIVELEGED), + opc_priv_write_reg_19(115, "priv_write_reg_19", OpcodeType.PRIVELEGED), + opc_priv_write_reg_20(116, "priv_write_reg_20", OpcodeType.PRIVELEGED), + opc_priv_write_reg_21(117, "priv_write_reg_21", OpcodeType.PRIVELEGED), + opc_priv_write_reg_22(118, "priv_write_reg_22", OpcodeType.PRIVELEGED), + opc_priv_write_reg_23(119, "priv_write_reg_23", OpcodeType.PRIVELEGED), + opc_priv_write_reg_24(120, "priv_write_reg_24", OpcodeType.PRIVELEGED), + opc_priv_write_reg_25(121, "priv_write_reg_25", OpcodeType.PRIVELEGED), + opc_priv_write_reg_26(122, "priv_write_reg_26", OpcodeType.PRIVELEGED), + opc_priv_write_reg_27(123, "priv_write_reg_27", OpcodeType.PRIVELEGED), + opc_priv_write_reg_28(124, "priv_write_reg_28", OpcodeType.PRIVELEGED), + opc_priv_write_reg_29(125, "priv_write_reg_29", OpcodeType.PRIVELEGED), + opc_priv_write_reg_30(126, "priv_write_reg_30", OpcodeType.PRIVELEGED), + opc_priv_write_reg_31(127, "priv_write_reg_31", OpcodeType.PRIVELEGED); + + private Integer value; + private String parseKey; + private String alias; + private Integer length; + private OpcodeType type; + + Opcode(Integer val, String parse, OpcodeType tp) { + init(val, parse, null, 2, tp); + } + + Opcode(Integer val, String parse, int len, OpcodeType tp) { + init(val, parse, null, len, tp); + } + + Opcode(Integer val, String parse, int len) { + init(val, parse, null, len, OpcodeType.NORMAL); + } + + Opcode(Integer val, String parse, String als, int len) { + init(val, parse, als, len, OpcodeType.NORMAL); + } + + private void init(Integer val, String parse, String als, int len, OpcodeType tp) { + type = tp; + switch (tp) { + case NORMAL -> value = val; + case WIDE -> value = (opc_wide.value << 8) | val; + case PRIVELEGED -> value = (opc_priv.value * 0xFF) + val; + case NONPRIVELEGED -> value = (opc_nonpriv.value * 0xFF) + val; + } + parseKey = parse; + alias = als; + length = len; + } + + public String getPrintName() { + if (alias != null) { + return alias; + } + return parseKey; + } + + public Integer value() { + return value; + } + + public byte byteValue() { + return (byte) (value & 0xFF); + } + + public int length() { + return length; + } + + public String parseKey() { + return parseKey; + } + + public OpcodeType type() { + return type; + } + + // JVMS chapter 6.2. Reserved Opcodes + public boolean isReservedOpcode() { + return this.value >= 0 && this.value < Opcode.opc_bytecode.value(); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAnnotation.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAnnotation.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAnnotation.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAnnotation.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,1165 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + + +import org.openjdk.asmtools.common.SyntaxError; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.jasm.TypeAnnotationTargetInfoData.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.TreeMap; +import java.util.stream.IntStream; + +import static org.openjdk.asmtools.jasm.ClassFileConst.*; +import static org.openjdk.asmtools.jasm.ClassFileConst.AnnotationElementType.*; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.*; +import static org.openjdk.asmtools.jasm.ConstantPool.ConstValue_UTF8; +import static org.openjdk.asmtools.jasm.JasmTokens.AnnotationType.isInvisibleAnnotationToken; +import static org.openjdk.asmtools.jasm.JasmTokens.Token; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; +import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.*; + +/** + * ParserAnnotation + *

+ * ParserAnnotation is a parser class owned by Parser.java. It is primarily responsible + * for parsing Annotations (for classes, methods or fields). + *

+ * ParserAnnotation can parse the different types of Annotation Attributes: + * Runtime(In)Visible Annotations (JDK 6+) Default Annotations (JDK 6+) + * Runtime(In)VisibleParameter Annotations (JDK 7+) Runtime(In)VisibleType Annotations + * (JSR308, JDK8+) + */ +public class ParseAnnotation extends ParseBase { + + /** + * local handles on the scanner, main parser, and the error reporting env + */ + private static final TargetTypeVisitor targetTypeVisitor = new TargetTypeVisitor(); + + protected ParseAnnotation(Parser parentParser) { + super.init(parentParser); + targetTypeVisitor.init(scanner); + } + + protected void scanParamName(int totalParams, int paramNum, MethodData curMethod) throws SyntaxError { + scanner.debugScan(" - - - > [ParserAnnotation.scanParamName]: Begin "); + scanner.scan(); + scanner.expect(Token.LBRACE); + // First scan the Name (String, or CPX to name) + ConstCell nameCell; + if ((scanner.token == Token.IDENT) || scanner.checkTokenIdent()) { + // Got a Class Name + nameCell = parser.parseName(); + } else if (scanner.token == Token.CPINDEX) { + int cpx = scanner.intValue; + nameCell = parser.pool.getCell(cpx); + // check the constant + ConstValue nameCellValue = nameCell.ref; + if (!(nameCellValue instanceof ConstValue_UTF8)) { + // throw an error + environment.error(scanner.pos, "err.paramname.constnum.invaltype", cpx); + throw new SyntaxError(); + } + } else { + // throw scan error - unexpected token + environment.error(scanner.pos, "err.paramname.token.unexpected", scanner.stringValue); + throw new SyntaxError(); + } + + // Got the name cell. Next, scan the access flags + int mod = parser.scanModifiers(); + + scanner.expect(Token.RBRACE); + + curMethod.addMethodParameter(totalParams, paramNum, nameCell, mod); + + scanner.debugScan(" - - - > [ParserAnnotation.scanParamName]: End "); + } + + /** + * The main entry for parsing an annotation list. + * + * @return An ArrayList of parsed annotations + */ + ArrayList parseAnnotations() throws SyntaxError { + ArrayList list = new ArrayList<>(); + while (scanner.token == Token.ANNOTATION) { + if (JasmTokens.AnnotationType.isAnnotationToken(scanner.stringValue)) { + list.add(parseAnnotation()); + } else if (JasmTokens.AnnotationType.isTypeAnnotationToken(scanner.stringValue)) { + list.add(parseTypeAnnotation()); + } else { + return null; + } + } + return (list.size() > 0) ? list : null; + } + + /** + * parseDefaultAnnotation + *

+ * parses a default Annotation attribute + * + * @return the parsed Annotation Attribute + * @throws SyntaxError + * @throws SyntaxError if a scanner error occurs + */ + protected DefaultAnnotationAttr parseDefaultAnnotation() throws SyntaxError { + scanner.scan(); + DefaultAnnotationAttr attr; + DataWriter value = null; + scanner.expect(Token.LBRACE); + + if ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { + value = scanAnnotationData("default"); + } + scanner.expect(Token.RBRACE); + attr = new DefaultAnnotationAttr(parser.pool, EAttribute.ATT_AnnotationDefault, value); + return attr; + } + + /** + * Parses Parameter Annotations attributes. + * + * @param totalParams + * @param curMethod + * @throws SyntaxError if a scanner error occurs + */ + protected void parseParamAnnotation(int totalParams, MethodData curMethod) throws SyntaxError { + scanner.debugScan(" - - - > [ParserAnnotation.parseParamAnnots]: Begin, totalParams = " + totalParams + " "); + // The _method thinks there are N+1 params in the signature + // (N = total params in the call list) + 1 (return value) + // int totalParams = totalParams - 1; + TreeMap> pAnnots = new TreeMap<>(); + + while (scanner.token == INTVAL) { + // Create the Parameter Array for Param Annotations + + // Do something with Parameter annotations + // -------------------- + // First - validate that the parameter number (integer) + // (eg >= 0, < numParams, and param num is not previously set) + int paramNum = scanner.intValue; + Integer iParamNum = Integer.valueOf(paramNum); + if (paramNum < 0 || paramNum >= totalParams) { + //invalid Parameter number. Throw an error. + environment.error(scanner.pos, "err.invalid.paramnum", paramNum); + } + if (pAnnots.get(iParamNum) != null) { + // paramter is already populated with annotations/pnames, Throw an error. + environment.error(scanner.pos, "err.duplicate.paramnum", paramNum); + } + // 2nd - Parse the COLON (invalid if not present) + scanner.scan(); + scanner.expect(Token.COLON); + + // 3rd - parse either an optional ParamName, or a list of annotations + if (scanner.token == Token.PARAM_NAME) { + //parse the ParamName + scanParamName(totalParams, iParamNum, curMethod); + } + + // 4th - parse each Annotation (followed by comma, followed by annotation + // assign array of annotations to param array + if (scanner.token == Token.ANNOTATION) { + ArrayList pAnnot = parseAnnotations(); + pAnnots.put(iParamNum, pAnnot); + + for (AnnotationData data : pAnnot) { + curMethod.addParamAnnotation(totalParams, paramNum, data); + } + } + } + } + + /** + * parseTypeAnnotation - parses an individual annotation. + * + * @return a parsed annotation. + * @throws SyntaxError if a scanner error occurs + */ + private AnnotationData parseTypeAnnotation() throws SyntaxError { + TypeAnnotationData ta; + boolean isInvisible = isInvisibleAnnotationToken(scanner.stringValue); + scanner.scan(); + if (scanner.token == CPINDEX) { + int cpIndex = scanner.intValue; + scanner.debugScan(" [ParserAnnotation.parseTypeAnnotation]: cpIndex = #%d".formatted(cpIndex)); + ta = new TypeAnnotationData(parser.pool.getCell(cpIndex), isInvisible); + } else { + String value = scanner.stringValue; + scanner.debugScan(" [ParserAnnotation.parseTypeAnnotation]: value = %s".formatted(value)); + ta = new TypeAnnotationData(parser.pool.findUTF8Cell(value), isInvisible); + } + + scanner.scan(); + scanner.expect(Token.LBRACE); + + // Scan the usual annotation data + _scanAnnotation(ta); + + // scan the Target (u1: target_type, union{...}: target_info) + _scanTypeTarget(ta); + + if (scanner.token != Token.RBRACE) { + // scan the Location (type_path: target_path) + _scanTargetPath(ta); + } + + scanner.expect(Token.RBRACE); + return ta; + } + + /** + * Parses an individual annotation. + * + * @return a parsed annotation. + * @throws SyntaxError if a scanner error occurs + */ + private AnnotationData parseAnnotation() throws SyntaxError { + AnnotationData ad; + boolean isInvisible = isInvisibleAnnotationToken(scanner.stringValue); + scanner.debugScan(" - - - > [ParserAnnotation.parseAnnotation]: Begin "); + scanner.scan(); + + if (scanner.token == CPINDEX) { + int cpIndex = scanner.intValue; + scanner.debugScan(" [ParserAnnotation.parseAnnotation]: cpIndex = #%d".formatted(cpIndex)); + ad = new AnnotationData(parser.pool.getCell(cpIndex), isInvisible); + } else { + String value = scanner.stringValue; + scanner.debugScan(" [ParserAnnotation.parseAnnotation]: value = %s".formatted(value)); + ad = new AnnotationData(parser.pool.findUTF8Cell(value), isInvisible); + } + + scanner.scan(); + _scanAnnotation(ad); + return ad; + } + + /** + * Parses an individual annotation-data. + * + * @return a parsed annotation. + * @throws SyntaxError if a scanner error occurs + */ + private void _scanAnnotation(AnnotationData annotData) throws SyntaxError { + scanner.debugScan(" - - - > [ParserAnnotation._scanAnnotation]: Begin"); + scanner.expect(Token.LBRACE); + + while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { + ConstCell nameCell = parser.parseName(); + scanner.expect(Token.ASSIGN); + if (nameCell.isSet()) { + ConstValue refValue = nameCell.ref; + if (refValue.tag != ConstType.CONSTANT_UTF8) { + throw new SyntaxError(); + } + String name = refValue.asString(); + scanner.debugScan(" [ParserAnnotation._scanAnnotation]: Annot - Field Name: " + name); + DataWriter dataWriter = scanAnnotationData(name); + annotData.add(new AnnotationData.ElemValuePair(nameCell, dataWriter)); + } else { + if (scanner.token == CPINDEX) { + ConstCell refCell = parser.parseName(); + scanner.debugScan(" [ParserAnnotation._scanAnnotation]: " + nameCell.cpIndex + " = " + refCell.cpIndex); + annotData.add(new AnnotationData.ElemValuePair(nameCell, refCell)); + } else { + DataWriter dataWriter = scanAnnotationData("unknown"); + annotData.add(new AnnotationData.ElemValuePair(nameCell, dataWriter)); + } + } + // consume tokens inbetween annotation fields + if (scanner.token == Token.COMMA) { + scanner.scan(); + } + } + scanner.expect(Token.RBRACE); + } + + /** + * Parses an individual annotation-data. + * + * @return a parsed annotation. + * @throws SyntaxError if a scanner error occurs + */ + private void _scanTypeTarget(TypeAnnotationData annotData) throws SyntaxError { + scanner.debugScan(" [ParserAnnotation._scanTypeTarget]: Begin "); + scanner.expect(Token.LBRACE); + + //Scan the target_type and the target_info + scanner.expect(Token.IDENT); + scanner.debugScan(" [ParserAnnotation._scanTypeTarget]: TargetType: " + scanner.idValue); + ETargetType targetType = ETargetType.getTargetType(scanner.idValue); + if (targetType == null) { + environment.error(scanner.pos, "err.incorrect.typeannot.target", scanner.idValue); + throw new SyntaxError(); + } + + scanner.debugScan(" [ParserAnnotation._scanTypeTarget]: Got TargetType: " + targetType); + + if (targetTypeVisitor.scanner == null) { + targetTypeVisitor.scanner = scanner; + } + targetTypeVisitor.visitExcept(targetType); + + annotData.targetInfo = targetTypeVisitor.getTargetInfo(); + annotData.targetType = targetType; + scanner.debugScan(" [ParserAnnotation._scanTypeTarget]: Got TargetInfo: " + annotData.targetInfo); + + scanner.expect(Token.RBRACE); + } + + /** + * _scanTargetPath + *

+ * parses and fills the type_path structure (4.7.20.2) + *

+ * type_path { + * u1 path_length; + * { u1 type_path_kind; + * u1 type_argument_index; + * } path[path_length]; + * } + * + * @throws SyntaxError if a scanner error occurs + */ + private void _scanTargetPath(TypeAnnotationData annotData) throws SyntaxError { + // parse the location info + scanner.expect(Token.LBRACE); + + while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { + TypePathEntry tpe = _scanTypePathEntry(); + annotData.addTypePathEntry(tpe); + // throw away comma + if (scanner.token == Token.COMMA) { + scanner.scan(); + } + } + + scanner.expect(Token.RBRACE); + } + + /** + * _scanTypeLocation + *

+ * parses a path entry of the type_path. + *

+ * { u1 type_path_kind; + * u1 type_argument_index; + * } + * + * @return a parsed type path. + * @throws SyntaxError if a scanner error occurs + */ + private TypePathEntry _scanTypePathEntry() throws SyntaxError { + TypePathEntry tpe; + + if ((scanner.token != Token.EOF) && scanner.token.possibleTypePathKind()) { + EPathKind pathKind = EPathKind.getPathKind(scanner.stringValue); + if (pathKind == EPathKind.TYPE_ARGUMENT) { + scanner.scan(); + // need to scan the index + // Take the form: TYPE_ARGUMENT{#} + scanner.expect(Token.LBRACE); + int index; + if ((scanner.token != Token.EOF) && (scanner.token == INTVAL)) { + index = scanner.intValue; + scanner.scan(); + } else { + // incorrect Arg index + environment.error(scanner.pos, "err.incorrect.typeannot.pathentry.argindex", scanner.token); + throw new SyntaxError(); + } + tpe = new TypePathEntry(pathKind, index); + scanner.expect(Token.RBRACE); + } else { + tpe = new TypePathEntry(pathKind, 0); + scanner.scan(); + } + } else { + // unexpected Type Path + environment.error(scanner.pos, "err.incorrect.typeannot.pathentry", scanner.token); + throw new SyntaxError(); + } + + return tpe; + } + + /** + * scanAnnotationArray + *

+ * Scans an Array of annotations. + * + * @param name Name of the annotation + * @return Array Element + * @throws SyntaxError if a scanner error occurs + */ + private ArrayElemValue scanAnnotationArray(String name) throws SyntaxError { + scanner.scan(); + ArrayElemValue arrayElem = new ArrayElemValue(); + + while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { + DataWriter dataWriter = scanAnnotationData(name + " {}"); + arrayElem.add(dataWriter); + + // consume tokens inbetween annotation fields + if (scanner.token == Token.COMMA) { + scanner.scan(); + } + } + + scanner.expect(Token.RBRACE); + return arrayElem; + } + + /** + * Scans an annotation enumeration. + * + * @param name Annotation Name + * @return Constant element value for the Class Annotation. + * @throws SyntaxError if a scanner error occurs + */ + private DataWriter scanAnnotationClass(String name) throws SyntaxError { + DataWriter constVal; + // scan the next identifier. + // if it is an Ident, consume it as the class name. + scanner.scan(); + switch (scanner.token) { + case IDENT, STRINGVAL: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Constant Class Field: " + name + " = " + scanner.stringValue); + //need to encode the stringval as an (internal) descriptor. + String desc = scanner.stringValue; + // note: for annotations, a class field points to a string with the class descriptor. + constVal = new ConstElemValue(AE_CLASS.tag(), parser.pool.findUTF8Cell(desc)); + scanner.scan(); + break; + case CPINDEX: + // could be a reference to a class name + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Constant Class Field: " + name + " = " + scanner.stringValue); + Integer ConstNmCPX = Integer.valueOf(scanner.stringValue); + constVal = new ClassElemValue(parser.pool.getCell(ConstNmCPX)); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annot.class", scanner.stringValue); + throw new SyntaxError(); + } + return constVal; + } + + /** + * Scans an annotation enum value. + * + * @return Enumeration Element Value + * @throws SyntaxError if a scanner error occurs + */ + private EnumElemValue scanAnnotationEnum() throws SyntaxError { + scanner.scan(); + EnumElemValue enumval; + switch (scanner.token) { + case IDENT, STRINGVAL: + // could be a string identifying enum class and name + String type = scanner.stringValue; + ConstElemValue typeConst = new ConstElemValue(AE_STRING.tag(), parser.pool.findUTF8Cell(type)); + scanner.scan(); + scanner.expect(Token.FIELD); + switch (scanner.token) { + case IDENT, STRINGVAL: + String name = scanner.stringValue; + ConstElemValue nameConst = new ConstElemValue(AE_STRING.tag(), parser.pool.findUTF8Cell(name)); + enumval = new EnumElemValue(typeConst.constCell, nameConst.constCell); + scanner.scan(); + break; + case CPINDEX: + int nameCpx = scanner.intValue; + enumval = new EnumElemValue(typeConst.constCell, parser.pool.getCell(nameCpx)); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annot.enum.name", scanner.stringValue); + throw new SyntaxError(); + } + break; + case CPINDEX: + int typeCpx = scanner.intValue; + scanner.scan(); + if( scanner.token == Token.FIELD ) { + // skip "." if found + // the new format uses "." to separate type and name: + // @+#24 /* java/lang/annotation/Retention */ { + // #11 /* value */ = enum #16.#17 /* "Ljava/lang/annotation/RetentionPolicy;".RUNTIME */ + // } + scanner.scan(); + } + //need two indexes to form a proper enum + switch (scanner.token) { + case CPINDEX: + int nameCpx = scanner.intValue; + enumval = new EnumElemValue(parser.pool.getCell(typeCpx), parser.pool.getCell(nameCpx)); + scanner.scan(); + break; + case IDENT, STRINGVAL: + // could be a string identifying enum class and name + String enumName = scanner.stringValue; + ConstElemValue nameConst = new ConstElemValue(AE_STRING.tag(), parser.pool.findUTF8Cell(enumName)); + enumval = new EnumElemValue(parser.pool.getCell(typeCpx), nameConst.constCell); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annot.enum.name", scanner.stringValue); + throw new SyntaxError(); + } + break; + default: + environment.error(scanner.pos, "err.incorrect.annot.enum.type", scanner.stringValue); + throw new SyntaxError(); + } + return enumval; + } + + /** + * scanAnnotationData + *

+ * parses the internals of an annotation. + * + * @param name Annotation Name + * @return a Data data structure containing the annotation data. + * @throws IOException for scanning errors. + */ + private DataWriter scanAnnotationData(String name) { + DataWriter dataWriter; + switch (scanner.token) { + // This handles the Annotation types (as normalized in the constant pool) + // Some primitive types (Boolean, char, short, byte) are identified by a keyword. + case INTVAL: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Integer Field: " + name + " = " + scanner.intValue); + dataWriter = new ConstElemValue(CONSTANT_INTEGER.getAnnotationElementTypeValue(), + parser.pool.findIntegerCell(scanner.intValue)); + scanner.scan(); + break; + case DOUBLEVAL: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Double Field: " + name + " = " + scanner.doubleValue); + double dval = scanner.doubleValue; + Long val = Double.doubleToLongBits(dval); + dataWriter = new ConstElemValue(CONSTANT_DOUBLE.getAnnotationElementTypeValue(), + parser.pool.findDoubleCell(val)); + scanner.scan(); + break; + case FLOATVAL: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Float Field: " + name + " = " + scanner.floatValue); + float fval = scanner.floatValue; + Integer val1 = Float.floatToIntBits(fval); + dataWriter = new ConstElemValue(CONSTANT_FLOAT.getAnnotationElementTypeValue(), + parser.pool.findFloatCell(val1)); + scanner.scan(); + break; + case LONGVAL: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Long Field: " + name + " = " + scanner.longValue); + dataWriter = new ConstElemValue(CONSTANT_LONG.getAnnotationElementTypeValue(), + parser.pool.findLongCell(scanner.longValue)); + scanner.scan(); + break; + case STRINGVAL: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: String Field: " + name + " = " + scanner.stringValue); + dataWriter = new ConstElemValue(CONSTANT_UTF8.getAnnotationElementTypeValue(), + parser.pool.findUTF8Cell(scanner.stringValue)); + scanner.scan(); + break; + case CLASS: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Class) keyword: " + scanner.stringValue); + dataWriter = scanAnnotationClass(name); + break; + case ENUM: + // scan the next two identifiers (eg ident.ident), or 2 CPRefs. + // if it is an Ident, use consume it as the class name. + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Enum) keyword: " + scanner.stringValue); + dataWriter = scanAnnotationEnum(); + break; + case IDENT: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: JASM Keyword: (annotation field name: " + name + ") keyword: " + scanner.stringValue); + dataWriter = scanAnnotationIdent(scanner.stringValue, name); + break; + case ANNOTATION: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Annotation Field: " + name + " = " + scanner.stringValue); + dataWriter = new AnnotationElemValue(parseAnnotation()); + break; + case LBRACE: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Annotation Array Field: " + name); + dataWriter = scanAnnotationArray(name); + break; + case CPINDEX: + environment.traceln("[ParserAnnotation.scanAnnotationData]:: Constant Field by index: " + name + " = #" + scanner.stringValue); + int cpIndex = Integer.parseInt(scanner.stringValue); + dataWriter = getElementValueByCPIndex(cpIndex); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annot.token", scanner.token); + throw new SyntaxError(); + } + return dataWriter; + } + + private DataWriter getElementValueByCPIndex(int cpIndex) { + DataWriter dataWriter; + ConstCell cell = parser.pool.getCell(cpIndex); + ConstType type = cell.getType(); + if (type.oneOf(CONSTANT_UNKNOWN, + CONSTANT_INTEGER, CONSTANT_FLOAT, + CONSTANT_LONG, CONSTANT_DOUBLE, + CONSTANT_UTF8)) { + dataWriter = new ConstElemValue(type.getAnnotationElementTypeValue(), cell); + } else { + dataWriter = new ClassElemValue(parser.pool.getCell(cpIndex)); + } + return dataWriter; + } + + /** + * scanAnnotationIdent + *

+ * parses the identifier of an annotation. + * + * @param ident Basic Type identifier + * @param name Annotation Name + * @return Basic Type Annotation data + * @throws SyntaxError if a scanning error occurs + */ + private DataWriter scanAnnotationIdent(String ident, String name) throws SyntaxError { + // Handle JASM annotation Keyword Identifiers + DataWriter dataWriter; + BasicType type = getBasicType(ident); + switch (type) { + case T_BOOLEAN: + // consume the keyword, get the value + scanner.scan(); + switch (scanner.token) { + case INTVAL: + // Handle Boolean value in integer form + environment.traceln("Boolean Field: " + name + " = " + scanner.intValue); + int val = scanner.intValue; + if (val > 1 || val < 0) { + environment.traceln("Warning: Boolean Field: " + name + " value is not 0 or 1, value = " + scanner.intValue); + } + dataWriter = new ConstElemValue(AE_BOOLEAN.tag(), parser.pool.findIntegerCell(val)); + scanner.scan(); + break; + case IDENT: + // handle boolean value with true/false keywords + int val1; + switch (scanner.stringValue) { + case "true": + val1 = 1; + break; + case "false": + val1 = 0; + break; + default: + environment.error(scanner.pos, "err.incorrect.annotation", + AE_BOOLEAN.printValue(), + INTVAL.parseKey() + ", " + + CPINDEX.parseKey() + ", " + + TRUE.parseKey() + ", " + + FALSE.parseKey(), + scanner.stringValue); + throw new SyntaxError(); + } + environment.traceln("Boolean Field: " + name + " = " + scanner.stringValue); + dataWriter = new ConstElemValue(AE_BOOLEAN.tag(), parser.pool.findIntegerCell(val1)); + scanner.scan(); + break; + case CPINDEX: + int cpIndex = Integer.parseInt(scanner.stringValue); + dataWriter = new ConstElemValue(AE_BOOLEAN.tag(), parser.pool.getCell(cpIndex)); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annotation", + AE_BOOLEAN.printValue(), + INTVAL.parseKey() + ", " + CPINDEX.parseKey(), + scanner.stringValue); + throw new SyntaxError(); + } + break; + case T_BYTE: + // consume the keyword, get the value + scanner.scan(); + switch (scanner.token) { + case INTVAL: + environment.traceln("Byte Field: " + name + " = " + scanner.intValue); + int val = scanner.intValue; + if (val > 0xFF) { + environment.traceln("Warning: Byte Field: " + name + " value is greater than 0xFF, value = " + scanner.intValue); + } + dataWriter = new ConstElemValue(AE_BYTE.tag(), parser.pool.findIntegerCell(val)); + scanner.scan(); + break; + case CPINDEX: + int cpIndex = Integer.parseInt(scanner.stringValue); + dataWriter = new ConstElemValue(AE_BYTE.tag(), parser.pool.getCell(cpIndex)); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annotation", + AE_BYTE.printValue(), + INTVAL.parseKey() + ", " + CPINDEX.parseKey(), + scanner.stringValue); + throw new SyntaxError(); + } + break; + case T_CHAR: + // consume the keyword, get the value + scanner.scan(); + switch (scanner.token) { + case INTVAL: + environment.traceln("Char Field: " + name + " = " + scanner.intValue); + Integer val = scanner.intValue; + // Bounds check? + dataWriter = new ConstElemValue(AE_CHAR.tag(), parser.pool.findIntegerCell(val)); + scanner.scan(); + break; + case CPINDEX: + int cpIndex = Integer.parseInt(scanner.stringValue); + dataWriter = new ConstElemValue(AE_CHAR.tag(), parser.pool.getCell(cpIndex)); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annotation", + AE_CHAR.printValue(), + INTVAL.parseKey() + ", " + CPINDEX.parseKey(), + scanner.stringValue); + throw new SyntaxError(); + } + break; + case T_SHORT: + // consume the keyword, get the value + scanner.scan(); + switch (scanner.token) { + case INTVAL: + environment.traceln("Short Field: " + name + " = " + scanner.intValue); + int val = scanner.intValue; + if (val > 0xFFFF) { + environment.traceln("Warning: Short Field: " + name + " value is greater than 0xFFFF, value = " + scanner.intValue); + } + dataWriter = new ConstElemValue(AE_SHORT.tag(), + parser.pool.findIntegerCell(val)); + scanner.scan(); + break; + case CPINDEX: + int cpIndex = Integer.parseInt(scanner.stringValue); + dataWriter = new ConstElemValue(AE_SHORT.tag(), + parser.pool.getCell(cpIndex)); + scanner.scan(); + break; + default: + environment.error(scanner.pos, "err.incorrect.annotation", + AE_SHORT.printValue(), + INTVAL.parseKey() + ", " + CPINDEX.parseKey(), + scanner.stringValue); + throw new SyntaxError(); + } + break; + default: + environment.error(scanner.pos, "err.incorrect.annot.keyword", ident); + throw new SyntaxError(); + } + return dataWriter; + } + + /** + * AnnotationElemValue - used to store Annotation values + */ + static class AnnotationElemValue implements ConstantPoolDataVisitor { + + AnnotationData annotationData; + + AnnotationElemValue(AnnotationData annotationData) { + this.annotationData = annotationData; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(AE_ANNOTATION.tag()); + annotationData.write(out); + } + + @Override + public int getLength() { + return 1 + annotationData.getLength(); + } + + @Override + public T visit(ConstantPool pool) { + annotationData = visitData(annotationData, pool); + return (T) this; + } + } + + /** + * Annotation Element value referring to a class + */ + static class ClassElemValue implements ConstantPoolDataVisitor { + + ConstCell constCell; + + ClassElemValue(ConstCell constCell) { + this.constCell = constCell; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(AE_CLASS.tag()); + constCell.write(out); + } + + @Override + public int getLength() { + return 3; + } + + @Override + public T visit(ConstantPool pool) { + constCell = visitConstCell(constCell, pool); + return (T) this; + } + } + + /** + * Annotation Element value referring to an Array + */ + static class ArrayElemValue implements ConstantPoolDataVisitor { + + ArrayList elemValues; + + ArrayElemValue() { + this.elemValues = new ArrayList<>(); + } + + void add(DataWriter elemValue) { + elemValues.add(elemValue); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(AE_ARRAY.tag()); + out.writeShort(elemValues.size()); + + for (DataWriter eval : elemValues) { + eval.write(out); + } + } + + @Override + public int getLength() { + return 3 + elemValues.stream().flatMapToInt(elem -> IntStream.of(elem.getLength())).sum(); + } + + @Override + public T visit(ConstantPool pool) { + for (DataWriter element : elemValues) { + visitData(element, pool); + } + return (T) this; + } + } + + /** + * Annotation Element value referring to a Constant + */ + static class ConstElemValue implements ConstantPoolDataVisitor { + + char tag; + ConstCell constCell; + + ConstElemValue(char tag, ConstCell constCell) { + this.tag = tag; + this.constCell = constCell; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(tag); + constCell.write(out); + } + + @Override + public int getLength() { + return 3; + } + + @Override + public T visit(ConstantPool pool) { + if (!this.constCell.isSet()) { + this.constCell = visitConstCell(this.constCell, pool); + if (!AnnotationElementType.isSet(this.tag)) { + tag = this.constCell.getAnnotationElementTypeValue(); + } + } + return (T) this; + } + } + + /** + * Element Value for Enums: + * type_name_index + * The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing a field descriptor(4.3.2). + * + * const_name_index + * The constant_pool entry gives the simple name of the enum constant represented by this element_value structure. + */ + static class EnumElemValue implements ConstantPoolDataVisitor { + + ConstCell type; + ConstCell name; + + EnumElemValue(ConstCell type, ConstCell name) { + this.type = type; + this.name = name; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(AE_ENUM.tag()); + type.write(out); + name.write(out); + } + + @Override + public int getLength() { + return 5; + } + + @Override + public T visit(ConstantPool pool) { + this.type = visitConstCell(this.type, pool); + this.name = visitConstCell(this.name, pool); + return (T) this; + } + } + + /** + * Target Type visitor, used for constructing the target-info within a type + * annotation. visitExcept() is the entry point. ti is the constructed target info. + */ + private static class TargetTypeVisitor extends TypeAnnotationTypes.TypeAnnotationTargetVisitor { + + private TypeAnnotationTargetInfoData targetInfoData; + private SyntaxError syntaxError; + private Scanner scanner; + private JasmEnvironment environment; + + public void init(Scanner scanner) { + this.scanner = scanner; + this.environment = scanner.environment; + reset(); + } + + public final void reset() { + targetInfoData = null; + syntaxError = null; + } + + //This is the entry point for a visitor that tunnels exceptions + public void visitExcept(ETargetType targetType) throws SyntaxError { + reset(); + visit(targetType); + if (syntaxError != null) { + throw syntaxError; + } + } + + public TypeAnnotationTargetInfoData getTargetInfo() { + return targetInfoData; + } + + // Gathers Int values, and tunnels any exceptions thrown by the scanner + private int scanIntVal(ETargetType targetType) { + int ret = -1; + if (scanner.token == INTVAL) { + ret = scanner.intValue; + try { + scanner.scan(); + } catch (SyntaxError se) { + syntaxError = se; + } + } else { + environment.error(scanner.pos, "err.incorrect.typeannot.targtype.int", targetType.parseKey(), scanner.token); + syntaxError = new SyntaxError(); + } + return ret; + } + + // Gathers String values, and tunnels any exceptions thrown by the scanner + private String scanStringVal(ETargetType targetType) { + String ret = ""; + if (scanner.token == Token.STRINGVAL) { + ret = scanner.stringValue; + try { + scanner.scan(); + } catch (SyntaxError se) { + syntaxError = se; + } + } else { + environment.error(scanner.pos, "err.incorrect.typeannot.targtype.string", targetType.parseKey(), scanner.token); + syntaxError = new SyntaxError(); + } + return ret; + } + + // Gathers braces, and tunnels any exceptions thrown by the scanner + private void scanBrace(boolean left) { + try { + scanner.expect(left ? Token.LBRACE : Token.RBRACE); + } catch (SyntaxError se) { + syntaxError = se; + } + } + + private boolean errorFound() { + return syntaxError != null; + } + + @Override + public void visit_type_param_target(ETargetType targetType) { + environment.traceln("Type Param Target: "); + int byteval = scanIntVal(targetType); // param index + if (!errorFound()) { + targetInfoData = new TypeAnnotationTargetInfoData.type_parameter_target(targetType, byteval); + } + } + + @Override + public void visit_supertype_target(ETargetType targetType) { + environment.traceln("SuperType Target: "); + int shortval = scanIntVal(targetType); // type index + if (!errorFound()) { + targetInfoData = new TypeAnnotationTargetInfoData.supertype_target(targetType, shortval); + } + } + + @Override + public void visit_typeparam_bound_target(ETargetType targetType) { + environment.traceln("TypeParam Bound Target: "); + int byteval1 = scanIntVal(targetType); // param index + if (errorFound()) { + return; + } + int byteval2 = scanIntVal(targetType); // bound index + if (errorFound()) { + return; + } + targetInfoData = new TypeAnnotationTargetInfoData.type_parameter_bound_target(targetType, byteval1, byteval2); + } + + @Override + public void visit_empty_target(ETargetType targetType) { + environment.traceln("Empty Target: "); + if (!errorFound()) { + targetInfoData = new TypeAnnotationTargetInfoData.empty_target(targetType); + } + } + + @Override + public void visit_methodformalparam_target(ETargetType targetType) { + environment.traceln("MethodParam Target: "); + int byteval = scanIntVal(targetType); // param index + if (!errorFound()) { + targetInfoData = new formal_parameter_target(targetType, byteval); + } + } + + @Override + public void visit_throws_target(ETargetType targetType) { + environment.traceln("Throws Target: "); + int shortval = scanIntVal(targetType); // exception index + if (!errorFound()) { + targetInfoData = new throws_target(targetType, shortval); + } + } + + @Override + public void visit_localvar_target(ETargetType targetType) { + environment.traceln("LocalVar Target: "); + localvar_target locvartab = new localvar_target(targetType, 0); + targetInfoData = locvartab; + + while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { + // consume the left brace + scanBrace(true); + if (errorFound()) { + return; + } + // scan the local var triple + int shortval1 = scanIntVal(targetType); // startPC + if (errorFound()) { + return; + } + int shortval2 = scanIntVal(targetType); // length + if (errorFound()) { + return; + } + int shortval3 = scanIntVal(targetType); // CPX + locvartab.addEntry(shortval1, shortval2, shortval3); + scanBrace(false); + if (errorFound()) { + return; + } + } + } + + @Override + public void visit_catch_target(ETargetType targetType) { + environment.traceln("Catch Target: "); + int shortval = scanIntVal(targetType); // catch index + + targetInfoData = new catch_target(targetType, shortval); + } + + @Override + public void visit_offset_target(ETargetType targetType) { + environment.traceln("Offset Target: "); + int shortval = scanIntVal(targetType); // offset index + if (!errorFound()) { + targetInfoData = new offset_target(targetType, shortval); + } + } + + @Override + public void visit_typearg_target(ETargetType targetType) { + environment.traceln("TypeArg Target: "); + int shortval = scanIntVal(targetType); // offset + if (errorFound()) { + return; + } + int byteval = scanIntVal(targetType); // type index + if (errorFound()) { + return; + } + targetInfoData = new type_argument_target(targetType, shortval, byteval); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAttribute.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAttribute.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAttribute.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseAttribute.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.SyntaxError; +import org.openjdk.asmtools.common.structure.StackMap; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.openjdk.asmtools.common.structure.StackMap.EntryType.*; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; +import static org.openjdk.asmtools.jasm.StackMapData.UNDEFINED; + +public class ParseAttribute extends ParseBase { + + private static final String LocalVariableTable_HEADER = START.parseKey() + LENGTH.parseKey() + SLOT.parseKey() + NAME.parseKey() + DESCRIPTOR.parseKey(); + private static final String LocalVariableTypeTable_HEADER = START.parseKey() + LENGTH.parseKey() + SLOT.parseKey() + NAME.parseKey() + SIGNATURE.parseKey(); + private static final int LocalVariableTable_HEADER_LENGTH = LocalVariableTable_HEADER.length(); + private static final int LocalVariableTypeTable_HEADER_LENGTH = LocalVariableTypeTable_HEADER.length(); + + protected ParseAttribute(Parser parentParser) { + super.init(parentParser); + } + + /** + * Parse either localVariableTable or localVariableTypeTable according to the boolean parameter isTypeTable + * + * @param isTypeTable defines which localVariableTypeTable or localVariableTable is parsed + * @return list of local_variable_table[i] or local_variable_type_table[i] entries + */ + public List parseLocalVariableTable(boolean isTypeTable) { + String attributeName = isTypeTable ? "LocalVariableTypeTable" : "LocalVariableTable"; + String parseKey = isTypeTable ? SIGNATURE.parseKey() : DESCRIPTOR.parseKey(); + String header = isTypeTable ? LocalVariableTypeTable_HEADER : LocalVariableTable_HEADER; + int headerLength = isTypeTable ? LocalVariableTypeTable_HEADER_LENGTH : LocalVariableTable_HEADER_LENGTH; + + ArrayList list = new ArrayList<>(); + scanner.scan(); + if (scanner.token == COLON) { + scanner.scan(); + } + String buffer = ""; + short slot = -1, start_pc = -1, length = -1; + ConstCell nameCell = null, descriptorCell = null; + + while ((scanner.token != EOF) && (scanner.token != RBRACE)) { + switch (scanner.token) { + case START, LENGTH, SLOT, NAME, DESCRIPTOR, SIGNATURE -> { + if (buffer.length() == headerLength || buffer.contains(scanner.stringValue)) { + environment.throwErrorException(scanner.pos, "err.header.locvars", parseKey); + } + buffer += scanner.stringValue; + if (!header.startsWith(buffer)) { + environment.throwErrorException(scanner.pos, "err.header.locvars", parseKey); + } + } + case INTVAL -> { + if (buffer.length() != headerLength) { + environment.throwErrorException(scanner.pos, "err.header.expected.locvars", parseKey); + } + if (start_pc == -1) { + start_pc = (short) scanner.intValue; + } else if (length == -1) { + length = (short) scanner.intValue; + } else if (slot == -1) { + slot = (short) scanner.intValue; + } else { + if (nameCell == null) { + environment.throwErrorException(scanner.pos, "err.expected.locvars", + attributeName, "\"" + NAME.parseKey() + "\""); + } + if (descriptorCell == null) { + environment.throwErrorException(scanner.pos, "err.expected.locvars", + attributeName, "\"" + parseKey + "\""); + } + } + } + case STRINGVAL -> { + verifyPosition(buffer, headerLength, attributeName, parseKey, start_pc, length, slot); + String str = scanner.stringValue; + if (nameCell == null) { + nameCell = parser.pool.findUTF8Cell(str); + } else if (descriptorCell == null) { + descriptorCell = parser.pool.findUTF8Cell(str); + list.add(new LocalVariableData(start_pc, length, slot, nameCell, descriptorCell)); + // next new line + slot = start_pc = length = -1; + nameCell = descriptorCell = null; + } else { + environment.throwErrorException(scanner.pos, "err.header.expected.locvars", parseKey); + } + } + case CPINDEX -> { + // processing class references: Name, [Descriptor|Signature] + verifyPosition(buffer, headerLength, attributeName, parseKey, start_pc, length, slot); + String str = scanner.stringValue; + if (nameCell == null) { + nameCell = parser.pool.findUTF8Cell(str); + } else if (descriptorCell == null) { + descriptorCell = parser.pool.findUTF8Cell(str); + list.add(new LocalVariableData(start_pc, length, slot, nameCell, descriptorCell)); + // next new line + slot = start_pc = length = -1; + nameCell = descriptorCell = null; + } else { + environment.throwErrorException(scanner.pos, "err.header.expected.locvars", parseKey); + } + } + default -> { + if (buffer.length() != headerLength) { + environment.throwErrorException(scanner.pos, "err.header.locvars", + parseKey); + } + if (slot != -1 || start_pc != -1 || length != -1 || nameCell != null || descriptorCell != null) { + environment.throwErrorException(scanner.pos, "err.expected.locvars", + attributeName, " either the line {start_pc length slot \"name\" \"descriptor\"} or " + + "{start_pc length slot name_index descriptor_index}"); + } + return list; + } + } + scanner.scan(); + } + return list; + } + + private void verifyPosition(String buffer, int headerLength, + String attributeName, String parseKey, + short start_pc, short length, short slot) { + if (buffer.length() != headerLength) { + environment.throwErrorException(scanner.pos, "err.header.locvars", parseKey); + } + if (start_pc == -1) { + environment.throwErrorException(scanner.pos, "err.expected.locvars", attributeName, "\"start_pc\""); + } else if (length == -1) { + environment.throwErrorException(scanner.pos, "err.expected.locvars", attributeName, "\"length\""); + } else if (slot == -1) { + environment.throwErrorException(scanner.pos, "err.expected.locvars", attributeName, "\"slot\""); + } + } + + public List parseStackMap() throws SyntaxError, IOException { + if (scanner.token == COLON) { + // ignore + scanner.scan(); + } + ArrayList list = new ArrayList<>(); + int numEntries = 0; + StackMap.EntryType entryType = UNKNOWN_TYPE; + StackMapData stackMapData = null; + + while ((scanner.token != EOF) && (scanner.token != RBRACE)) { + switch (scanner.token) { + case NUMBEROFENTRIES -> { // number_of_entries + scanner.scan(); + scanner.expect(ASSIGN); + if (scanner.token != INTVAL) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"number of entries\""); + } + numEntries = scanner.intValue; + } + case BYTECODEOFFSET -> { // BCI + if (stackMapData != null) { + list.add(stackMapData); + } + scanner.scan(); + scanner.expect(ASSIGN); + if (scanner.token != INTVAL) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "The offset value"); + } + stackMapData = new StackMapData(environment, false); + stackMapData.setPC(scanner.intValue); + } + case LOCALSMAP -> { // locals_map + if (stackMapData == null) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(BYTECODEOFFSET.parseKey())); + } else { + if (stackMapData.localsMap != null && stackMapData.localsMap.size() > 0) { + environment.warning(scanner.pos, "warn.stackmap.redeclared", + "\"%s\"".formatted(LOCALSMAP.parseKey())); + } + scanner.scan(); + scanner.expect(ASSIGN); + if (scanner.token == IDENT && scanner.stringValue.equals(LSQBRACKET.parseKey() + RSQBRACKET.parseKey())) { + // empty list + stackMapData.localsMap = new DataVector(); + } else { + scanner.expectIdentContent(LSQBRACKET); + DataVector localsMap = new DataVector(); + stackMapData.localsMap = localsMap; + while (scanner.token != EOF) { + if (scanner.token == SEMICOLON) { + scanner.scan(); + scanner.expectIdentContent(RSQBRACKET); + break; + } + // list can be empty due to some issues + if (scanner.token == IDENT && scanner.stringValue.equals(RSQBRACKET.parseKey())) { + // LocalsMap could be empty: environment.warning(scanner.pos, "warm.locals_map.empty"); + break; + } + parser.parseMapItem(localsMap); + if (scanner.token != JasmTokens.Token.COMMA) { + if (scanner.token != SEMICOLON) { + environment.throwErrorException(scanner.pos, "err.token.expected", "\"" + + SEMICOLON.parseKey() + "\""); + } + continue; + } + scanner.scan(); + } + continue; + } + } + } + case STACKMAP -> { + if (stackMapData == null) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(BYTECODEOFFSET.parseKey())); + } else { + + if (stackMapData.stackMap != null && stackMapData.stackMap.size() > 0) { + environment.warning(scanner.pos, "warn.stackmap.redeclared", + "\"%s\"".formatted(STACKMAP.parseKey())); + } + scanner.scan(); + scanner.expect(ASSIGN); + if (scanner.token == IDENT && scanner.stringValue.equals(LSQBRACKET.parseKey() + RSQBRACKET.parseKey())) { + // empty list + stackMapData.stackMap = new DataVector(); + + } else { + scanner.expectIdentContent(LSQBRACKET); + DataVector stackMap = new DataVector(); + stackMapData.stackMap = stackMap; + while (scanner.token != EOF) { + if (scanner.token == SEMICOLON) { + scanner.scan(); + scanner.expectIdentContent(RSQBRACKET); + break; + } + // the list can be empty due to some issues + if (scanner.token == IDENT && scanner.stringValue.equals(RSQBRACKET.parseKey())) { + // StackMap could be empty: environment.warning(scanner.pos, "warm.stack_map.empty"); + break; + } + parser.parseMapItem(stackMap); + if (scanner.token != JasmTokens.Token.COMMA) { + if (scanner.token != SEMICOLON) { + environment.throwErrorException(scanner.pos, "err.token.expected", "\"" + + SEMICOLON.parseKey() + "\""); + } + continue; + } + scanner.scan(); + } + continue; + } + } + } + } + scanner.scan(); + } + if (stackMapData != null) { + list.add(stackMapData); + } + return list; + } + + public List parseStackMapTable() throws SyntaxError, IOException { + int wrapLevel = 0; + int numEntries = 0; // - might be used to check that the header's number matches the actual number of records. + ArrayList list = new ArrayList<>(); + int stackFrameTypeValue = UNDEFINED; + StackMap.EntryType entryType = UNKNOWN_TYPE; + StackMapData stackMapData = null; + + scanner.scan(); + if (scanner.token == COLON) { + // ignore + scanner.scan(); + } + while (scanner.token != EOF) { + switch (scanner.token) { + case LBRACE -> { + if (wrapLevel == 0) { + environment.throwErrorException(scanner.pos, "err.larvar.frame.expected"); + } + } + case RBRACE -> { + if (wrapLevel == 0) { + return list; + } + wrapLevel--; + } + case NUMBEROFENTRIES -> { // number_of_entries + scanner.scan(); + scanner.expect(ASSIGN); + if (scanner.token != INTVAL) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"number of entries\""); + } + numEntries = scanner.intValue; + } + case FRAMETYPE, ENTRYTYPE -> { // frame_type, entry_type + scanner.scan(); + scanner.expect(ASSIGN); + if (scanner.token == INTVAL) { + stackFrameTypeValue = scanner.intValue; + entryType = StackMap.EntryType.getByTag(stackFrameTypeValue); + } + if (entryType == UNKNOWN_TYPE) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "An integer within the range of [0 to 255]"); + } + if (entryType == EARLY_LARVAL) { + if (wrapLevel > 2) { // limit of enclosure + environment.throwErrorException(scanner.pos, "err.base.frame.expected"); + } + wrapLevel++; + } + + if (stackMapData == null) { + stackMapData = new StackMapData(environment, parser.curCodeAttr.isTypeCheckingVerifier()); + } else { + JasmTokens.Token expectedToken = stackMapData.checkIntegrity(); + if (expectedToken == null) { + list.add(stackMapData); + stackMapData = new StackMapData(environment, parser.curCodeAttr.isTypeCheckingVerifier()); + } else { + if (expectedToken == STACKMAP || stackMapData.getFrameType() == FULL_FRAME) { + stackMapData.stackMap = new DataVector<>(); + list.add(stackMapData); + stackMapData = new StackMapData(environment, parser.curCodeAttr.isTypeCheckingVerifier()); + environment.warning(scanner.pos, "warn.stackmap.expected", + "\"%s\"".formatted(expectedToken.parseKey())); + } else { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(expectedToken.parseKey())); + } + } + } + stackMapData.setStackFrameType(stackFrameTypeValue); + if (stackMapData.checkIntegrity() == null) { + list.add(stackMapData); + stackMapData = null; + } + continue; + } + case OFFSETDELTA -> { // offset_delta + if (stackMapData == null || stackMapData.getFrameType() == SAME_FRAME) { + if (wrapLevel > 0) { + environment.throwErrorException(scanner.pos, "err.token.expected", RBRACE.parseKey()); + } else { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(FRAMETYPE.parseKey())); + } + } else { + JasmTokens.Token expectedToken = stackMapData.checkIntegrity(); + if (expectedToken != OFFSETDELTA) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(expectedToken.parseKey())); + } + scanner.scan(); + scanner.expect(ASSIGN); + if (scanner.token != INTVAL) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "The offset_delta value"); + } + stackMapData.setOffset(scanner.intValue); + if (stackMapData.checkIntegrity() == null) { + list.add(stackMapData); + stackMapData = null; + } + } + } + case LOCALSMAP -> { // locals_map + if (stackMapData == null || stackMapData.getFrameType() == SAME_FRAME) { + if (wrapLevel > 0) { + environment.throwErrorException(scanner.pos, "err.token.expected", RBRACE.parseKey()); + } else { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(FRAMETYPE.parseKey())); + } + } else { + JasmTokens.Token expectedToken = stackMapData.checkIntegrity(); + if (expectedToken != LOCALSMAP) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(expectedToken.parseKey())); + } + scanner.scan(); + scanner.expect(ASSIGN); + stackMapData.localsMap = new DataVector(); + // The scanner identifies an empty statement ([] in locals_map = []) as an identifier. + if (scanner.token == IDENT && scanner.stringValue.equals(LSQBRACKET.parseKey() + RSQBRACKET.parseKey())) { + scanner.scan(); + } else { + scanner.expectIdentContent(LSQBRACKET); + while (scanner.token != EOF) { + if (scanner.token == SEMICOLON) { + scanner.scan(); + scanner.expectIdentContent(RSQBRACKET); + break; + } + // list can be empty due to some issues + if (scanner.token == IDENT && scanner.stringValue.equals(RSQBRACKET.parseKey())) { + // LocalsMap could be empty: environment.warning(scanner.pos, "warm.locals_map.empty"); + break; + } + parser.parseMapItem(stackMapData.localsMap); + if (scanner.token != JasmTokens.Token.COMMA) { + if (scanner.token != SEMICOLON) { + environment.throwErrorException(scanner.pos, "err.token.expected", "\"" + + SEMICOLON.parseKey() + "\""); + } + continue; + } + scanner.scan(); + } + } + if (stackMapData.checkIntegrity() == null) { + list.add(stackMapData); + stackMapData = null; + } + continue; + } + } + case STACKMAP -> { + if (stackMapData == null || stackMapData.getFrameType() == SAME_FRAME) { + if (wrapLevel > 0) { + environment.throwErrorException(scanner.pos, "err.token.expected", RBRACE.parseKey()); + } else { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(FRAMETYPE.parseKey())); + } + } else { + JasmTokens.Token expectedToken = stackMapData.checkIntegrity(); + if (expectedToken != STACKMAP) { + if (expectedToken != LOCALSMAP || stackMapData.getFrameType() != FULL_FRAME) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(expectedToken.parseKey())); + } + } + scanner.scan(); + scanner.expect(ASSIGN); + stackMapData.stackMap = new DataVector(); + // The scanner identifies an empty statement ([] in stack_map = []) as an identifier. + if (scanner.token == IDENT && scanner.stringValue.equals(LSQBRACKET.parseKey() + RSQBRACKET.parseKey())) { + scanner.scan(); + } else { + scanner.expectIdentContent(LSQBRACKET); + while (scanner.token != EOF) { + if (scanner.token == SEMICOLON) { + scanner.scan(); + scanner.expectIdentContent(RSQBRACKET); + break; + } + // the list can be empty due to some issues + if (scanner.token == IDENT && scanner.stringValue.equals(RSQBRACKET.parseKey())) { + // StackMap could be empty: environment.warning(scanner.pos, "warm.stack_map.empty"); + break; + } + parser.parseMapItem(stackMapData.stackMap); + if (scanner.token != JasmTokens.Token.COMMA) { + if (scanner.token != SEMICOLON) { + environment.throwErrorException(scanner.pos, "err.token.expected", "\"" + + SEMICOLON.parseKey() + "\""); + } + continue; + } + scanner.scan(); + } + } + if (stackMapData.checkIntegrity() == null) { + list.add(stackMapData); + stackMapData = null; + } + continue; + } + } + case UNSETFIELDS -> { + if (stackMapData == null || stackMapData.getFrameType() == SAME_FRAME) { + if (wrapLevel > 0) { + environment.throwErrorException(scanner.pos, "err.token.expected", RBRACE.parseKey()); + } else { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(FRAMETYPE.parseKey())); + } + } else { + JasmTokens.Token expectedToken = stackMapData.checkIntegrity(); + if (expectedToken != UNSETFIELDS) { + environment.throwErrorException(scanner.pos, "err.stackmap.expected", + "\"%s\"".formatted(expectedToken.parseKey())); + } + scanner.scan(); + scanner.expect(ASSIGN); + stackMapData.unsetFields = new DataVector(); + // The scanner identifies an empty statement ([ ] in unset_fields = [ ]) as an identifier. + if (scanner.token == IDENT && scanner.stringValue.equals(LSQBRACKET.parseKey() + RSQBRACKET.parseKey())) { + scanner.scan(); + } else { + scanner.expectIdentContent(LSQBRACKET); + while (scanner.token != EOF) { + if (scanner.token == SEMICOLON) { + scanner.scan(); + scanner.expectIdentContent(RSQBRACKET); + break; + } + // the list can be empty due to some issues + if (scanner.token == IDENT && scanner.stringValue.equals(RSQBRACKET.parseKey())) { + // StackMap could be empty: environment.warning(scanner.pos, "warm.stack_map.empty"); + break; + } + parser.parseNameAndType(stackMapData.unsetFields); + if (scanner.token != JasmTokens.Token.COMMA) { + if (scanner.token != SEMICOLON) { + environment.throwErrorException(scanner.pos, "err.token.expected", SEMICOLON.parseKey()); + } + continue; + } + scanner.scan(); + } + } + if (stackMapData.checkIntegrity() == null) { + list.add(stackMapData); + stackMapData = null; + } + continue; + } + } + } + scanner.scan(); + } + return list; + } + + public List parseLineTable() { + ArrayList list = new ArrayList<>(); + scanner.scan(); + if (scanner.token == COLON) { + // ignore + scanner.scan(); + } + int start_pc = -1, line_number = -1; + boolean newLine = true, colonFound = false; + while ((scanner.token != EOF) && (scanner.token != RBRACE)) { + switch (scanner.token) { + case COLON -> { + if (newLine) { + environment.throwErrorException(scanner.pos, "err.expected.linetable", + "line keyword"); + } + if (line_number == -1) { + environment.throwErrorException(scanner.pos, "err.expected.linetable", + "line_number:"); + } else if (colonFound) { + if (start_pc == -1) + environment.throwErrorException(scanner.pos, "err.expected.linetable", + "start_pc"); + else + environment.throwErrorException(scanner.pos, "err.expected.linetable", + "line keyword"); + } + colonFound = true; + } + case LINE -> { + if (!newLine) { + environment.throwErrorException(scanner.pos, "err.expected.linetable", + "line line_number: start_pc"); + } + newLine = false; + } + case INTVAL -> { + if (line_number == -1) + line_number = scanner.intValue; + else { + start_pc = scanner.intValue; + list.add(new LineNumberData(start_pc, line_number)); + newLine = true; + colonFound = false; + line_number = -1; + start_pc = -1; + } + } + default -> { + if (line_number != -1 || start_pc != -1 || !newLine) { + environment.throwErrorException(scanner.pos, "err.expected.linetable", "line line_number: start_pc"); + } + return list; + } + } + scanner.scan(); + } + return list; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseBase.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseBase.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseBase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseBase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + + +import java.util.function.Supplier; + +/** + * Base helper class for a Parser. + */ +public class ParseBase { + + // debug flag + protected boolean debugFlag; + protected Scanner scanner; + protected Parser parser; + protected JasmEnvironment environment; + + public ParseBase() { + } + + public void init(Parser parentParser) { + this.environment = parentParser.environment; + this.scanner = parentParser.scanner; + this.parser = parentParser; + } + + public void init(JasmEnvironment environment, Parser parser) { + this.environment = environment; + this.scanner = new Scanner(environment); + this.parser = parser; + } + + public void init(JasmEnvironment environment) { + this.environment = environment; + } + + public void setDebugFlag(boolean value) { + debugFlag = value; + } + + protected void traceMethodInfoLn() { + traceMethodInfoLn(() -> null); + } + + protected void traceMethodInfoLn(String str) { + traceMethodInfoLn(() -> str); + } + + protected void traceMethodInfoLn(Supplier supplier) { + if (debugFlag) { + String str = supplier.get(); + StackTraceElement elem = Thread.currentThread().getStackTrace()[str == null ? 3 : 2]; + String msg = String.format("%s::%s[%d]%s", + elem.getClassName().substring(elem.getClassName().lastIndexOf('.') + 1), + elem.getMethodName(), elem.getLineNumber(), str == null ? "" : " " + str); + environment.traceln(msg); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseConstPool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseConstPool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseConstPool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseConstPool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,716 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.SyntaxError; + +import java.util.ArrayList; +import java.util.function.BiFunction; + +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.ClassFileConst.*; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.*; +import static org.openjdk.asmtools.jasm.ConstantPool.*; +import static org.openjdk.asmtools.jasm.JasmTokens.Token; + +/** + * ParserCP + *

+ * ParseCP is a parser class owned by Parser.java. It is primarily responsible for parsing + * the constant pool and constant declarations. + */ +public class ParseConstPool extends ParseBase { + + // Visitor object + private final ParserCPVisitor pConstVstr; + // Stop parsing a source file immediately and interpret any issue as an error + private boolean exitImmediately = false; + // counter of left braces + private int lbrace = 0; + + /** + * main constructor + */ + protected ParseConstPool(Parser parentParser) { + super.init(parentParser); + pConstVstr = new ParserCPVisitor(); + } + + /** + * In particular cases, it's necessary to interpret a warning issue as an error and + * stop parsing a source file immediately + * cpParser.setExitImmediately(true); + * parseConstRef(...); + * cpParser.setExitImmediately(false); + */ + public void setExitImmediately(boolean exitImmediately) { + this.exitImmediately = exitImmediately; + } + + /** + * Parse CONSTVALUE + */ + protected ConstValue parseConstValue(ConstType tag) throws SyntaxError { + return pConstVstr.visitExcept(tag); + } + + private ConstType scanConstByID(boolean ignoreKeywords, boolean isBSMArgTag) throws SyntaxError { + ConstType tag = null; + if (!ignoreKeywords) { + tag = (isBSMArgTag) ? ClassFileConst.getBSMArgumentTypeByParseKey(scanner.idValue) : + ClassFileConst.getByParseKey(scanner.idValue); + } + traceMethodInfoLn(format("\t\tTag: %s ", tag == null ? "" : tag)); + return tag; + } + + private ConstType scanConstPrimVal() throws SyntaxError { + ConstType tag; + switch (scanner.token) { + case BYTE -> tag = CONSTANT_BYTE; + case BYTEVAL -> tag = CONSTANT_C_BYTE; + case CHAR -> tag = CONSTANT_CHAR; + case CHARVAL -> tag = CONSTANT_C_CHAR; + case DOUBLE -> tag = CONSTANT_DOUBLE; + case DOUBLEVAL -> tag = CONSTANT_C_DOUBLE; + case FLOAT -> tag = ConstType.CONSTANT_FLOAT; + case FLOATVAL -> tag = ConstType.CONSTANT_C_FLOAT; + case LONG -> tag = ConstType.CONSTANT_LONG; + case LONGVAL -> tag = ConstType.CONSTANT_C_LONG; + case INT -> tag = CONSTANT_INT; + case INTVAL -> tag = CONSTANT_INTEGER; + case SHORT -> tag = CONSTANT_SHORT; + case SHORTVAL -> tag = CONSTANT_C_SHORT; + case BOOLEAN -> tag = CONSTANT_BOOLEAN; + case BOOLEANVAL -> tag = CONSTANT_C_BOOLEAN; + case STRINGVAL, BITS, IDENT -> tag = ConstType.CONSTANT_STRING; + default -> { + // problem - no constant value + environment.error(scanner.pos, "err.value.expected", scanner.token.printValue()); + throw new SyntaxError(); + } + } + return tag; + } + + private void checkWrongTag(ConstType tag, ConstType defaultTag, ConstType default2Tag) throws SyntaxError { + if (defaultTag != null) { + if (!tag.equals(defaultTag)) { + if (default2Tag == null) { + if (exitImmediately) { + environment.error(scanner.pos, "err.wrong.tag", defaultTag.parseKey()); + throw new SyntaxError().setFatal(); + } + environment.warning(scanner.pos, "warn.wrong.tag", defaultTag.parseKey()); + } else if (!tag.equals(default2Tag)) { + if (exitImmediately) { + environment.error(scanner.pos, "err.wrong.tag2", defaultTag.parseKey(), default2Tag.parseKey()); + throw new SyntaxError().setFatal(); + } + environment.warning(scanner.pos, "warn.wrong.tag2", defaultTag.parseKey(), default2Tag.parseKey()); + } + } + } + } + + protected ConstValue parseTagConstValue(ConstType defaultTag, ConstType default2Tag, + boolean ignoreKeywords, boolean isBSMArgTag) throws SyntaxError { + traceMethodInfoLn(() -> "\t<< DefaultTag: %s 2nd DefaultTag: %s IgnoreKeyword?: %b". + formatted(defaultTag == null ? "" : defaultTag, + default2Tag == null ? "" : default2Tag, ignoreKeywords)); + // Lookup the Tag from the scanner + ConstType tag = scanConstByID(ignoreKeywords, isBSMArgTag); + traceMethodInfoLn("\tResult Tag: %s >>".formatted(tag)); + // If the scanned tag is null + if (tag == null) { + // and, if the expected tag is null + if (defaultTag == null) { + // return some other type of constant as the tag + tag = scanConstPrimVal(); + } else { + // otherwise, make the scanned-tag the same constant-type + // as the expected tag. + tag = defaultTag; + } + } else { + // If the scanned tag is some constant type + // and the scanned type does not equal the expected type + checkWrongTag(tag, defaultTag, default2Tag); + scanner.scan(); + } + return parseConstValue(tag); + } // end parseTagConstValue + + protected ConstCell parseConstRef(ConstType defaultTag) throws SyntaxError { + return parseConstRef(defaultTag, null, false); + } + + /** + * Parses a pair [TAG CONSTVALUE] from a constant pool entry [const #DD = TAG CONSTVALUE]. + * + * @return a ConstantCell holding the ConstValue + * @throws SyntaxError if a syntax error occurs + */ + protected ConstCell parseConstPoolRef() throws SyntaxError { + ConstType tag = scanConstByID(false, true); + // check a tag: + ConstValue ref; + if (tag == null || tag.getTag() < 1) { + // if element is given without tag, + // i.e. instead of const #dd = long 1l; is written const #dd = 1l; + ref = switch (scanner.token) { + case IDENT -> { + String value = scanner.stringValue; + if( value.equalsIgnoreCase("true") ) { + yield new ConstValue_Integer(CONSTANT_BOOLEAN, 1); + } else if (value.equalsIgnoreCase("false") ) { + yield new ConstValue_Integer(CONSTANT_BOOLEAN, 0); + } + environment.error(scanner.pos, "err.constant.kind.expected"); + throw new SyntaxError().setFatal(); + } + case STRINGVAL -> new ConstValue_UTF8(scanner.stringValue); + case INTVAL -> new ConstValue_Integer(CONSTANT_INT, scanner.intValue); + case BYTEVAL -> new ConstValue_Integer(CONSTANT_BYTE, scanner.intValue); + case SHORTVAL -> new ConstValue_Integer(CONSTANT_SHORT, scanner.intValue); + case CHARVAL -> new ConstValue_Integer(CONSTANT_CHAR, scanner.intValue); + case BOOLEANVAL -> new ConstValue_Integer(CONSTANT_BOOLEAN, scanner.intValue); + case FLOATVAL -> new ConstValue_Float(Float.floatToIntBits(scanner.floatValue)); + case DOUBLEVAL -> new ConstValue_Double(Double.doubleToLongBits(scanner.doubleValue)); + case LONGVAL -> new ConstValue_Long(scanner.longValue); + default -> { + environment.error(scanner.pos, "err.constant.kind.expected"); + throw new SyntaxError().setFatal(); + } + }; + scanner.scan(); + return parser.pool.findCell(ref); + } + scanner.scan(); + ref = parseConstValue(tag); + return parser.pool.findCell(ref); + } + + protected ConstCell parseConstRef(ConstType defaultTag, ConstType default2Tag) throws SyntaxError { + return parseConstRef(defaultTag, default2Tag, false); + } + + /** + * Parse an instruction argument, one of: * #NUMBER, #NAME, [TAG] CONSTVALUE + */ + protected ConstCell parseConstRef(ConstType defaultTag, + ConstType default2Tag, + boolean ignoreKeywords) throws SyntaxError { + if (scanner.token == Token.CPINDEX) { + int cpx = scanner.intValue; + scanner.scan(); + return parser.pool.getCell(cpx); + } else { + ConstValue ref = parseTagConstValue(defaultTag, default2Tag, ignoreKeywords, false); + return parser.pool.findCell(ref); + } + } // end parseConstRef + + protected ConstCell parseBSMArgumentConstRef() throws SyntaxError { + if (scanner.token == Token.CPINDEX) { + int cpx = scanner.intValue; + scanner.scan(); + return parser.pool.getCell(cpx); + } else { + ConstValue ref = parseTagConstValue(null, null, false, true); + return parser.pool.findCell(ref); + } + } // end parseConstRef + + /** + * ParserCPVisitor + *

+ * This inner class overrides a constant pool visitor to provide specific parsing + * instructions (per method) for each type of Constant. + *

+ * Note: since the generic visitor throws no exceptions, this derived class tunnels + * the exceptions, rethrown in the visitExcept method. + */ + class ParserCPVisitor extends CPTagVisitor> { + + private SyntaxError syntaxError; + + //This is the entry point for a visitor that tunnels exceptions + public ConstValue visitExcept(ConstType tag) throws SyntaxError { + syntaxError = null; + traceMethodInfoLn(); + ConstValue ret = visit(tag); + if (syntaxError != null) { + throw syntaxError; + } + return ret; + } + + @Override + public ConstValue visitUTF8() { + traceMethodInfoLn(); + try { + scanner.expect(Token.STRINGVAL); + } catch (SyntaxError se) { + syntaxError = se; + } + return new ConstValue_UTF8(scanner.stringValue); + } + + @Override + public ConstValue visitInteger(ClassFileConst.ConstType tag) { + traceMethodInfoLn(); + int v = 0; + try { + if (scanner.token == Token.BITS) { + scanner.scan(); + scanner.inBits = true; + } + v = scanner.intValue * scanner.sign; + scanner.expect(Token.INTVAL); + } catch (SyntaxError se) { + syntaxError = se; + } + return new ConstValue_Integer(tag, v); + } + + @Override + public ConstValue visitLong() { + traceMethodInfoLn(); + ConstValue_Long valueLong = null; + try { + long v; + if (scanner.token == Token.BITS) { + scanner.scan(); + scanner.inBits = true; + } + switch (scanner.token) { + case INTVAL -> v = scanner.intValue; + case LONGVAL -> v = scanner.longValue; + default -> { + environment.error(scanner.prevPos, "err.token.expected", "Integer"); + throw new SyntaxError(); + } + } + valueLong = new ConstValue_Long(v * scanner.sign); + scanner.scan(); + } catch (SyntaxError se) { + syntaxError = se; + } + return valueLong; + } + + @Override + public ConstValue visitFloat() { + traceMethodInfoLn(); + ConstValue_Float valueFloat = null; + try { + int v; + float f; + scanner.inBits = false; // this needs to be initialized for each float! + if (scanner.token == Token.BITS) { + scanner.scan(); + scanner.inBits = true; + } + i2f: + { + switch (scanner.token) { + case INTVAL -> { + if (scanner.inBits) { + v = scanner.intValue; + break i2f; + } else { + f = (float) scanner.intValue; + } + } + case FLOATVAL -> f = scanner.floatValue; + case DOUBLEVAL -> f = (float) scanner.doubleValue; // to be excluded? + case INF -> f = Float.POSITIVE_INFINITY; + case NAN -> f = Float.NaN; + default -> { + environment.traceln(() -> "token=" + scanner.token); + environment.error(scanner.pos, "err.token.expected", ""); + throw new SyntaxError(); + } + } + v = Float.floatToIntBits(f); + } + if (scanner.sign == -1) { + v = v ^ 0x80000000; + } + valueFloat = new ConstValue_Float(v); + scanner.scan(); + } catch (SyntaxError se) { + syntaxError = se; + } + return valueFloat; + } + + @Override + public ConstValue visitDouble() { + traceMethodInfoLn(); + ConstValue_Double valueDouble = null; + try { + long v; + double d; + if (scanner.token == Token.BITS) { + scanner.scan(); + scanner.inBits = true; + } + d2l: + { + switch (scanner.token) { + case INTVAL -> { + if (scanner.inBits) { + v = scanner.intValue; + break d2l; + } else { + d = scanner.intValue; + } + } + case LONGVAL -> { + if (scanner.inBits) { + v = scanner.longValue; + break d2l; + } else { + d = (double) scanner.longValue; + } + } + case FLOATVAL -> d = scanner.floatValue; + case DOUBLEVAL -> d = scanner.doubleValue; + case INF -> d = Double.POSITIVE_INFINITY; + case NAN -> d = Double.NaN; + default -> { + environment.error(scanner.pos, "err.token.expected", "Double"); + throw new SyntaxError(); + } + } + v = Double.doubleToLongBits(d); + } + if (scanner.sign == -1) { + v = v ^ 0x8000000000000000L; + } + valueDouble = new ConstValue_Double(v); + scanner.scan(); + } catch (SyntaxError se) { + syntaxError = se; + } + return valueDouble; + } + + public ConstCell visitName() { + traceMethodInfoLn(); + ConstCell obj = null; + try { + // Parse an external name: CPINDEX, string, or identifier. + obj = parser.parseName(); + } catch (SyntaxError se) { + syntaxError = se; + } + return obj; + } + + @Override + public ConstValue visitMethodType() { + traceMethodInfoLn(); + ConstValue_MethodType obj = null; + ConstCell cell = (ConstCell) visitName(); + if (syntaxError == null) { + obj = new ConstValue_MethodType(cell); + } + return obj; + } + + @Override + public ConstValue visitString() { + traceMethodInfoLn(); + ConstValue_String obj = null; + ConstCell cell = visitName(); + if (syntaxError == null) { + obj = new ConstValue_String(cell); + } + return obj; + } + + @Override + public ConstValue visitClass() { + traceMethodInfoLn(); + ConstValue_Class obj = null; + try { + ConstCell cell = parser.parseConstantClassInfo(true); + obj = new ConstValue_Class(cell); + } catch (SyntaxError se) { + syntaxError = se; + } + return obj; + } + + @Override + public ConstValue visitPackage() { + traceMethodInfoLn(); + ConstValue_Package obj = null; + try { + ConstCell cell = parser.parseConstantPackageInfo(); + obj = new ConstValue_Package(cell); + } catch (SyntaxError se) { + syntaxError = se; + } + return obj; + } + + @Override + public ConstValue visitModule() { + traceMethodInfoLn(); + ConstValue_Module obj = null; + try { + ConstCell cell = parser.parseConstantModuleInfo(); + obj = new ConstValue_Module(cell); + } catch (SyntaxError se) { + syntaxError = se; + } + return obj; + } + + + @Override + public ConstValue visitMethodHandle() { + traceMethodInfoLn(); + ConstValue_MethodHandle obj = null; + try { + ConstCell refCell; + SubTag subTag; + // MethodHandle [INVOKESUBTAG|INVOKESUBTAG_INDEX] : CONSTANT_FIELD | [FIELDREF|METHODREF|INTERFACEMETHODREF] + if (scanner.token == Token.INTVAL) { + // INVOKESUBTAG_INDEX + // Handle an explicit constant pool form + subTag = subTag(scanner.intValue); + scanner.scan(); + scanner.expect(Token.COLON); + if (scanner.token == Token.CPINDEX) { + // CONSTANT_FIELD + int cpx = scanner.intValue; + refCell = parser.pool.getCell(cpx); + scanner.scan(); + } else { + // [FIELDREF|METHODREF|INTERFACEMETHODREF] + refCell = parser.parseMethodHandle(subTag); + } + } else { + // INVOKESUBTAG : REF_INVOKEINTERFACE, REF_NEWINVOKESPECIAL, ... + // normal JASM + subTag = parser.parseSubtag(); + scanner.expect(Token.COLON); + if (scanner.token == Token.CPINDEX) { + // CODETOOLS-7901522: Jasm doesn't allow creating REF_invoke* referring an InterfaceMethod + // Parsing the case when refCell is CP index (#1) + // const #1 = InterfaceMethod m:"()V"; + // const #2 = MethodHandle REF_invokeSpecial:#1; + int cpx = scanner.intValue; + refCell = parser.pool.getCell(cpx); + scanner.scan(); + } else { + refCell = parser.parseMethodHandle(subTag); + } + } + obj = new ConstValue_MethodHandle(subTag, refCell); + } catch (SyntaxError se) { + syntaxError = se; + } + return obj; + } + + public > T visitMember(ConstType tag) { + traceMethodInfoLn(); + T constValue = null; + try { + Token prevToken = scanner.token; + ConstCell firstName; + ConstCell ClassCell; + ConstCell NameCell, NapeCell; + firstName = parser.parseConstantClassInfo(false); + if (scanner.token == Token.FIELD) { // DOT + scanner.scan(); + if (prevToken == Token.CPINDEX) { + ClassCell = firstName; + } else { + ClassCell = parser.pool.findCell(ConstType.CONSTANT_CLASS, firstName); + } + NameCell = parser.parseName(); + } else { + // no class provided - assume current class + if (parser.classData.coreClasses.this_class().isSet() || + parser.classData.coreClasses.this_class().ref == null) { + ClassCell = (ConstCell) parser.classData.coreClasses.this_class(); + } else { + ClassCell = parser.pool.findCell((ConstValue_Class) parser.classData.coreClasses.this_class().ref); + } + NameCell = firstName; + } + if (scanner.token == Token.COLON) { + // name and type separately + scanner.scan(); + NapeCell = parser.pool.findCell(ConstType.CONSTANT_NAMEANDTYPE, NameCell, parser.parseName()); + } else { + // name and type as single name + NapeCell = NameCell; + } + switch (tag) { + case CONSTANT_INTERFACEMETHODREF -> + constValue = (T) new ConstValue_InterfaceMethodRef(ClassCell, NapeCell); + case CONSTANT_METHODREF -> constValue = (T) new ConstValue_MethodRef(ClassCell, NapeCell); + case CONSTANT_FIELDREF -> constValue = (T) new ConstValue_FieldRef(ClassCell, NapeCell); + } + if (constValue == null) { + environment.error("err.invalid.type", tag.printVal()); + throw new SyntaxError().setFatal(); + } + } catch (SyntaxError se) { + syntaxError = se; + } + + return constValue; + } + + @Override + public ConstValue visitField() { + traceMethodInfoLn(); + return visitMember(ConstType.CONSTANT_FIELDREF); + } + + @Override + public ConstValue visitMethod() { + traceMethodInfoLn(); + return visitMember(ConstType.CONSTANT_METHODREF); + } + + @Override + public ConstValue visitInterfaceMethod() { + traceMethodInfoLn(); + return visitMember(ConstType.CONSTANT_INTERFACEMETHODREF); + } + + @Override + public ConstValue visitNameAndType() { + traceMethodInfoLn(); + ConstValue_NameAndType obj = null; + try { + ConstCell NameCell = parser.parseName(), TypeCell; + scanner.expect(Token.COLON); + TypeCell = parser.parseName(); + obj = new ConstValue_NameAndType((ConstCell) NameCell, (ConstCell) TypeCell); + } catch (SyntaxError se) { + syntaxError = se; + } + return obj; + } + + @Override + public ConstValue_InvokeDynamic visitInvokeDynamic() { + traceMethodInfoLn(); + final BiFunction, ConstValue_InvokeDynamic> ctor = + ConstValue_InvokeDynamic::new; + return visitBsm(ctor); + } + + @Override + public ConstValue_Dynamic visitDynamic() { + traceMethodInfoLn(); + final BiFunction, ConstValue_Dynamic> ctor = + ConstValue_Dynamic::new; + return visitBsm(ctor); + } + + private E visitBsm(BiFunction, E> ctor) { + E obj = null; + try { + if (scanner.token == Token.INTVAL) { + // Handle an explicit constant pool form + int bsmIndex = scanner.intValue; + scanner.scan(); + + scanner.expect(Token.COLON); + + if (scanner.token != Token.CPINDEX) { + environment.traceln(() -> "token=" + scanner.token); + environment.error(scanner.pos, "err.token.expected", ""); + throw new SyntaxError(); + } + int cpx = scanner.intValue; + scanner.scan(); + // Put a placeholder in place of BSM. + // resolve placeholder after the attributes are scanned. + BootstrapMethodData bsmData = new BootstrapMethodData(bsmIndex); + obj = ctor.apply(bsmData, parser.pool.getCell(cpx)); + } else { + // Handle full form + ConstCell MHCell = parser.pool.findCell(parseConstValue(ConstType.CONSTANT_METHODHANDLE)); + scanner.expect(Token.COLON); + ConstCell NapeCell = parser.pool.findCell(parseConstValue(ConstType.CONSTANT_NAMEANDTYPE)); + if (scanner.token == Token.LBRACE) { + incLBRACE(); + scanner.scan(); + } + ArrayList> bsm_args = new ArrayList<>(256); + while (true) { + if (ParseConstPool.this.lbrace > 0) { + if (scanner.token == Token.RBRACE) { + decLBRACE(); + scanner.scan(); + break; + } else if (scanner.token == Token.SEMICOLON) { + scanner.expect(Token.RBRACE); + } + } else if (scanner.token == Token.SEMICOLON) { + break; + } + if (scanner.token == Token.COMMA) { + scanner.scan(); + } + ConstCell cell = parseBSMArgumentConstRef(); + bsm_args.add(cell); + } + if (ParseConstPool.this.lbrace == 0) { + scanner.check(Token.SEMICOLON); + } + BootstrapMethodData bsmData = new BootstrapMethodData(MHCell, bsm_args); + parser.classData.addBootstrapMethod(bsmData); + obj = ctor.apply(bsmData, NapeCell); + } + } catch (SyntaxError se) { + syntaxError = se; + } + return obj; + } + } // End Visitor + + public ParseConstPool decLBRACE() { + ParseConstPool.this.lbrace--; + return this; + } + + + public ParseConstPool incLBRACE() { + ParseConstPool.this.lbrace++; + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseInstruction.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseInstruction.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseInstruction.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/ParseInstruction.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,487 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.SyntaxError; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.List; + +import static org.openjdk.asmtools.common.structure.StackMap.EntryType.EARLY_LARVAL; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType; +import static org.openjdk.asmtools.jasm.JasmTokens.Token; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.ENTRYTYPE; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.FRAMETYPE; +import static org.openjdk.asmtools.jasm.OpcodeTables.*; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode.*; + +/** + * Instruction Parser + *

+ * ParserInstr is a parser class owned by Parser.java. It is primarily responsible for + * parsing instruction byte codes. + */ +public class ParseInstruction extends ParseBase { + + /** + * local handle for the constant parser - needed for parsing constants during + * instruction construction. + */ + private final ParseConstPool instructionParser; + + /** + * Constructor + * + * @param parser parent, main parser + * @param cpParser constant pool parser + */ + protected ParseInstruction(Parser parser, ParseConstPool cpParser) throws IOException { + super.init(parser); + this.instructionParser = cpParser; + } + + private boolean isInstruction(Token token) { + return (token == Token.IDENT || token.in(Token.LOCALSMAP, Token.STACKMAP, Token.UNSETFIELDS)); + } + + /** + * Parse an instruction. + */ + protected void parseInstr() throws SyntaxError, IOException { + // ignore possible line numbers after java disassembler + if (scanner.token == Token.INTVAL) { + scanner.scan(); + } + // ignore possible numeric labels after java disassembler + if (scanner.token == Token.INTVAL) { + scanner.scan(); + } + if (scanner.token == Token.COLON) { + scanner.scan(); + } + + String mnemocode; + long mnenoc_pos; + for (; ; ) { // read labels + if (!isInstruction(scanner.token)) { + return; + } + + mnemocode = scanner.idValue; + mnenoc_pos = scanner.pos; + scanner.scan(); + if (scanner.token != Token.COLON) { + break; + } + // actually it was a label + scanner.scan(); + parser.curCodeAttr.LabelDef(mnenoc_pos, mnemocode); + } + + Opcode opcode = OpcodeTables.opcode(mnemocode); + if (opcode == null) { + environment.error(mnenoc_pos, "err.wrong.mnemocode", mnemocode); + throw new SyntaxError(); + } + OpcodeType opcodeType = opcode.type(); + + Indexer arg = null; + Object arg2 = null; + StackMapData stackMapData; + scanner.debugScan(mnenoc_pos, "parseInstr: MnemoCode \'%s\'".formatted(opcode.parseKey())); + switch (opcodeType) { + case NORMAL: + switch (opcode) { + + // pseudo-instructions: + case opc_bytecode: + for (; ; ) { + if (scanner.token == Token.IDENT) { + Opcode oc = OpcodeTables.opcode(scanner.stringValue); + if (oc == null) { + environment.error(scanner.pos, "err.unknown.bytecode", scanner.stringValue); + throw new SyntaxError(); + } + parser.curCodeAttr.addInstr(mnenoc_pos, opc_bytecode, new Indexer(oc.value()), null); + scanner.scan(); + } else { + parser.curCodeAttr.addInstr(mnenoc_pos, Opcode.opc_bytecode, parser.parseUInt(1), null); + } + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_try: + for (; ; ) { + parser.curCodeAttr.beginTrap(scanner.pos, parser.parseIdent()); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_endtry: + for (; ; ) { + parser.curCodeAttr.endTrap(scanner.pos, parser.parseIdent()); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_catch: + parser.curCodeAttr.trapHandler(scanner.pos, parser.parseIdent(), + instructionParser.parseConstRef(ConstType.CONSTANT_CLASS)); + return; + case opc_var: + for (; ; ) { + parser.parseLocVarDef(opc_var); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_endvar: + for (; ; ) { + parser.parseLocVarEnd(opc_var); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_type: + for (; ; ) { + parser.parseLocVarDef(opc_type); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_endtype: + for (; ; ) { + parser.parseLocVarEnd(opc_type); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + + case opc_locals_map: + stackMapData = parser.curCodeAttr.getStackMapTable(); + if (stackMapData.localsMap != null) { + environment.error(scanner.pos, "err.stackmap.entity.repeated", opc_locals_map.parseKey()); + } + DataVector localsMap = new DataVector(); + stackMapData.localsMap = localsMap; + stackMapData.setScannerPosition(scanner.pos); + if (scanner.token == Token.SEMICOLON) { + return; // empty locals_map allowed + } + for (; ; ) { + parser.parseMapItem(localsMap); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_stack_map: + stackMapData = parser.curCodeAttr.getStackMapTable(); + if (stackMapData.stackMap != null) { + environment.error(scanner.pos, "err.stackmap.entity.repeated", opc_stack_map.parseKey()); + } + DataVector stackMap = new DataVector(); + stackMapData.stackMap = stackMap; + stackMapData.setScannerPosition(scanner.pos); + if (scanner.token == Token.SEMICOLON) { + return; // empty stack_map allowed + } + for (; ; ) { + parser.parseMapItem(stackMap); + if (scanner.token != Token.COMMA) { + return; + } + scanner.scan(); + } + case opc_unset_fields: + stackMapData = parser.curCodeAttr.getStackMapTable(); + if (!stackMapData.isWrapper()) { + environment.error(scanner.pos, "err.stackmap.map.eligible", + opc_unset_fields.parseKey(), + EARLY_LARVAL.tagName()); + } + if (stackMapData.unsetFields != null) { + environment.error(scanner.pos, "err.stackmap.entity.repeated", opc_unset_fields.parseKey()); + } + DataVector unsetFields = new DataVector(); + stackMapData.unsetFields = unsetFields; + stackMapData.setScannerPosition(scanner.pos); + if (scanner.token == Token.SEMICOLON) { + // empty unset_fields allowed + scanner.scan(); + scanner.expectOneOf(List.of(opc_stack_map_entry.parseKey(), opc_stack_frame_type.parseKey()), + FRAMETYPE, ENTRYTYPE); + } else { + for (; ; ) { + parser.parseNameAndType(unsetFields); + if (scanner.token != Token.COMMA) { + scanner.expect(Token.SEMICOLON); + scanner.expectOneOf(List.of(opc_stack_map_entry.parseKey(), opc_stack_frame_type.parseKey()), + FRAMETYPE, ENTRYTYPE); + break; + } + scanner.scan(); + } + } + opcode = opc_frame_type; + scanner.scan(); + // continue to the next case: opc_stack_frame_type, opc_stack_map_entry, opc_frame_type, opc_entry_type + // StackMapTable Attribute (Since 7.0) + case opc_stack_frame_type, opc_stack_map_entry, + opc_frame_type, opc_entry_type: + stackMapData = parser.curCodeAttr.getStackMapTable(); + if (stackMapData.isFrameTypeSet()) { + if (stackMapData.isWrapper()) { + stackMapData = parser.curCodeAttr.getNextStackMapTable(); + } else { + environment.error(scanner.pos, "err.stackmaptable.repeated"); + } + } + stackMapData.setScannerPosition(scanner.pos).setStackFrameTypeByName(parser.parseIdent()); + return; + // StackMap Attribute (Java 6.0) + case opc_stack_map_frame: // stack_map_frame + stackMapData = parser.curCodeAttr.getStackMapTable(); + if (stackMapData.isFrameTypeSet()) { + environment.error(scanner.pos, "err.stackmaptable.repeated"); + } + stackMapData.setScannerPosition(scanner.pos); + return; + // normal instructions: + case opc_aload: + case opc_astore: + case opc_fload: + case opc_fstore: + case opc_iload: + case opc_istore: + case opc_lload: + case opc_lstore: + case opc_dload: + case opc_dstore: + case opc_ret: + case opc_aload_w: + case opc_astore_w: + case opc_fload_w: + case opc_fstore_w: + case opc_iload_w: + case opc_istore_w: + case opc_lload_w: + case opc_lstore_w: + case opc_dload_w: + case opc_dstore_w: + case opc_ret_w: + // loc var + arg = parser.parseLocVarRef(); + break; + case opc_iinc: // loc var, const + arg = parser.parseLocVarRef(); + scanner.expect(Token.COMMA); + arg2 = parser.parseInt(opcode.parseKey(), 1); + break; + case opc_tableswitch: + case opc_lookupswitch: + arg2 = parseSwitchTable(); + break; + case opc_newarray: { + int type; + if (scanner.token == Token.INTVAL) { + type = scanner.intValue; + } else if ((type = ClassFileConst.basicTypeValue(scanner.idValue)) == -1) { + environment.error(scanner.pos, "err.array.type.expected"); + throw new SyntaxError(); + } + scanner.scan(); + arg = new Indexer(type); + break; + } + case opc_new: + case opc_anewarray: + case opc_instanceof: + case opc_checkcast: + arg = instructionParser.parseConstRef(ConstType.CONSTANT_CLASS); + break; + case opc_bipush: + arg = parser.parseInt(opcode.parseKey(), 1); + break; + case opc_sipush: + arg = parser.parseInt(opcode.parseKey(), 2); + break; + case opc_ldc: + case opc_ldc_w: + case opc_ldc2_w: + arg = instructionParser.parseConstRef(null); + break; + case opc_putstatic: + case opc_getstatic: + case opc_putfield: + case opc_getfield: + arg = instructionParser.parseConstRef(ConstType.CONSTANT_FIELDREF); + break; + case opc_invokevirtual: + arg = instructionParser.parseConstRef(ConstType.CONSTANT_METHODREF); + break; + case opc_invokestatic: + case opc_invokespecial: + ConstType ctype01 = ConstType.CONSTANT_METHODREF; + ConstType ctype02 = ConstType.CONSTANT_INTERFACEMETHODREF; + if (Modifier.isInterface(this.parser.classData.access)) { + ctype01 = ConstType.CONSTANT_INTERFACEMETHODREF; + ctype02 = ConstType.CONSTANT_METHODREF; + } + arg = instructionParser.parseConstRef(ctype01, ctype02); + break; + case opc_jsr: + case opc_goto: + case opc_ifeq: + case opc_ifge: + case opc_ifgt: + case opc_ifle: + case opc_iflt: + case opc_ifne: + case opc_if_icmpeq: + case opc_if_icmpne: + case opc_if_icmpge: + case opc_if_icmpgt: + case opc_if_icmple: + case opc_if_icmplt: + case opc_if_acmpeq: + case opc_if_acmpne: + case opc_ifnull: + case opc_ifnonnull: + case opc_jsr_w: + case opc_goto_w: + arg = parseLabelRef(); + break; + case opc_invokeinterface: + arg = instructionParser.parseConstRef(ConstType.CONSTANT_INTERFACEMETHODREF); + scanner.expect(Token.COMMA); + arg2 = parser.parseUInt(1); + break; + case opc_invokedynamic: + arg = instructionParser.parseConstRef(ConstType.CONSTANT_INVOKEDYNAMIC); + break; + + case opc_multianewarray: + arg = instructionParser.parseConstRef(ConstType.CONSTANT_CLASS); + scanner.expect(Token.COMMA); + arg2 = parser.parseUInt(1); + break; + case opc_wide: + case opc_nonpriv: + case opc_priv: + int opc2 = (opcode.value() << 8) | parser.parseUInt(1).cpIndex; + opcode = opcode(opc2); + break; + } + break; + case WIDE: + arg = parser.parseLocVarRef(); + if (opcode == Opcode.opc_iinc_w) { // loc var, const + scanner.expect(Token.COMMA); + arg2 = parser.parseInt(opcode.parseKey(), 2); + } + break; + case NONPRIVELEGED: + case PRIVELEGED: + break; + default: + environment.error(scanner.prevPos, "err.wrong.mnemocode", mnemocode); + throw new SyntaxError(); + } + parser.curCodeAttr.addInstr(mnenoc_pos, opcode, arg, arg2); + } //end parseInstr + + /** + * Parse a Switch Table. return value: SwitchTable. + */ + protected SwitchTable parseSwitchTable() throws SyntaxError, IOException { + scanner.expect(Token.LBRACE); + Indexer label; + int numpairs = 0, key; + SwitchTable table = new SwitchTable(environment); + tableScan: + { + while (numpairs < MAX_LOOKUPSWITCH_PAIRS_COUNT) { + switch (scanner.token) { + case INTVAL: + key = scanner.intValue * scanner.sign; + scanner.scan(); + scanner.expect(Token.COLON); + table.addEntry(key, parseLabelRef()); + numpairs++; + if (scanner.token != Token.SEMICOLON) { + break tableScan; + } + scanner.scan(); + break; + case DEFAULT: + scanner.scan(); + scanner.expect(Token.COLON); + if (table.defLabel != null) { + environment.error("err.default.redecl"); + } + table.defLabel = parseLabelRef(); + if (scanner.token != Token.SEMICOLON) { + break tableScan; + } + scanner.scan(); + break; + default: + break tableScan; + } + } + environment.error("err.long.switchtable", MAX_LOOKUPSWITCH_PAIRS_COUNT); + } // end tableScan + scanner.expect(Token.RBRACE); + return table; + } // end parseSwitchTable + + /** + * Parse a label instruction argument + */ + protected Indexer parseLabelRef() throws SyntaxError, IOException { + switch (scanner.token) { + case INTVAL: { + int v = scanner.intValue * scanner.sign; + scanner.scan(); + return new Indexer(v); + } + case IDENT: { + String label = scanner.stringValue; + scanner.scan(); + return parser.curCodeAttr.LabelRef(label); + } + } + environment.error("err.label.expected"); + throw new SyntaxError(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Parser.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Parser.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Parser.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Parser.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,2870 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.asmutils.StringUtils; +import org.openjdk.asmtools.common.SyntaxError; +import org.openjdk.asmtools.common.outputs.NamedToolOutput; +import org.openjdk.asmtools.common.structure.*; +import org.openjdk.asmtools.jasm.ConstantPool.ConstValue_Cell; +import org.openjdk.asmtools.jasm.JasmTokens.Token; +import org.openjdk.asmtools.jdis.ModuleContent; +import org.openjdk.asmtools.jdis.notations.Signature; + +import java.io.IOException; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import static org.openjdk.asmtools.common.structure.CFVersion.copyOf; +import static org.openjdk.asmtools.common.structure.EAttribute.*; +import static org.openjdk.asmtools.common.structure.EModifier.*; +import static org.openjdk.asmtools.jasm.ClassData.CoreClasses.PLACE.CLASSFILE; +import static org.openjdk.asmtools.jasm.ClassFileConst.*; +import static org.openjdk.asmtools.jasm.ConstantPool.ConstValue_UTF8; +import static org.openjdk.asmtools.jasm.Indexer.NotSet; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode.opc_type; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode.opc_var; +import static org.openjdk.asmtools.jdis.ConstantPool.TAG.*; + +/** + * This class is used to parse Jasm statements and expressions. + * The result is a parse tree.

+ *

+ * This class implements an operator precedence parser. Errors are + * reported to the Environment object, if the error can't be + * resolved immediately, a SyntaxError exception is thrown.

+ *

+ * Error recovery is implemented by catching Scanner.SyntaxError exceptions + * and discarding input scanner.tokens until an input token is reached that + * is possibly a legal continuation.

+ *

+ * The parse tree that is constructed represents the input + * exactly (no rewrites to simpler forms). This is important + * if the resulting tree is to be used for code formatting in + * a programming environment. Currently, only documentation comments + * are retained.

+ *

+ * A parser owns several components (scanner, constant-parser, + * instruction-parser, annotations-parser) to which it delegates certain + * parsing responsibilities. This parser contains functions to parse the + * overall form of a class, and any members (fields, methods, inner-classes). + *

+ * Syntax errors should always be caught inside the + * parser for error recovery. + */ +class Parser extends ParseBase { + + private final ArrayList clsDataList = new ArrayList<>(); + /** + * other parser components + */ + private final ParseAnnotation annotParser; // For parsing Annotations + private final ParseConstPool cpParser; // for parsing Constants + private final ParseInstruction instrParser; // for parsing Instructions + private final ParseAttribute attributeParser; // for parsing Instructions + /* Parser Fields */ + protected ConstantPool pool = null; + ClassData classData = null; + CFVersion currentCFV; // parser cfv + CodeAttr curCodeAttr; + private String pkg = null; + private String pkgPrefix = ""; + private ArrayList packageAnnotations = null; + private ArrayList classAnnotations = null; + private ArrayList memberAnnotations = null; + private boolean explicitCP = false; + private ModuleAttr moduleAttribute; + + /** + * Create a parser + */ + protected Parser(JasmEnvironment environment, CFVersion cfVersion) throws IOException { + super.init(environment, this); + this.cpParser = new ParseConstPool(this); + this.annotParser = new ParseAnnotation(this); + this.instrParser = new ParseInstruction(this, cpParser); + this.attributeParser = new ParseAttribute(this); + this.currentCFV = copyOf(cfVersion); + } + + void setDebugFlags(boolean debugScanner, boolean debugMembers, + boolean debugCP, boolean debugAnnot, + boolean debugInstr, boolean debugAttribute) { + setDebugFlag(debugMembers); + scanner.setDebugFlag(debugScanner); + cpParser.setDebugFlag(debugCP); + annotParser.setDebugFlag(debugAnnot); + instrParser.setDebugFlag(debugInstr); + attributeParser.setDebugFlag(debugAttribute); + } + + public long getPosition() { + return environment.getPosition(); + } + + private Pair parseVersion() { + int majorVersion, minorVersion; + if (scanner.token == Token.VERSION) { + scanner.scan(); + if (scanner.token == Token.INTVAL) { + majorVersion = scanner.intValue; + scanner.scan(); + if (scanner.token == Token.COLON) { + scanner.scan(); + if (scanner.token == Token.INTVAL) { + minorVersion = scanner.intValue; + classData.cfv.setFileVersion(majorVersion, minorVersion); + scanner.scan(); + traceMethodInfoLn("parseVersion: " + classData.cfv.asString()); + return new Pair<>(majorVersion, minorVersion); + } + } + } + } + environment.error(scanner.pos, "err.version.expected"); + throw new SyntaxError(); + } + + // Parse an internal name: identifier. + String parseIdent() throws SyntaxError { + String v = scanner.idValue; + scanner.expect(Token.IDENT); + return v; + } + + /** + * Parse a local variable (type) presented in the form + * (var) index #name_index:#descriptor_index; [ (var) index name:descriptor; ] + * or + * (type) index #name_index:#signature_index; [ (type) index name:signature; ] + *

+ * index - a valid index into the local variable array of the current frame. + * name - valid unqualified name denoting a local variable + * descriptor - a field descriptor which encodes the type or the signature of a local variable in the source program + */ + void parseLocVarDef(OpcodeTables.Opcode opcode) throws SyntaxError { + int slot = NotSet; + ConstCell nameCell, descriptorCell; + // The form is (var) slot #name_index:#descriptor_index; [ (var) slot name:descriptor; ] + // or (type) slot #name_index:#signature_index; [ (type) slot name:signature; ] + long indexPosition = scanner.pos; + if (scanner.token != Token.INTVAL) { + environment.throwErrorException(indexPosition, "err.locvar.expected"); + } + slot = scanner.intValue; + if (!curCodeAttr.max_locals.inRange(slot)) { + environment.throwErrorException(indexPosition, "err.locvar.wrong.index", slot, curCodeAttr.max_locals.cpIndex - 1); + } + scanner.scan(); + // scan pair #name_index:#descriptor_index or name:descriptor + // 1. scan (#)name(_index) + nameCell = parseName(); + scanner.expect(Token.COLON); + // scan pair #name_index:#descriptor_index or name:descriptor + // 1. scan (#)descriptor(_index) + long descriptorPosition = scanner.pos; + descriptorCell = parseName(); + // check either field descriptor or signature of the local var according to the opcode + if (opcode == opc_var) { + FieldType fieldType = FieldType.getFieldType(((String) descriptorCell.ref.value).charAt(0)); + if (fieldType == null) { + environment.throwErrorException(descriptorPosition, + "err.locvar.unknown.field.descriptor", slot, descriptorCell.ref.value.toString()); + } + } else if (opcode == opc_type) { + try { + // check validity of the parsed signature + new Signature<>(environment.getLogger(), descriptorCell.ref.value.toString()).getFieldType(null); + } catch (Exception ex) { + environment.warning(descriptorPosition, + "warn.loctype.wrong.field.signature", slot, descriptorCell.ref.value.toString()); + } + } else { + environment.throwErrorException(descriptorPosition, + "err.one.of.two.token.expected", opc_var.parseKey(), opc_type.parseKey()); + } + curCodeAttr.LocVarDataDef(opcode, indexPosition, slot, nameCell, descriptorCell); + } + + /** + * Parse The index (LOCAL_VARIABLE) into the local variable array of the instructions: + * [wide]aload, astore, fload, fstore, iload, istore, lload, lstore, dload, dstore LOCAL_VARIABLE; + * [wide]iinc LOCAL_VARIABLE, NUMBER; + */ + Indexer parseLocVarRef() throws SyntaxError { + if (scanner.token == Token.INTVAL) { + int index = scanner.intValue; + scanner.scan(); + return new Indexer(index); + } else { + //IMPROVEMENT: add parsing form where LOCAL_VARIABLE is a name of the LocalVariable + // like aload count[| #12]; where count was defined above: var 2 count:I; + environment.error(scanner.pos, "err.locvar.expected"); + throw new SyntaxError(); + } + } + + /** + * Parse The index (LOCAL_VARIABLE) into the local variable array of the instructions: + * either endvar LOCAL_VARIABLE; or endtype LOCAL_VARIABLE; + */ + void parseLocVarEnd(OpcodeTables.Opcode opcode) throws SyntaxError { + final long position = scanner.pos; + if (scanner.token == Token.INTVAL) { + int index = scanner.intValue; + curCodeAttr.LocVarDataEnd(opcode, (short) index, position); + scanner.scan(); + } else { + //IMPROVEMENT: add parsing form where LOCAL_VARIABLE is a name of the LocalVariable + // like varend count[| #12]; where count was defined above: var 2 count:I; + environment.error(scanner.pos, "err.locvar.expected"); + throw new SyntaxError(); + } + } + + /** + * Parse a set of CONSTANT_NameAndType_info entries in the following forms: + * #id1, #id2, #idN; + * or + * fldS:"Ljava/lang/String;", fldS:"I", fldI:"I"; + * + * @param fields is the list of fields that is populated with a newly scanned item + * @throws SyntaxError if any format error + * @throws IOException if any input error + */ + void parseNameAndType(DataVector fields) throws SyntaxError { + if (scanner.token == CPINDEX) { + fields.add(new ConstantPoolIndexData(scanner.intValue)); + scanner.scan(); + } else { + ConstCell nameCell = parseName(); + scanner.expect(COLON); + ConstCell typeCell = parseName(); + // Define the variable + ConstantPool.ConstValue_NameAndType nameAndType = new ConstantPool.ConstValue_NameAndType(nameCell, typeCell); + ConstCell cell = pool.findNameAndTypeCell(nameAndType); + fields.add(new ConstantPoolIndexData(cell, pool)); + } + } + + void parseMapItem(DataVector map) throws SyntaxError, IOException { + StackMap.VerificationType itemVerificationType = StackMap.getVerificationType(scanner.intValue, Optional.empty()); + ConstType tag = null; + Indexer arg = null; + Token token = scanner.token; + int iValue = scanner.intValue; + String sValue = scanner.stringValue; + scanner.scan(); + resolve: + { + switch (token) { + case INTVAL: + break resolve; + case CLASS: + itemVerificationType = StackMap.VerificationType.ITEM_Object; + tag = ConstType.CONSTANT_CLASS; + break resolve; + case CPINDEX: + itemVerificationType = StackMap.VerificationType.ITEM_Object; + arg = pool.getCell(iValue); + break resolve; + case IDENT: + itemVerificationType = StackMap.getVerificationType(sValue); + tag = ClassFileConst.getByParseKey(sValue); + if (itemVerificationType != null) { // itemType OK + if ((tag != null) // ambiguity: "int," or "int 77,"? + && (scanner.token != SEMICOLON) + && (scanner.token != COMMA)) { + itemVerificationType = StackMap.VerificationType.ITEM_Object; + } + break resolve; + } else if (tag != null) { // tag OK + itemVerificationType = StackMap.VerificationType.ITEM_Object; + break resolve; + } + } + // resolution failed: + itemVerificationType = StackMap.VerificationType.ITEM_Bogus; + environment.error("err.itemtype.expected", "<" + token.printValue() + ">"); + } + switch (itemVerificationType) { + case ITEM_Object -> { // followed by CP index + if (arg == null) { + arg = pool.findCell(cpParser.parseConstValue(tag)); + } + map.addElement(new StackMapData.StackMapItemTaggedPointer(itemVerificationType, arg)); + } + case ITEM_NewObject -> { // followed by label + arg = instrParser.parseLabelRef(); + map.addElement(new StackMapData.StackMapItemTaggedPointer(itemVerificationType, arg)); + } + default -> map.addElement(new StackMapData.StackMapItemTagged(itemVerificationType)); + } + } + + /** + * Parse an external name: CPINDEX, string, or identifier. + */ + ConstCell parseName() throws SyntaxError { + traceMethodInfoLn(); + String v; + if (scanner.token == CPINDEX) { + int cpx = scanner.intValue; + scanner.scan(); + return pool.getCell(cpx); + } else if (scanner.token == STRINGVAL) { + v = scanner.stringValue; + scanner.scan(); + return pool.findUTF8Cell(v); + } else if (scanner.token.isPossibleClassName()) { + // In many cases, Identifiers can correctly have the same + // names as keywords. Let's allow Class Names. + v = scanner.idValue; + scanner.scan(); + return pool.findUTF8Cell(v); + } + environment.error(scanner.pos, "err.name.expected", "\"" + scanner.token + "\""); + throw new SyntaxError(); + } + + /** + * Parses a field or method reference for a method handle. + */ + ConstCell parseMethodHandle(SubTag subtag) throws SyntaxError { + ConstCell refCell; + switch (subtag) { + // If the value of the reference_kind item is + // 1 (REF_getField), 2 (REF_getStatic), 3 (REF_putField) or 4 (REF_putStatic), + // then the constant_pool entry at that index must be a CONSTANT_Fieldref_info structure (4.4.2) + // representing a field for which a method handle is to be created. jvms-4.4.8-200-C-A + case REF_GETFIELD, REF_GETSTATIC, REF_PUTFIELD, REF_PUTSTATIC -> + refCell = pool.findCell(cpParser.parseConstValue(ConstType.CONSTANT_FIELDREF)); + + // If the value of the reference_kind item is + // 5 (REF_invokeVirtual) or 8 (REF_newInvokeSpecial), + // then the constant_pool entry at that index must be a CONSTANT_Methodref_info structure (4.4.2) + // representing a class's method or constructor (2.9.1) for which a method handle is to be created. + // jvms-4.4.8-200-C-B + case REF_INVOKEVIRTUAL, REF_NEWINVOKESPECIAL -> { + cpParser.setExitImmediately(true); + refCell = cpParser.parseConstRef(ConstType.CONSTANT_METHODREF, ConstType.CONSTANT_INTERFACEMETHODREF); + cpParser.setExitImmediately(false); + checkReferenceIndex(getPosition(), ConstType.CONSTANT_METHODREF, null); + } + case REF_INVOKESTATIC, REF_INVOKESPECIAL -> { + // CODETOOLS-7902333 + // 4.4.8. The CONSTANT_MethodHandle_info Structure + // reference_index + // The value of the reference_index item must be a valid index into the constant_pool table. + // The constant_pool entry at that index must be as follows: + // If the value of the reference_kind item is 6 (REF_invokeStatic) or 7 (REF_invokeSpecial), + // then if the class file version number is less than 52.0, the constant_pool entry at that index must be + // a CONSTANT_Methodref_info structure representing a class's method for which a method handle is to be created; + // if the class file version number is 52.0 or above, the constant_pool entry at that index must be + // either a CONSTANT_Methodref_info structure or a CONSTANT_InterfaceMethodref_info structure (4.4.2) + // representing a class's or interface's method for which a method handle is to be created. + ConstType ctype01 = ConstType.CONSTANT_METHODREF; + ConstType ctype02 = ConstType.CONSTANT_INTERFACEMETHODREF; + if (this.classData.cfv.major_version() >= 52 && EModifier.isInterface(this.classData.access)) { + ctype01 = ConstType.CONSTANT_INTERFACEMETHODREF; + ctype02 = ConstType.CONSTANT_METHODREF; + } + cpParser.setExitImmediately(true); + refCell = cpParser.parseConstRef(ctype01, ctype02); + cpParser.setExitImmediately(false); + checkReferenceIndex(getPosition(), ctype01, ctype02); + } + case REF_INVOKEINTERFACE -> { + cpParser.setExitImmediately(true); + refCell = cpParser.parseConstRef(ConstType.CONSTANT_INTERFACEMETHODREF, ConstType.CONSTANT_METHODREF); + cpParser.setExitImmediately(false); + checkReferenceIndex(getPosition(), ConstType.CONSTANT_INTERFACEMETHODREF, null); + } + default -> + // should not reach + throw new SyntaxError(); + } + return refCell; + } + + /** + * Check the pair reference_kind:reference_index where reference_kind is any from: + * REF_invokeVirtual, REF_newInvokeSpecial, REF_invokeStatic, REF_invokeSpecial, REF_invokeInterface + * and reference_index is one of [Empty], Method or InterfaceMethod + * There are possible entries: + * ldc Dynamic REF_newInvokeSpecial:InterfaceMethod LdcConDyTwice."": + * ldc Dynamic REF_invokeInterface:LdcConDyTwice."": + * ldc Dynamic REF_newInvokeSpecial:Method LdcConDyTwice."": + * ldc MethodHandle REF_newInvokeSpecial:InterfaceMethod LdcConDyTwice."": + * ldc MethodHandle REF_invokeInterface:LdcConDyTwice."": + * ldc MethodHandle REF_newInvokeSpecial:Method LdcConDyTwice."": + * invokedynamic MethodHandle REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + * invokedynamic MethodHandle REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants + * .... + * + * @param position the position in a source file + * @param defaultTag expected reference_index tag (Method or InterfaceMethod) + * @param defaultTag2 2nd expected reference_index tag (Method or InterfaceMethod) + */ + private void checkReferenceIndex(long position, ConstType defaultTag, ConstType defaultTag2) { + if (!scanner.token.in(COLON, SEMICOLON, COMMA)) { + if (defaultTag2 != null) { + environment.error(position, "err.wrong.tag2", defaultTag.parseKey(), defaultTag2.parseKey()); + } else { + environment.error(position, "err.wrong.tag", defaultTag.parseKey()); + } + throw new SyntaxError().setFatal(); + } + } + + /** + * Parses a sub-tag value in a method handle. + */ + SubTag parseSubtag() throws SyntaxError { + SubTag subtag = switch (scanner.token) { + case IDENT -> subTag(scanner.stringValue); + case INTVAL -> subTag(scanner.intValue); + default -> null; + }; + if (subtag == null) { + environment.error("err.subtag.expected"); + throw new SyntaxError(); + } + scanner.scan(); + return subtag; + } + + ConstCell parseConstantPackageInfo() throws SyntaxError { + if (scanner.token == CPINDEX) { + int cpx = scanner.intValue; + scanner.scan(); + return pool.getCell(cpx); + } else if (scanner.token == STRINGVAL || + // Some identifiers might coincide with token names. + // these should be OK to use as identifier names. + scanner.token.isPossibleClassName()) { + String packageName = scanner.stringValue; + scanner.scan(); + return pool.findPackageCell(packageName); + } else { + throwSyntaxError("err.package.name.expected"); + return null; + } + } + + ConstCell parseConstantModuleInfo() throws SyntaxError { + if (scanner.token == CPINDEX) { + int cpx = scanner.intValue; + scanner.scan(); + return pool.getCell(cpx); + } else if (scanner.token == STRINGVAL || + // Some identifiers might coincide with token names. + // these should be OK to use as identifier names. + scanner.token.isPossibleModuleName()) { + String moduleName = scanner.stringValue; + scanner.scan(); + return pool.findModuleCell(moduleName); + } else { + throwSyntaxError("err.module.name.expected"); + return null; + } + } + + ConstCell parseConstantClassInfo(boolean uncond) throws SyntaxError { + if (scanner.token == CPINDEX) { + int cpx = scanner.intValue; + scanner.scan(); + return pool.getCell(cpx); + } else if (scanner.token == STRINGVAL || + // Some identifiers might coincide with token names. + // These should be OK to use as identifier names. + scanner.token.isPossibleClassName()) { + String value = scanner.stringValue; + scanner.scan(); + value = prependPackage(value, uncond); + return pool.findUTF8Cell(value); + } else { + throwSyntaxError("err.class.name.expected"); + return null; + } + } + + private void throwSyntaxError(String msgId) throws SyntaxError { + ConstType key = ClassFileConst.getByTag(scanner.token.value()); + environment.traceln("Unrecognized token %s: %s", scanner.token.toString(), key == null ? "null" : key.parseKey()); + environment.error(scanner.prevPos, msgId, "\"" + scanner.token.parseKey() + "\""); + throw new SyntaxError(); + } + + private String prependPackage(String className, boolean uncond) { + if (uncond || (scanner.token == Token.FIELD)) { + if ((!className.contains("/")) // class identifier doesn't contain "/" + && (!className.contains("["))) { // class identifier doesn't contain "[" + className = pkgPrefix + className; // add package + } + } + return className; + } + + /** + * Parse a signed integer of size bytes long. + * size = 1 or 2 + */ + Indexer parseInt(String opCode, int size) throws SyntaxError { + if (scanner.token == Token.BITS) { + scanner.scan(); + } + if (scanner.token != Token.INTVAL) { + environment.error(scanner.pos, "err.int.expected"); + throw new SyntaxError(); + } + int arg = scanner.intValue * scanner.sign; + switch (size) { + case 1: +// if ((arg>127)||(arg<-128)) { // 0xFF not allowed + if ((arg > 255) || (arg < -128)) { // to allow 0xFF + environment.error(scanner.pos, "err.value.large", opCode, arg, "1 byte"); + throw new SyntaxError(); + } + break; + case 2: +// if ((arg > 32767) || (arg < -32768)) { //this seems +// natural but is not backward compatible. Some tests contain +// expressions like: sipush 0x8765; + if ((arg > 65535) || (arg < -32768)) { + environment.error(scanner.pos, "err.value.large", opCode, arg, "2 bytes"); + throw new SyntaxError(); + } + break; + default: + throw new InternalError("parseInt(" + size + ")"); + } + scanner.scan(); + return new Indexer(arg); + } + + /** + * Parse an unsigned integer of size bytes long. + * size = 1 or 2 + */ + Indexer parseUInt(int size) throws SyntaxError { + if (scanner.token != Token.INTVAL) { + environment.error(scanner.pos, "err.int.expected"); + throw new SyntaxError(); + } + if (scanner.sign == -1) { + environment.error(scanner.pos, "err.neg.forbidden"); + throw new SyntaxError(); + } + int arg = scanner.intValue; + switch (size) { + case 1: + if (arg > 255) { + environment.error(scanner.pos, "err.value.large", "ubyte", arg, "1 byte"); + throw new SyntaxError(); + } + break; + case 2: + if (arg > 65535) { + environment.error(scanner.pos, "err.value.large", "ushort", arg, "2 bytes"); + throw new SyntaxError(); + } + break; + default: + throw new InternalError("parseUInt(" + size + ")"); + } + scanner.scan(); + return new Indexer(arg); + } + + /** + * Parse constant declaration + */ + private void parseConstDef() { + for (; ; ) { + if (scanner.token == Token.CPINDEX) { + int cpx = scanner.intValue; + scanner.scan(); + scanner.expect(Token.ASSIGN); + traceMethodInfoLn("\ncpIndex: %d".formatted(cpx)); + pool.setCell(cpx, cpParser.parseConstPoolRef()); + } else { + environment.error("err.const.def.expected"); + throw new SyntaxError(); + } + if (scanner.token != COMMA) { + scanner.expect(SEMICOLON); + return; + } + scanner.scan(); // COMMA + } + } + + /** + * Parse the modifiers + */ + private int scanModifier(int mod) throws SyntaxError { + int nextmod; + long prevpos; + + while (true) { + nextmod = 0; + switch (scanner.token) { + case PUBLIC -> nextmod = ACC_PUBLIC.getFlag(); + case PRIVATE -> nextmod = ACC_PRIVATE.getFlag(); + case PROTECTED -> nextmod = ACC_PROTECTED.getFlag(); + case STATIC -> nextmod = ACC_STATIC.getFlag(); + case FINAL -> nextmod = ACC_FINAL.getFlag(); + case SYNCHRONIZED -> nextmod = ACC_SYNCHRONIZED.getFlag(); + case SUPER -> nextmod = ACC_SUPER.getFlag(); + case IDENTITY -> nextmod = ACC_IDENTITY.getFlag() | VALUE_OBJECTS_ATTRIBUTE.getFlag(); + case VALUE -> nextmod = ACC_VALUE.getFlag() | VALUE_OBJECTS_ATTRIBUTE.getFlag(); + case VOLATILE -> nextmod = ACC_VOLATILE.getFlag(); + case BRIDGE -> nextmod = ACC_BRIDGE.getFlag(); + case TRANSIENT -> nextmod = ACC_TRANSIENT.getFlag(); + case VARARGS -> nextmod = ACC_VARARGS.getFlag(); + case NATIVE -> nextmod = ACC_NATIVE.getFlag(); + case INTERFACE -> nextmod = ACC_INTERFACE.getFlag(); + case ABSTRACT -> nextmod = ACC_ABSTRACT.getFlag(); + case STRICT -> nextmod = ACC_STRICT.getFlag(); + case ENUM -> nextmod = ACC_ENUM.getFlag(); + case SYNTHETIC -> nextmod = this.classData.cfv.isSyntheticAttributeContext() + ? SYNTHETIC_ATTRIBUTE.getFlag() + : ACC_SYNTHETIC.getFlag(); + case ANNOTATION_ACCESS -> nextmod = ACC_ANNOTATION.getFlag(); + case DEPRECATED -> nextmod = DEPRECATED_ATTRIBUTE.getFlag(); + case MANDATED -> nextmod = ACC_MANDATED.getFlag(); + case INTVAL -> nextmod = scanner.intValue; + default -> { + return nextmod; + } + } + prevpos = scanner.pos; + scanner.scan(); + if ((mod & nextmod) == 0) { + return nextmod; + } + environment.warning(prevpos, "warn.repeated.modifier"); + } + } + + int scanModifiers() throws SyntaxError { + int mod = 0, nextmod; + while (true) { + nextmod = scanModifier(mod); + if (nextmod == 0) { + return mod; + } + mod = mod | nextmod; + } + } + + /** + * Parse a field. + */ + private void parseField(int mod) throws SyntaxError { + // Parses in the form: + // FIELD (, FIELD)*; + // where + // FIELD = NAME:DESCRIPTOR(:SIGNATURE)? CONST_VALUE? + // FIELD = NAME:DESCRIPTOR(:SIGNATURE_FULL)? + // FIELD = NAME:DESCRIPTOR CONST_VALUE(:SIGNATURE_FULL)? + // NAME = (CPINDEX | IDENT) + // DESCRIPTOR = (CPINDEX | STRING) + // SIGNATURE = (CPINDEX | STRING) + // SIGNATURE_FULL=Signature SIGNATURE + // CONST_VALUE = ASSIGN CONSTREF + traceMethodInfoLn("Begin"); + // check access modifiers: + Checker.checkFieldModifiers(classData, mod, scanner.prevPos); + while (true) { + ConstCell nameCell = parseName(); + scanner.expect(COLON); + ConstCell typeCell = parseName(); + + // Define the variable + FieldData fld = classData.addField(mod, nameCell, typeCell); + + if (memberAnnotations != null) { + fld.addAnnotations(memberAnnotations); + } + + // Parse the optional attribute: signature + if (scanner.token == COLON) { + scanner.scan(); + if (scanner.token == SIGNATURE) { + scanner.scan(); // skip + } + ConstCell signatureCell = parseName(); + fld.setSignatureAttr(signatureCell); + } + + // Parse the optional initializer + if (scanner.token == ASSIGN) { + scanner.scan(); + fld.SetInitialValue(cpParser.parseConstRef(null)); + } + + if (scanner.token == COLON) { + scanner.scan(); + fld.checkExistence(ATT_Signature, + () -> environment.warning(scanner.pos, "warn.repeat.signature.field")); + if (scanner.token == SIGNATURE) { + scanner.scan(); // skip + } + ConstCell signatureCell = parseName(); + fld.setSignatureAttr(signatureCell); + } + + // If the next scanner.token is a comma, then there is more + if (scanner.token != COMMA) { + scanner.expect(SEMICOLON); + return; + } + scanner.scan(); + } // end while + } // end parseField + + /** + * Scan method's signature to determine the size of parameters. + */ + private int countParams(ConstCell sigCell) throws SyntaxError { + String sig; + try { + ConstValue_UTF8 strConst = (ConstValue_UTF8) sigCell.ref; + sig = strConst.value; + } catch (NullPointerException | ClassCastException e) { + return 0; // ??? TBD + } + int siglen = sig.length(), k = 0, loccnt = 0; + String errMsg = "\"({JavaTypeSignature})Result\" is missing."; + boolean arraytype = false; + scan: + { + if (k >= siglen) { + break scan; + } + if (sig.charAt(k) != '(') { + errMsg = "A \"(\" token is expected in \"({JavaTypeSignature})Result\""; + break scan; + } + for (k = 1; k < siglen; k++) { + switch (sig.charAt(k)) { + case ')': + if (arraytype) { + errMsg = "An array type signature is expected: \"[JavaTypeSignature\""; + break scan; + } + return loccnt; + case '[': + arraytype = true; + break; + case 'B': + case 'C': + case 'F': + case 'I': + case 'S': + case 'Z': + loccnt++; + arraytype = false; + break; + case 'D': + case 'J': + loccnt++; + if (arraytype) { + arraytype = false; + } else { + loccnt++; + } + break; + case 'L': + case 'Q': + for (; ; k++) { + if (k >= siglen) { + errMsg = "ClassTypeSignature is not properly terminated: L{PackageSpecifier/}SimpleClassTypeSignature;"; + break scan; + } + if (sig.charAt(k) == ';') { + break; + } + } + loccnt++; + arraytype = false; + break; + default: + errMsg = "Unknown token \"%s\" in \"({JavaTypeSignature})Result\"".formatted(sig.charAt(k)); + break scan; + } + } + } + environment.warning(scanner.prevPos, "err.msig.malformed", k + 1, errMsg); + return loccnt; + } + + /** + * Parse a method. + */ + private void parseMethod(int mod) throws SyntaxError, IOException { + traceMethodInfoLn("Begin"); + long scannerPosition = scanner.prevPos; + // The start of the method + ConstCell nameCell = parseName(); + ConstValue_UTF8 strConst = (ConstValue_UTF8) nameCell.ref; + String name = strConst.value; + boolean is_clinit = name.equals(""); + // TODO: not a good way to detect factories... + boolean is_init = name.equals("") && !EModifier.isStatic(mod); + + // check access modifiers: + Checker.checkMethodModifiers(classData, mod, scannerPosition, is_init, is_clinit); + + scanner.expect(Token.COLON); + ConstCell typeCell = parseName(); + int paramCount = countParams(typeCell); + if ((!EModifier.isStatic(mod)) && !is_clinit) { + paramCount++; + } + if (paramCount > 255) { + environment.warning(scanner.pos, "warn.msig.more255", Integer.toString(paramCount)); + } + + MethodData curMethod = (MethodData) classData.StartMethod(mod, nameCell, typeCell, null).addAnnotations(memberAnnotations); + + // Parse the optional attribute(s): signature + // :SIGNATURE or :#d + if (scanner.token == COLON) { + scanner.scan(); + if (!scanner.expectOneOfToken(CPINDEX, IDENT, STRINGVAL)) { + environment.error(scanner.pos, "err.name.expected", + "\"" + scanner.token.parseKey() + "\""); + throw new SyntaxError(); + } + // Signature expected + ConstCell signatureCell = parseName(); + if (signatureCell != null) { + curMethod.setSignatureAttr(signatureCell); + } + } + boolean nextAttributeExpected = false, endClassExpected = false; + if (scanner.token == SEMICOLON) { + // probably method header is closed + // public varargs abstract Method #5:#6:#15; + endClassExpected = true; + } + // Parse the optional attribute(s): signature, exceptions, default annotation + boolean parseNext = true; + do { + switch (scanner.token) { + // Parse throws clause, it expected to be the last clause. + case THROWS -> { + if (curMethod.hasExceptions()) { + environment.warning(scanner.pos, "warn.method_info.attribute.repeated", + ATT_Exceptions.parseKey()); + } + nextAttributeExpected = false; + ArrayList> exceptions = parseThrowsClause(curMethod.getExceptions()); + curMethod.addExceptions(exceptions); + if( scanner.token == SEMICOLON ) { + parseNext = false; + scanner.scan(); + } else if( scanner.expectOneOfToken(STACK, LOCAL, LBRACE) ) { + parseNext = false; + } + } + // Parse default clause + case DEFAULT -> { + if (curMethod.getDefaultAnnotation() != null) { + environment.throwErrorException(scanner.pos, "err.method_info.attribute.repeated", + ATT_AnnotationDefault.parseKey()); + } + DefaultAnnotationAttr defAnnot = annotParser.parseDefaultAnnotation(); + if (defAnnot != null) { + curMethod.setDefaultAnnotation(defAnnot); + } + if (scanner.token == SEMICOLON) { + endClassExpected = true; + parseNext = false; + } else if (scanner.expectOneOfToken(SIGNATURE, THROWS)) { + continue; + } + scanner.scan(); + } + // parse signature + case SIGNATURE -> { + scanner.scan(); + if (curMethod.getSignatureAttr() != null) { + environment.warning(scanner.pos, "warn.method_info.attribute.repeated", + ATT_Signature.parseKey()); + } + nextAttributeExpected = false; + ConstCell signatureCell = parseName(); + if (signatureCell != null) { + curMethod.setSignatureAttr(signatureCell); + } + } + case SEMICOLON -> { + parseNext = false; + scanner.scan(); + } + case COMMA -> { + nextAttributeExpected = true; + scanner.scan(); + } + default -> { + if (nextAttributeExpected) { + ArrayList expected = new ArrayList<>(); + if (curMethod.getDefaultAnnotation() == null) { + expected.add(DEFAULT); + } + if (!curMethod.hasExceptions()) { + expected.add(THROWS); + } + if (curMethod.getSignatureAttr() == null) { + expected.add(SIGNATURE); + } + if (expected.size() != 1) { + environment.throwErrorException(scanner.prevPos, "err.one.of.N.token.expected", JasmTokens.asString(expected)); + } else { + environment.throwErrorException(scanner.prevPos, "err.token.expected", expected.get(0).parseKey()); + } + } + parseNext = false; + } + } + } while (parseNext); + + if (!endClassExpected) { + Indexer max_stack = null, max_locals = null; + do { + if (scanner.token == STACK) { + scanner.scan(); + max_stack = parseUInt(2); + } + if (scanner.token == LOCAL) { + scanner.scan(); + max_locals = parseUInt(2); + } + if (scanner.token == INTVAL) { + annotParser.parseParamAnnotation(paramCount, curMethod); + } + } while (scanner.token.in(STACK, LOCAL, INTVAL)); + + if (scanner.token == SEMICOLON) { + if ((max_stack != null) || (max_locals != null)) { + environment.error("err.token.expected", LBRACE.parseKey()); + } + scanner.scan(); + } else if (!EModifier.isAbstract(mod)) { + scanner.expect(LBRACE); + curCodeAttr = curMethod.startCode(paramCount, max_stack, max_locals); + parseCodeAttribute(); + curCodeAttr.endCode(); + scanner.expect(RBRACE); + } else { // abstract method could have empty body {} and even not empty + if (scanner.token == LBRACE) { + scanner.scan(); + curCodeAttr = curMethod.startCode(paramCount, max_stack, max_locals); + parseCodeAttribute(); + curCodeAttr.endCode(); + scanner.expect(RBRACE); + } + } + } + classData.EndMethod(); + traceMethodInfoLn("End of the method " + curMethod); + } // end parseMethod + + private void parseCodeAttribute() throws IOException { + while ((scanner.token != EOF) && (scanner.token != RBRACE)) { + instrParser.parseInstr(); + if (scanner.token == RBRACE) { + break; + } else if (scanner.token == LINETABLE_HEADER) { + curCodeAttr.fillLineTable(attributeParser.parseLineTable()); + continue; + } else if (scanner.token == LOCALVARIABLES_HEADER) { + curCodeAttr.fillLocalVariableTable(false, attributeParser.parseLocalVariableTable(false)); + continue; + } else if (scanner.token == LOCALVARIABLETYPES_HEADER) { + curCodeAttr.fillLocalVariableTable(true, attributeParser.parseLocalVariableTable(true)); + continue; + } else if (scanner.token == ANNOTATION) { + curCodeAttr.addAnnotations(annotParser.parseAnnotations()); + continue; + } else if (scanner.token == STACKMAP_HEADER) { + curCodeAttr.fillStackMapTable(attributeParser.parseStackMap()); + continue; + } else if (scanner.token == STACKMAPTABLE_HEADER) { + curCodeAttr.fillStackMapTable(attributeParser.parseStackMapTable()); + continue; + } + scanner.expect(SEMICOLON); + } + } + + /** + * @return list of the exception classes + */ + private ArrayList> parseThrowsClause(DataVectorAttr> exceptionList) { + scanner.scan(); + ArrayList> list = new ArrayList<>(); + for (; ; ) { + ConstCell exc = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); + if (exceptionList != null && exceptionList.contains(exc)) { + environment.warning(scanner.pos, "warn.exc.repeated"); + } + list.add(exc); + if (scanner.token == SEMICOLON) { + break; + } else if (scanner.token != COMMA) { + break; + } + scanner.scan(); + } + return list; + } + + /** + * Parse a group of BootstrapMethod entries. + *

+ * BootstrapMethods { + * N: MethodHandle; + * ( + * Arguments: + * (ARG,)* + * ARG; + * )? + * } + */ + private void parseBootstrapMethodGroup() throws SyntaxError { + scanner.scan(); + scanner.expect(LBRACE); + List expectedToken = List.of(INTVAL); + int mhIndex = 0; + ConstCell MHCell = null; + ArrayList> bsm_args = new ArrayList<>(10); + while (true) { + switch (scanner.token) { + case INTVAL -> { + // 0: + if (!expectedToken.contains(scanner.token)) { + environment.throwErrorException(scanner.pos, "err.token.expected", INTVAL.parseKey()); + } + if (MHCell != null) { + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, bsm_args)); + } + scanner.expect(INTVAL); + mhIndex = scanner.intValue; + scanner.expect(COLON); + MHCell = parseMHCell(); + if (scanner.token == CPINDEX) { + scanner.scan(); + scanner.expect(SEMICOLON); + } + expectedToken = List.of(ARGUMENTS, INTVAL, RBRACE); + } + case ARGUMENTS -> { + if (!expectedToken.contains(scanner.token)) { + environment.throwErrorException(scanner.pos, "err.token.isnot.expected", ARGUMENTS.parseKey()); + } + scanner.scan(); + scanner.expect(COLON); + cpParser.incLBRACE(); + // scan Bootstrap arguments + bsm_args = new ArrayList<>(10); + expectedToken = List.of(CPINDEX, IDENT, CLASS); + while (true) { + if (scanner.token.in(CPINDEX, IDENT, CLASS)) { + if (!expectedToken.contains(scanner.token)) { + environment.throwErrorException(scanner.pos, "err.bootstrap.arg.is.not.expected"); + } + bsm_args.add(cpParser.parseConstRef(null)); + expectedToken = List.of(COMMA, SEMICOLON); + } else if (scanner.token == COMMA) { + if (!expectedToken.contains(scanner.token)) { + environment.throwErrorException(scanner.pos, "err.token.isnot.expected", COMMA.parseKey()); + } + scanner.scan(); + expectedToken = List.of(CPINDEX, IDENT); + } else if (scanner.token == SEMICOLON) { + if (!expectedToken.contains(scanner.token)) { + environment.throwErrorException(scanner.pos, "err.token.isnot.expected", SEMICOLON.parseKey()); + } + cpParser.decLBRACE(); + scanner.scan(); + break; + } else { + if (bsm_args.isEmpty()) { + environment.throwErrorException(scanner.pos, "err.bootstrap.arg.expected"); + } else { + String expectedTokens = expectedToken.stream().map(Token::printValue). + collect(Collectors.joining(", ")); + environment.throwErrorException(scanner.pos, "err.one.of.N.token.expected", + expectedTokens); + } + } + } + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, bsm_args)); + MHCell = null; + bsm_args = new ArrayList<>(10); + expectedToken = List.of(INTVAL, RBRACE); + } + case RBRACE -> { + if (!expectedToken.contains(scanner.token)) { + environment.throwErrorException(scanner.pos, "err.token.expected", RBRACE.parseKey()); + } + if (MHCell != null) { + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, bsm_args)); + } + scanner.scan(); + return; + } + default -> { + String expectedTokens = expectedToken.stream().map(Token::printValue).collect(Collectors.joining(", ")); + environment.throwErrorException(scanner.pos, + (expectedToken.size() == 1) ? "err.token.expected" : "err.one.of.N.token.expected", expectedTokens); + } + } + } + } + + /** + * Parse a BootstrapMethod entry individually. + *

+ * Two formats are supported: + * BootstrapMethod #METHODHANDLE (#ARG)*; + * BootstrapMethod #MH; { (#ARG,)* (ARG)? } + */ + private void parseBootstrapMethod() throws SyntaxError { + ArrayList> bsm_args = new ArrayList<>(256); + ConstCell MHCell = parseMHCell(); + if (scanner.token != LBRACE) { + // in the case BootstrapMethod REF_invokeStatic:Phoo.phee:"()LBoo;"; { } don't skip LBRACE + scanner.scan(); + } + if (scanner.token == SEMICOLON) { + // BOOTSTRAPMETHOD MethodHandle; ({(ARG,)* ARG;]})? + scanner.scan(); + if (scanner.token == LBRACE) { + scanner.scan(); + cpParser.incLBRACE(); + if (scanner.token == RBRACE) { + // BSMethod doesn't have arguments. + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, List.of())); + scanner.scan(); + return; + } + // scan Bootstrap arguments + while (true) { + bsm_args.add(cpParser.parseConstRef(null)); + if (scanner.token.in(COMMA, SEMICOLON)) { + scanner.scan(); + if (scanner.token == RBRACE) { + cpParser.decLBRACE(); + scanner.scan(); + break; + } + } else if (scanner.token == RBRACE) { + cpParser.decLBRACE(); + scanner.scan(); + break; + } else { + environment.throwErrorException(scanner.pos, "err.one.of.N.token.expected", + "%s, %s, or %s".formatted(COMMA.printValue(), SEMICOLON.printValue(), RBRACE.printValue())); + } + } + } // else BSMethod doesn't have arguments: BootstrapMethod #MH; + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, bsm_args)); + } + if (scanner.token == LBRACE) { + scanner.scan(); + cpParser.incLBRACE(); + if (scanner.token == RBRACE) { + // BSMethod doesn't have arguments. + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, List.of())); + scanner.scan(); + return; + } + // scan Bootstrap arguments + while (true) { + bsm_args.add(cpParser.parseConstRef(null)); + if (scanner.token.in(COMMA, SEMICOLON)) { + scanner.scan(); + if (scanner.token == RBRACE) { + cpParser.decLBRACE(); + scanner.scan(); + break; + } + } else if (scanner.token == RBRACE) { + cpParser.decLBRACE(); + scanner.scan(); + break; + } else { + environment.throwErrorException(scanner.pos, "err.one.of.N.token.expected", + "%s, %s, or %s".formatted(COMMA.printValue(), SEMICOLON.printValue(), RBRACE.printValue())); + } + } + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, bsm_args)); + } else if (scanner.token == Token.CPINDEX) { + // CPX can be a CPX to a MethodHandle constant + // BootstrapMethod #MH #ARG1 #ARG2; + int cpx = scanner.intValue; + bsm_args.add(pool.getCell(cpx)); + scanner.scan(); + while (scanner.token != Token.SEMICOLON) { + if (scanner.token == Token.CPINDEX) { + bsm_args.add(pool.getCell(scanner.intValue)); + } else { + // throw error, bootstrap method is not recognizable + environment.throwErrorException(scanner.pos, "invalid.bootstrapmethod"); + } + scanner.scan(); + } + classData.addBootstrapMethod(new BootstrapMethodData(MHCell, bsm_args)); + } + } + + private ConstCell parseMHCell() throws SyntaxError { + ConstCell MHCell; + if (scanner.token == CPINDEX) { + // MethodHandle #CPX + int cpx = scanner.intValue; + MHCell = pool.getCell(cpx); + } else { + // MethodHandle [INVOKESUBTAG|INVOKESUBTAG_INDEX] : [METHODREF|INTERFACEMETHODREF] + // INVOKESUBTAG : REF_INVOKEINTERFACE, REF_NEWINVOKESPECIAL, ... + SubTag subTag = parser.parseSubtag(); + scanner.expect(Token.COLON); + if (scanner.token == Token.CPINDEX) { + int cpx = scanner.intValue; + MHCell = pool.getCell(cpx); + scanner.scan(); + } else { + MHCell = parser.parseMethodHandle(subTag); + } + scanner.expect(SEMICOLON); + } + return MHCell; + } + + /** + * Parse the class Signature entry. + */ + private void parseClassSignature() throws SyntaxError { + // Parses in the form: + // SIGNATURE; + // where + // SIGNATURE = (CPINDEX | STRING) + traceMethodInfoLn("Begin"); + ConstCell signatureCell = parseName(); + traceMethodInfoLn("Signature: " + signatureCell); + classData.setSignatureAttr(signatureCell); + } + + /** + * Parse class reference used by statements: + * this_class[:] (CPINDEX | STRING); + * super_class[:] (CPINDEX | STRING); + */ + private void parseClassRef(Consumer> consumer) { + traceMethodInfoLn("Begin"); + if (scanner.token == COLON) { + scanner.scan(); + } + ConstCell nm = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + consumer.accept(nm); + } + + private void parseSourceFile() throws SyntaxError { + // Parses in the form: + // SOURCEFILE (CPINDEX | IDENT); + traceMethodInfoLn("Begin"); + String cpSourceFile = null; + if (pool.findUTF8Cell(EAttribute.ATT_SourceFile.parseKey()) != null) { + String sourceName = environment.getSourceName(); + ConstCell cell = pool.lookupUTF8Cell(name -> name.contains(sourceName) && + StringUtils.contains.apply(name, List.of(".java", ".jcod", ".jasm", ".class"))); + if (cell != null) { + cpSourceFile = (String) cell.ref.value; + } + } + ConstCell sourceFileCell = parseName(); + if (sourceFileCell.ref == null && sourceFileCell.cpIndex != NotSet) { + environment.error(scanner.prevPos, "err.wrong.sourcefile.ref"); + throw new SyntaxError(); + } + traceMethodInfoLn("Source File: " + sourceFileCell); + if (cpSourceFile != null && !cpSourceFile.equals(sourceFileCell.ref.value)) { + // new file name that overwrites CP value. + environment.warning(scanner.prevPos, "warn.extra.attribute", + EAttribute.ATT_SourceFile.parseKey(), sourceFileCell.ref.value); + } + classData.setSourceFileAttr(sourceFileCell); + } + + /** + * Parse a SourceDebugExtension attribute + */ + private void parseSourceDebugExtension() throws SyntaxError { + // Parses in the form: + // SOURCEDEBUGEXTENSION { ("STRING"; | (0x?? )+; )+ } + traceMethodInfoLn("Begin"); + SourceDebugExtensionAttr sourceDebugExtensionAttr = classData.setSourceDebugExtensionAttr(); + boolean prevSemicolonParsed = true; + + scanner.expect(LBRACE); + while (true) { + switch (scanner.token) { + case INTVAL, BYTEVAL, SHORT -> { + try { + sourceDebugExtensionAttr.append(scanner.intValue); + } catch (IllegalArgumentException ex) { + environment.error(scanner.pos, "err.token.expected", STRINGVAL.parseKey()); + throw new SyntaxError(); + } + // SEMICOLON ignored if list of bytes + prevSemicolonParsed = false; + } + case STRINGVAL -> { + if (!prevSemicolonParsed) { + environment.error(scanner.pos, "err.token.expected", SEMICOLON.parseKey()); + throw new SyntaxError(); + } + try { + sourceDebugExtensionAttr.append(scanner.stringValue); + } catch (IllegalArgumentException ex) { + environment.error(scanner.pos, "err.token.expected", BYTEVAL.parseKey()); + throw new SyntaxError(); + } + prevSemicolonParsed = false; + } + case SEMICOLON -> { + if (prevSemicolonParsed) { + environment.error(scanner.pos, "err.token.expected", + (sourceDebugExtensionAttr.type == SourceDebugExtensionAttr.Type.BYTE) ? + BYTEVAL.parseKey() : STRINGVAL.parseKey()); + throw new SyntaxError(); + } + prevSemicolonParsed = true; + } + case RBRACE -> { + if (!prevSemicolonParsed) { + environment.error(scanner.pos, "err.token.expected", SEMICOLON.parseKey()); + throw new SyntaxError(); + } + if (sourceDebugExtensionAttr.isEmpty()) { + environment.warning(scanner.pos, "warn.empty.debug.extension"); + } + scanner.scan(); + return; + } + default -> { + if (prevSemicolonParsed) { + environment.error(scanner.pos, "err.one.of.two.token.expected", + STRINGVAL.parseKey(), RBRACE.parseKey()); + } else { + environment.error(scanner.pos, "err.token.expected", SEMICOLON.parseKey()); + } + + throw new SyntaxError(); + + } + } + // next line + scanner.scan(); + } + } + + /** + * Parse a NestHost entry + */ + private void parseNestHost() throws SyntaxError { + // Parses in the form: + // NESTHOST IDENT; + traceMethodInfoLn("Begin"); + ConstCell cell = parseConstantClassInfo(true); + if (!cell.getType().oneOf(ConstType.CONSTANT_UTF8, ConstType.CONSTANT_CLASS)) { + throwSyntaxError("err.class.name.expected"); + } + classData.addNestHost(cell); + traceMethodInfoLn("NestHost: class " + cell); + scanner.expect(SEMICOLON); + } + + /** + * Parse a list of classes belonging to the [NestMembers | PermittedSubclasses] entry + */ + private void parseClasses(Consumer> classesConsumer) throws SyntaxError { + ArrayList classes = new ArrayList<>(); + // Parses in the form: + // (NESTMEMBERS|PERMITTEDSUBCLASSES)? IDENT(, IDENT)*; + traceMethodInfoLn("Begin"); + while (true) { + ConstCell cell = parseConstantClassInfo(true); + if (!cell.getType().oneOf(ConstType.CONSTANT_UTF8, ConstType.CONSTANT_CLASS)) { + throwSyntaxError("err.class.name.expected"); + } + classes.add(cell); + traceMethodInfoLn("Added cell: " + cell); + if (scanner.token != COMMA) { + scanner.expect(SEMICOLON); + classesConsumer.accept(classes); + return; + } + scanner.scan(); + } + } + + /** + * Valhalla specific + * Parse a list of Utf-8 belonging to the [LoadableDescriptors] entry + */ + private void parseUtf8List(Consumer> utf8Consumer) throws SyntaxError { + ArrayList utf8List = new ArrayList<>(); + // Parses in the form: + // (LOADABLEDESCRIPTORS)? IDENT(, IDENT)*; + traceMethodInfoLn("Begin"); + while (true) { + ConstCell cell = parseName(); + if (!cell.getType().equals(ConstType.CONSTANT_UTF8)) { + throwSyntaxError("err.field.descriptor.expected"); + } + utf8List.add(cell); + traceMethodInfoLn("Added cell: " + cell); + if (scanner.token != COMMA) { + scanner.expect(SEMICOLON); + utf8Consumer.accept(utf8List); + return; + } + scanner.scan(); + } + } + + + private void parseEnclosingMethod() { + // Parse in the form: + // ENCLOSINGMETHOD (CPINDEX | CLASS_NAME)(: CPINDEX | METHOD_NAME:"METHOD_SIGNATURE"); + traceMethodInfoLn("Begin"); + ConstCell classCell = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + if (scanner.token == SEMICOLON) { + //If the current class is not immediately enclosed by a method or constructor, + // then the value of the method_index item must be zero. + classData.addEnclosingMethod(classCell, null); + return; + } + scanner.expect(COLON); + ConstCell methodCell = null; + if (scanner.token.in(CPINDEX, INTVAL)) { + int methodCPIdx = scanner.intValue; + if (methodCPIdx != 0) { + methodCell = pool.getCell(methodCPIdx); + } + scanner.scan(); + } else { + methodCell = pool.findCell(cpParser.parseConstValue(ConstType.CONSTANT_NAMEANDTYPE)); + } + classData.addEnclosingMethod(classCell, methodCell); + } + + // Parse the Record entry + private void parseRecord() throws SyntaxError { + // Parses in the form: + // RECORD { (COMPONENT)+ } + // where + // COMPONENT Component (ANNOTATION)* NAME:DESCRIPTOR(:SIGNATURE)? (,|;) + // NAME = (CPINDEX | IDENT) + // DESCRIPTOR = (CPINDEX | STRING) + // SIGNATURE = (CPINDEX | STRING) + traceMethodInfoLn("Begin"); + scanner.expect(LBRACE); + + RecordData rd = classData.setRecord(scanner.pos); + + while (true) { + if (scanner.token == RBRACE) { + if (rd.isEmpty()) { + environment.warning(scanner.pos, "warn.no.components.in.record.attribute"); + classData.rejectRecord(); + } + scanner.scan(); + break; + } + + ConstCell nameCell, descCell, signatureCell = null; + ArrayList componentAnnotations = null; + if (scanner.token == ANNOTATION) { + componentAnnotations = annotParser.parseAnnotations(); + } + + scanner.expect(COMPONENT); + nameCell = parseName(); + scanner.expect(COLON); + descCell = parseName(); + + switch (scanner.token) { + case COMMA, SEMICOLON -> { + // end of the component + scanner.scan(); + if (scanner.token == SIGNATURE) { + scanner.scan(); + signatureCell = parseName(); + } else { + rd.addComponent(nameCell, descCell, signatureCell, componentAnnotations); + continue; + } + } + case COLON -> { + // Parse the optional attribute: signature + scanner.scan(); + if (scanner.token == SIGNATURE) { + scanner.scan(); + } + signatureCell = parseName(); + } + } + + rd.addComponent(nameCell, descCell, signatureCell, componentAnnotations); + + if (!scanner.token.in(COMMA, SEMICOLON)) { + environment.throwErrorException(scanner.pos, "err.one.of.two.token.expected", + "<" + SEMICOLON.printValue() + ">", + "<" + COMMA.printValue() + ">"); + + } + // next component + scanner.scan(); + } // end while + traceMethodInfoLn("End"); + } + + /** + * Parse a group of InnerClasses. + * + * @param mod inner_class_access_flags is ignored for a group of inner classes. + */ + private void parseInnerClassGroup(int mod) throws SyntaxError, IOException { + // Parses in the form: + // INNERCLASSES { (INNER_CLASS)+ } + // INNER_CLASS = MODIFIERS (INNERCLASSNAME =)? (INNERCLASS) (OF OUTERCLASS)? [;|,] + // } + // where + // INNERCLASSNAME = (IDENT | CPX_IN-CL-NM) + // INNERCLASS = (CLASS IDENT | CPX_IN-CL) (S2) + // OUTERCLASS = (CLASS IDENT | CPX_OT-CL) (S3) + // + // Note: + // If a class reference cannot be identified using IDENT, CPX indexes must be used. + traceMethodInfoLn("Begin"); + if (mod != 0) { + environment.warning(scanner.pos, "warn.invalid.modifier.innerclasses"); + } + scanner.expect(LBRACE); + while (true) { + if (scanner.token == RBRACE) { + if (classData.innerClasses == null || classData.innerClasses.isEmpty()) { + environment.warning(scanner.pos, "warn.no.classes.in.innnerclasses"); + } + scanner.scan(); + break; + } + parseInnerClass(0); + if (!scanner.token.in(COMMA, SEMICOLON)) { + environment.throwErrorException(scanner.pos, "err.one.of.two.token.expected", + "<" + SEMICOLON.printValue() + ">", + "<" + COMMA.printValue() + ">"); + + } + scanner.scan(); + } + traceMethodInfoLn("End"); + } + + /** + * Parse an inner class. + * + * @param mod inner_class_access_flags + */ + private void parseInnerClass(int mod) throws SyntaxError, IOException { + // Parses in the form: + // MODIFIERS (INNERCLASSNAME =)? (INNERCLASS) (OF OUTERCLASS)? ; + // + // where + // INNERCLASSNAME = (IDENT | CPX_IN-CL-NM) + // INNERCLASS = (CLASS IDENT | CPX_IN-CL) (S2) + // OUTERCLASS = (CLASS IDENT | CPX_OT-CL) (S3) + // + // Note: + // If a class reference cannot be identified using IDENT, CPX indexes must be used. + + // check access modifiers: + traceMethodInfoLn("Begin"); + Checker.checkInnerClassModifiers(classData, mod, scanner.pos); + // possible case "MODIFIERS InnerClass MODIFIERS (INNERCLASSNAME =)? (INNERCLASS) (OF OUTERCLASS)? ;" + int inlineMod = scanModifiers(); + if (mod != 0 && inlineMod != 0) { + environment.warning(scanner.pos, "warn.both.modifiers.apply", + EModifier.asKeywords(mod | inlineMod, ClassFileContext.INNER_CLASS).strip()); + } + mod |= inlineMod; + + ConstCell nameCell, innerClass = null, outerClass = null; + + if (scanner.token == CLASS) { + nameCell = pool.getCell(0); // no NameIndex + parseInnerClass_s2(mod, nameCell, innerClass, outerClass); + } else { + if (scanner.token == IDENT && scanner.checkTokenIdent()) { + // Got a Class Name + nameCell = parseName(); + parseInnerClass_s1(mod, nameCell, innerClass, outerClass); + } else if (scanner.token == CPINDEX) { + // CPX can be either a CPX to an InnerClassName, + // or a CPX to an InnerClassInfo + int cpx = scanner.intValue; + nameCell = pool.getCell(cpx); + ConstValue nameCellValue = nameCell.ref; + + if (nameCellValue instanceof ConstValue_UTF8) { + // got a name cell + scanner.scan(); + parseInnerClass_s1(mod, nameCell, innerClass, outerClass); + } else { + // got a CPRef cell + nameCell = pool.getCell(0); // no NameIndex + parseInnerClass_s2(mod, nameCell, innerClass, outerClass); + } + } else if (scanner.token.isPossibleJasmIdentifier()) { + // The name InnerClass of the inner class is allowed. + nameCell = pool.findUTF8Cell(scanner.token.parseKey()); + scanner.scan(); + parseInnerClass_s1(mod, nameCell, innerClass, outerClass); + } else { + pic_error(); + } + } + traceMethodInfoLn("End"); + } + + private void parseInnerClass_s1(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws + IOException { + // the next scanner.token must be '=' + if (scanner.token == ASSIGN) { + scanner.scan(); + parseInnerClass_s2(mod, nameCell, innerClass, outerClass); + } else { + pic_error(); + } + } + + private void parseInnerClass_s2(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws + IOException { + // scanner.token is either "CLASS IDENT" or "CPX_Class" + if ((scanner.token == CPINDEX) || (scanner.token == CLASS)) { + if (scanner.token == CPINDEX) { + innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); + } + + if (scanner.token == CLASS) { + // next symbol needs to be InnerClass + scanner.scan(); + // innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); ignore keywords as much as possible: + // private static InnerClass Module = class NormalModule$Module of class NormalModule; + innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + } + + // See if declaration is terminated + if (scanner.token == SEMICOLON) { + // InnerClass is complete, no OUTERINFO; + outerClass = pool.getCell(0); + pic_tracecreate(mod, nameCell, innerClass, outerClass); + classData.addInnerClass(mod, nameCell, innerClass, outerClass); + } else if (scanner.token == OF) { + // got an outer class reference + parseInnerClass_s3(mod, nameCell, innerClass, outerClass); + } else { + pic_error(); + } + + } else { + pic_error(); + } + + } + + private void parseInnerClass_s3(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws + IOException { + scanner.scan(); + if ((scanner.token == CLASS) || (scanner.token == CPINDEX)) { + if (scanner.token == CLASS) { + // next symbol needs to be InnerClass + scanner.scan(); + // outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); ignore keywords as much as possible: + // private static InnerClass NormalModule = class Module$NormalModule of class Module; + outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + + } + if (scanner.token == CPINDEX) { + outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); + } + + if (scanner.token == SEMICOLON) { + pic_tracecreate(mod, nameCell, innerClass, outerClass); + classData.addInnerClass(mod, nameCell, innerClass, outerClass); + } else { + pic_error(); + } + } else { + pic_error(); + } + } + + private void pic_tracecreate(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) { + // throw error, IC is not recognizable + traceMethodInfoLn("Creating InnerClass:"); + environment.trace("[" + EModifier.asNames(mod, ClassFileContext.INNER_CLASS) + "], "); + + if (nameCell != pool.getCell(0)) { + ConstValue value = nameCell.ref; + if (value != null) { + environment.trace(value + " =\n\t\t"); + } + } + + ConstValue_Cell ici_val = (ConstValue_Cell) innerClass.ref; + ConstCell ici_ascii = ici_val.value; + // Constant pool may not be numberized yet. + // + // check values before dereference on a trace. + if (ici_ascii.ref == null) { + environment.trace("<#cpx-unresolved> "); + } else { + if (ici_ascii.ref.value == null) { + environment.trace("<#cpx-0> "); + } else { + environment.trace(ici_ascii.ref.value + " "); + } + } + + if (outerClass != pool.getCell(0)) { + if (outerClass.cpIndex != 0) { + ConstValue_Cell oci_val = (ConstValue_Cell) outerClass.ref; + ConstCell oci_ascii = oci_val.value; + if (oci_ascii.ref == null) { + environment.trace("\n\t\tof <#cpx-unresolved> "); + } else { + ConstValue_UTF8 cval = (ConstValue_UTF8) oci_ascii.ref; + if (cval.value == null) { + environment.trace("\n\t\tof <#cpx-0> "); + } else { + environment.trace("\n\t\tof " + cval.value); + } + } + } + } + environment.trace("\n"); + } + + private void pic_error() { + // throw error, IC is not recognizable + environment.error(scanner.pos, "err.invalid.innerclass"); + throw new SyntaxError(); + } + + /** + * The match() method is used to quickly match opening + * brackets (ie: '(', '{', or '[') with their closing + * counterpart. This is useful during error recovery.

+ *

+ * Scan to a matching '}', ']' or ')'. The current scanner.token must be + * a '{', '[' or '('; + */ + private void match(Token open, Token close) { + int depth = 1; + + while (true) { + scanner.scan(); + if (scanner.token == open) { + depth++; + } else if (scanner.token == close) { + if (--depth == 0) { + return; + } + } else if (scanner.token == EOF) { + environment.error(scanner.pos, "err.unbalanced.paren"); + return; + } + } + } + + /** + * Recover after a syntax error in a field. This involves + * discarding scanner.tokens until an EOF or a possible legal + * continuation is encountered. + */ + private void recoverField() throws SyntaxError { + while (true) { + switch (scanner.token) { + case EOF: + case STATIC: + case FINAL: + case PUBLIC: + case PRIVATE: + case SYNCHRONIZED: + case TRANSIENT: + case PROTECTED: + case VOLATILE: + case NATIVE: +// case INTERFACE: see below + case ABSTRACT: + case ANNOTATION_ACCESS: + // possible begin of a field, continue + return; + + case LBRACE: + match(LBRACE, RBRACE); + scanner.scan(); + break; + + case LPAREN: + match(LPAREN, RPAREN); + scanner.scan(); + break; + + case LSQBRACKET: + match(LSQBRACKET, RSQBRACKET); + scanner.scan(); + break; + + case RBRACE: + case INTERFACE: + case CLASS: + case IMPORT: + case PACKAGE: + // begin of something outside a class, panic more + endClass(); + traceMethodInfoLn("scanner position %d".formatted(scanner.pos)); + throw new SyntaxError().setFatal(); + default: + // don't know what to do, skip + scanner.scan(); + break; + } + } + } + + /** + * Parse a class or interface declaration. + */ + private void parseClass(int mod) throws IOException { + long posa = scanner.pos; + traceMethodInfoLn("Begin"); + // check access modifiers: + Checker.checkClassModifiers(mod, scanner); + if (classAnnotations != null) { + classData.addAnnotations(classAnnotations); + } + + // move the tokenizer to the identifier: + if (scanner.token == CLASS) { + scanner.scan(); + } else if (scanner.token == ANNOTATION) { + scanner.scan(); + if (scanner.token == INTERFACE) { + mod |= ACC_ANNOTATION.getFlag() | ACC_INTERFACE.getFlag(); + scanner.scan(); + } else { + environment.error(scanner.prevPos, "err.one.of.two.token.expected", + ANNOTATION.parseKey(), INTERFACE.parseKey()); + throw new SyntaxError(); + } + } + + // Parse the class name + ConstCell nm = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + + if (scanner.token == FIELD) { // DOT + String fileExtension; + scanner.scan(); + switch (scanner.token) { + // CLASS token added to allow: + // class ClassName.class version 45:0 {..} + case STRINGVAL, CLASS -> fileExtension = scanner.stringValue; + case IDENT -> fileExtension = scanner.idValue; + default -> { + environment.error(scanner.pos, "err.name.expected", "\"" + scanner.token.parseKey() + "\""); + throw new SyntaxError(); + } + } + scanner.scan(); + classData.fileExtension = "." + fileExtension; + } else if (scanner.token == MODULE) { + environment.error(scanner.prevPos, "err.token.expected", "\"" + OPEN.parseKey() + "\""); + throw new SyntaxError(); + } else if (scanner.token == SEMICOLON) { + // drop the semicolon following a name + scanner.scan(); + } else if (scanner.token == COLON) { + // parse optional attribute Signature + scanner.scan(); + parseClassSignature(); + } + + // Parse extends clause + ConstCell sup = null; + if (scanner.token == EXTENDS) { + scanner.scan(); + // sup = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); ignore keywords as much as possible: + // class Module$NormalModule extends Module version 63:0 + sup = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + while (scanner.token == COMMA) { + scanner.scan(); + environment.warning(posa, "warn.multiple.inherit"); + // sup = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); ignore keywords as much as possible: + // class Module$NormalModule extends Module version 63:0 + sup = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + } + } + + // Parse implements clause + ArrayList impl = new ArrayList<>(); + if (scanner.token == IMPLEMENTS) { + do { + scanner.scan(); + // Indexer intf = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); ignore keywords as much as possible: + // public interface AddressField implements Field version 63:0 + Indexer intf = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); + if (impl.contains(intf)) { + environment.warning(posa, "warn.intf.repeated", intf); + } else { + impl.add(intf); + } + } while (scanner.token == COMMA); + } + + // parse version + if (scanner.token == LBRACE) { + // no version info in the source + if (!classData.cfv.isSet() && !classData.cfv.isSetByParameter()) { + // the version isn't set by params + classData.cfv.initClassDefaultVersion(); + environment.warning(scanner.prevPos, "warn.default.cfv", classData.cfv.asString()); + } + } else { + if (classData.cfv.isSet() && classData.cfv.isSetByParameter() && classData.cfv.isFrozen()) { + int minor = classData.cfv.minor_version(); + int major = classData.cfv.major_version(); + String version = classData.cfv.asString(); + String option = classData.cfv.isThresholdSet() ? classData.cfv.asThresholdString() : + classData.cfv.asString(); + Pair ver = parseVersion(); + if (classData.cfv.isSetByParameter() && (ver.first != major || ver.second != minor)) + environment.warning(scanner.prevPos, "warn.isset.cfv", version, option); + } else { + parseVersion(); + if (EModifier.GlobalContext() == ClassFileContext.VALUE_OBJECTS && !classData.cfv.isValueObjectContext()) { + environment.warning(scanner.prevPos, "warn.value.object.defined", classData.cfv.asString(), + CFVersion.ValueObjectsVersion().asString()); + } + } + } + scanner.expect(LBRACE); + + // Begin a new class + classData.init(mod, nm, sup, impl); + + // Parse class members + while ((scanner.token != EOF) && (scanner.token != RBRACE)) { + switch (scanner.token) { + case SEMICOLON -> + // Empty fields are allowed + scanner.scan(); + case CONST -> { + scanner.scan(); + parseConstDef(); + explicitCP = true; + } + default -> // scanner.token is some member. + parseClassMembers(); + } + } + scanner.expect(RBRACE); + endClass(); + } // end parseClass + + /** + * Parses a package or type name in a module statement(s) + * + * @return Pair Either Package/Type name or CP Index for this Package/Type name. + */ + private NameInfo parseTypeName() { + String name = "", field = ""; + int cpIndex = 0; + if (scanner.token == IDENT) { + while (true) { + if (scanner.token.isPossibleClassName()) { + name = name + field + scanner.idValue; + scanner.scan(); + } else { + environment.error(scanner.pos, "err.name.expected", "\"" + scanner.token.parseKey() + "\""); + throw new SyntaxError(); + } + if (scanner.token == FIELD) { + environment.warning(scanner.pos, "warn.dot.will.be.converted"); + field = "/"; + scanner.scan(); + } else { + break; + } + } + } else if (scanner.token == CPINDEX) { + cpIndex = scanner.intValue; + scanner.scan(); + } + return new NameInfo(cpIndex, name); + } + + /** + * Parses a module name in a module statement(s) + * + * @return Pair Either Module name or CP Index for the module name. + */ + private NameInfo parseModuleName() { + String field = ""; + NameInfo nameInfo = new NameInfo(); + if (scanner.token == IDENT) { + while (true) { + if (scanner.token.isPossibleModuleName()) { + nameInfo.setName(nameInfo.name() + field + scanner.idValue); + scanner.scanModuleStatement(); + } else { + environment.error(scanner.pos, "err.module.name.expected", "\"" + scanner.token.parseKey() + "\""); + throw new SyntaxError().setFatal(); + } + if (scanner.token == FIELD) { + field = Character.toString((char) scanner.token.value()); + scanner.scanModuleStatement(); + } else { + break; + } + } + } else if (scanner.token == CPINDEX) { + nameInfo.setCpIndex(scanner.intValue); + scanner.scan(); + } else { + environment.error(scanner.pos, "err.module.name.expected", "\"" + scanner.token.parseKey() + "\""); + throw new SyntaxError().setFatal(); + } + return nameInfo; + } + + /** + * Parse a module declaration. + */ + private void parseModule(int mod) throws IOException { + traceMethodInfoLn("Begin"); + if (mod != 0) { + environment.warning(scanner.pos, "warn.modifiers.ignored", EModifier.asNames(mod, ClassFileContext.MODULE)); + } + if (classAnnotations != null) { + classData.addAnnotations(classAnnotations); + } + moduleAttribute = new ModuleAttr(classData); + + if (scanner.token == OPEN) { + moduleAttribute.openModule(); + scanner.scan(); + } + + // move the tokenizer to the identifier: + if (scanner.token == MODULE) { + scanner.scanModuleStatement(); + // scanner.scan(); + } else { + environment.error(scanner.pos, "err.token.expected", MODULE.parseKey()); + throw new SyntaxError().setFatal(); + } + // Parse the module name + NameInfo moduleNameInfo = parseModuleName(); + if (moduleNameInfo.isEmpty()) { + environment.error(scanner.pos, "err.name.expected", "\"" + scanner.token + "\""); + throw new SyntaxError().setFatal(); + } + if (moduleNameInfo.cpIndex() != 0) { + moduleAttribute.setModuleNameCpIndex(moduleNameInfo.cpIndex()); + } else { + moduleAttribute.setModuleName(moduleNameInfo.name()); + } + // parse version + if (scanner.token == LBRACE) { + classData.cfv.initModuleDefaultVersion(); + environment.warning(scanner.pos, "warn.default.cfv", classData.cfv.asString()); + } else { + parseVersion(); + } + scanner.expect(LBRACE); + + // Begin a new class as module + classData.initAsModule(); + + // Parse module statement(s) + while ((scanner.token != EOF) && (scanner.token != RBRACE)) { + switch (scanner.token) { + case CONST -> { + // Parse constant declarations + scanner.scan(); + parseConstDef(); + explicitCP = true; + } + case REQUIRES -> scanRequires(moduleAttribute.requires); + case EXPORTS -> scanStatement(moduleAttribute.exports, + this::parseTypeName, + this::parseModuleName, + TO, + true, + "err.exports.expected"); + case OPENS -> scanStatement(moduleAttribute.opens, + this::parseTypeName, + this::parseModuleName, + TO, true, "err.opens.expected"); + case PROVIDES -> scanStatement(moduleAttribute.provides, + this::parseTypeName, + this::parseTypeName, + WITH, + false, + "err.provides.expected"); + case USES -> scanStatement(moduleAttribute.uses, "err.uses.expected"); + case SEMICOLON -> + // Empty fields are allowed + scanner.scan(); + default -> { + environment.error(scanner.pos, "err.module.statement.expected"); + throw new SyntaxError().setFatal(); + } + } // end switch + } // while + scanner.expect(RBRACE); + // End of the module + endModule(); + } // end parseModule + + /** + * Scans ModuleStatement: requires [transitive|static|mandated|synthetic] ModuleName ; + * Scans ModuleStatement: requires [transitive|static|mandated|synthetic] #ref ; + */ + private void scanRequires(Consumer action) { + int flags = 0; + NameInfo moduleNameInfo = new NameInfo(); + scanner.scanModuleStatement(); + while (scanner.token != SEMICOLON) { + switch (scanner.token) { + case STATIC -> { + if (EModifier.isStaticPhase(flags) || !moduleNameInfo.isEmpty()) { + environment.error(scanner.pos, "err.requires.expected"); + throw new SyntaxError().setFatal(); + } + flags |= EModifier.ACC_STATIC_PHASE.getFlag(); + } + case TRANSITIVE -> { + if (EModifier.isTransitive(flags) || !moduleNameInfo.isEmpty()) { + environment.error(scanner.pos, "err.requires.expected"); + throw new SyntaxError().setFatal(); + } + flags |= EModifier.ACC_TRANSITIVE.getFlag(); + } + case SYNTHETIC -> { + if (EModifier.isSynthetic(flags) || !moduleNameInfo.isEmpty()) { + environment.error(scanner.pos, "err.requires.expected"); + throw new SyntaxError().setFatal(); + } + flags |= EModifier.ACC_SYNTHETIC.getFlag(); + } + case MANDATED -> { + if (EModifier.isMandated(flags) || !moduleNameInfo.isEmpty()) { + environment.error(scanner.pos, "err.requires.expected"); + throw new SyntaxError().setFatal(); + } + flags |= EModifier.ACC_MANDATED.getFlag(); + } + case IDENT, CPINDEX -> { + if (!moduleNameInfo.isEmpty()) { + environment.error(scanner.pos, "err.requires.expected"); + throw new SyntaxError().setFatal(); + } + moduleNameInfo = parseModuleName(); + continue; + } + default -> { + environment.error(scanner.pos, "err.requires.expected"); + throw new SyntaxError().setFatal(); + } + } + scanner.scanModuleStatement(); + } + // SEMICOLON + if (moduleNameInfo.isEmpty()) { + environment.error(scanner.pos, "err.requires.expected"); + throw new SyntaxError().setFatal(); + } + action.accept(new ModuleContent.Dependence(moduleNameInfo.cpIndex(), moduleNameInfo.name(), flags, null)); + scanner.scanModuleStatement(); + } + + /** + * Scans Module Statement(s): + * exports [mandated|synthetic] packageName [to ModuleName {, ModuleName}*] ; + * opens [mandated|synthetic] packageName [to ModuleName {, ModuleName}*] ; + * provides TypeName with TypeName {,typeName} ; + */ + private void scanStatement( + BiConsumer> action, + NameSupplier source, + NameSupplier target, + Token startList, + boolean emptyListAllowed, + String err) throws IOException { + boolean isProvidesStatement = (startList == WITH); + int flags = 0; // [mandated|synthetic] + NameInfo typeNameInfo = new NameInfo(); + HashSet nameInfos = new HashSet<>(); // to ModuleName {, ModuleName}* Or with TypeName {,typeName}* + scanner.scan(); + while (scanner.token != SEMICOLON) { + switch (scanner.token) { + case SYNTHETIC -> { + if (EModifier.isSynthetic(flags) || !typeNameInfo.isEmpty() || isProvidesStatement) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + flags |= EModifier.ACC_SYNTHETIC.getFlag(); + } + case MANDATED -> { + if (EModifier.isMandated(flags) || !typeNameInfo.isEmpty() || isProvidesStatement) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + flags |= EModifier.ACC_MANDATED.getFlag(); + } + case IDENT, CPINDEX -> { + if (!typeNameInfo.isEmpty()) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + typeNameInfo = source.get(); + continue; + } + case TO, WITH -> { // to[with] + nameInfos = scanList(isProvidesStatement ? () -> scanner.scan() : () -> scanner.scanModuleStatement(), + target, err, false); + continue; + } + default -> { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + } + if (isProvidesStatement) + scanner.scan(); + else + scanner.scanModuleStatement(); + } + // SEMICOLON + if (typeNameInfo.isEmpty() || (nameInfos.isEmpty() && !emptyListAllowed)) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + if (isProvidesStatement) { + // provides with Class(es) + Set classes = nameInfos.stream(). + map(nameInfo -> new ModuleContent.TargetType(CONSTANT_CLASS, nameInfo.cpIndex(), nameInfo.name())). + collect(Collectors.toSet()); + action.accept( + (T) (new ModuleContent.FlaggedTargetType(CONSTANT_CLASS, typeNameInfo.cpIndex(), typeNameInfo.name(), flags, ClassFileContext.MODULE)), + classes); + } else { + // Package to Module(s) + Set modules = nameInfos.stream(). + map(nameInfo -> new ModuleContent.TargetType(CONSTANT_MODULE, nameInfo.cpIndex(), nameInfo.name())). + collect(Collectors.toSet()); + action.accept( + (T) (new ModuleContent.FlaggedTargetType(CONSTANT_PACKAGE, typeNameInfo.cpIndex(), typeNameInfo.name(), flags, ClassFileContext.MODULE)), + modules); + } + scanner.scan(); + } + + /** + * Scans ModuleStatement: uses TypeName; + */ + private void scanStatement(Consumer action, String err) throws IOException { + HashSet nameInfos = scanList(() -> scanner.scan(), this::parseTypeName, err, true); + // SEMICOLON + if (nameInfos.size() != 1) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + nameInfos. + forEach(nameInfo -> action.accept(new ModuleContent.TargetType(CONSTANT_CLASS, nameInfo.cpIndex(), nameInfo.name()))); + scanner.scan(); + } + + /** + * Scans the "to" or "with" part of the following ModuleStatement: + * exports PackageName [to ModuleName {, ModuleName}] ;, + * opens PackageName [to ModuleName {, ModuleName}] ; + * provides TypeName with TypeName [,typeName] ; + * uses TypeName; + *

+ * : [ModuleName {, ModuleName}]; , [TypeName [,typeName]]; or TypeName; + */ + private HashSet scanList(Method scanMethod, NameSupplier target, + String err, boolean onlyOneElement) throws IOException { + HashSet nameInfos = new HashSet<>(); + boolean comma = false, first = true; + scanMethod.call(); + while (scanner.token != SEMICOLON) { + switch (scanner.token) { + case COMMA -> { + if (comma || first || onlyOneElement) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + comma = true; + } + case IDENT, CPINDEX -> { + if (!first && !comma) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + nameInfos.add(target.get()); + comma = false; + first = false; + continue; + } + default -> { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + } + scanner.scan(); + } + // SEMICOLON + if (nameInfos.isEmpty() || comma) { + environment.error(scanner.pos, err); + throw new SyntaxError().setFatal(); + } + return nameInfos; + } + + private void parseClassMembers() throws IOException { + traceMethodInfoLn("Begin"); + boolean bothFound = false; + // Parse annotations + if (scanner.token == ANNOTATION) { + memberAnnotations = annotParser.parseAnnotations(); + } + // Parse modifiers + int mod = scanModifiers(); + try { + switch (scanner.token) { + case FIELDREF -> { + scanner.scan(); + parseField(mod); + } + case METHODREF -> { + scanner.scan(); + parseMethod(mod); + } + case INNERCLASS -> { + scanner.scan(); + if (scanner.stringValue.equals(INNERCLASS.alias())) { + // Parse a group of InnerClasses {....} + parseInnerClassGroup(mod); + } else { + // Parse an InnerClass individually. + parseInnerClass(mod); + } + } + case BOOTSTRAPMETHOD -> { + if (scanner.stringValue.equals(BOOTSTRAPMETHOD.alias())) { + // Parse a group of BootstrapMethods {....} + parseBootstrapMethodGroup(); + } else { + scanner.scan(); + // Parse a BootstrapMethod individually. + parseBootstrapMethod(); + } + + } + case SIGNATURE -> { + scanner.scan(); + classData.setSignatureAttr(parseName(), scanner.pos); + scanner.expect(SEMICOLON); + } + case THIS_CLASS -> { + scanner.scan(); + parseClassRef(constCell -> classData.coreClasses.this_class(CLASSFILE, constCell)); + scanner.expect(SEMICOLON); + } + case SUPER_CLASS -> { + scanner.scan(); + parseClassRef(constCell -> classData.coreClasses.super_class(CLASSFILE, constCell)); + scanner.expect(SEMICOLON); + } + // + case SOURCEFILE -> { + classData.checkExistence(ATT_SourceFile, scanner.pos); + scanner.scan(); + parseSourceFile(); + scanner.expect(SEMICOLON); + } + case SOURCEDEBUGEXTENSION -> { + classData.checkExistence(ATT_SourceDebugExtension, scanner.pos); + scanner.scan(); + parseSourceDebugExtension(); + } + case NESTHOST -> { + classData.checkExistence(ATT_NestHost, scanner.pos). + checkExistence(ATT_NestMembers, () -> environment.warning(scanner.pos, "err.both.nesthost.nestmembers.found")); + scanner.scan(); + parseNestHost(); + } + case NESTMEMBERS -> { + classData.checkExistence(ATT_NestMembers, scanner.pos). + checkExistence(ATT_NestHost, () -> environment.warning(scanner.pos, "err.both.nesthost.nestmembers.found")); + scanner.scan(); + parseClasses(list -> classData.addNestMembers(list)); + } + case PERMITTEDSUBCLASSES -> { // JEP 360 + classData.checkExistence(ATT_PermittedSubclasses, scanner.pos); + scanner.scan(); + parseClasses(list -> classData.addPermittedSubclasses(list)); + } + case RECORD -> { // JEP 359 + classData.checkExistence(ATT_Record, scanner.pos); + scanner.scan(); + parseRecord(); + } + case LOADABLEDESCRIPTORS -> { + classData.checkExistence(ATT_LoadableDescriptors, scanner.pos); + scanner.scan(); + parseUtf8List(list -> classData.addLoadableDescriptors(list)); + } + case ENCLOSINGMETHOD -> { + classData.checkExistence(ATT_EnclosingMethod, scanner.pos); + scanner.scan(); + parseEnclosingMethod(); + } + default -> { + environment.error(scanner.pos, "err.field.expected"); + throw new SyntaxError().setFatal(); + } + } // end switch + } catch (SyntaxError e) { + if (!e.isFatal()) { + recoverField(); + } else { + throw new SyntaxError().setFatal(); + } + } + traceMethodInfoLn("End"); + memberAnnotations = null; + } + + /** + * Recover after a syntax error in the file. + * This involves discarding scanner.tokens until an EOF + * or a possible legal continuation is encountered. + */ + private void recoverFile() throws IOException { + while (true) { + environment.traceln(() -> "recoverFile: scanner.token=" + scanner.token); + switch (scanner.token) { + case CLASS: + case INTERFACE: + // Start of a new source file statement, continue + return; + + case LBRACE: + match(LBRACE, RBRACE); + scanner.scan(); + break; + + case LPAREN: + match(LPAREN, RPAREN); + scanner.scan(); + break; + + case LSQBRACKET: + match(LSQBRACKET, RSQBRACKET); + scanner.scan(); + break; + + case EOF: + return; + + default: + // Don't know what to do, skip + scanner.scan(); + break; + } + } + } + + /** + * End class + */ + private void endClass() { + if (explicitCP) { + // Fix references in the constant pool (for explicitly coded CPs) + // TODO Synthetic in package info + pool.fixRefsInPool(); + // Fix any bootstrap Method references too + classData.relinkBootstrapMethods(); + + // Fix Source file if it isn't defined. + if (classData.sourceFileAttr == null) { + String sourceFileName = environment.getSimpleInputFileName(); + String sourceName = environment.getSourceName(); + classData.sourceFileAttr = new SourceFileAttr(this.classData.pool, sourceFileName). + updateIfFound(this.classData.pool, + name -> name.contains(sourceName) && + StringUtils.contains.apply(name, List.of(".java", ".jcod", ".jasm", ".class")) + ); + } + } else { + // Fix Source file if it isn't defined. + if (classData.sourceFileAttr == null) { + classData.sourceFileAttr = new CPXAttr(pool, + EAttribute.ATT_SourceFile, + pool.findUTF8Cell(environment.getSimpleInputFileName())); + } + } + classData.endClass(); + clsDataList.add(classData); + initializeClassData(); + } + + /** + * End package-info + */ + private void endPackageInfo() { + if (explicitCP) { + // Fix references in the constant pool (for explicitly coded CPs) + pool.fixRefsInPool(); + // Fix Source file if it isn't defined. + if (classData.sourceFileAttr == null) { + String sourceName = environment.getSimpleInputFileName(); + classData.sourceFileAttr = new SourceFileAttr(this.classData.pool, sourceName). + updateIfFound(this.classData.pool, name -> name.contains("package-info.")); + } + } else { + // Fix Source file if it isn't defined. + if (classData.sourceFileAttr == null) { + classData.sourceFileAttr = new CPXAttr(pool, + EAttribute.ATT_SourceFile, + pool.findUTF8Cell(environment.getSimpleInputFileName())); + } + } + classData.endPackageInfo(); + clsDataList.add(classData); + classData = null; + } + + /** + * End module + */ + private void endModule() { + if (explicitCP) { + // Fix references in the constant pool (for explicitly coded CPs) + pool.fixRefsInPool(); + // Fix Source file if it isn't defined. + if (classData.sourceFileAttr == null) { + String sourceName = environment.getSimpleInputFileName(); + classData.sourceFileAttr = new SourceFileAttr(this.classData.pool, sourceName). + updateIfFound(this.classData.pool, name -> name.contains("module-info.")); + } + } else { + // Fix Source file if it isn't defined. + if (classData.sourceFileAttr == null) { + classData.sourceFileAttr = new CPXAttr(pool, + EAttribute.ATT_SourceFile, + pool.findUTF8Cell(environment.getSimpleInputFileName())); + } + } + classData.endModule(moduleAttribute); + clsDataList.add(classData); + classData = null; + } + + final ClassData[] getClassesData() { + return clsDataList.toArray(new ClassData[0]); + } + + /** + * Determines whether the JASM file is for a package-info class + * or for a module-info class. + *

+ * creates the correct kind of ClassData accordingly. + * + * @throws IOException if any parse exception is met + */ + private void parseJasmPackages() throws IOException { + if (scanner.token.in(CONST, ANNOTATION, PACKAGE)) { + boolean scanNext = true; + try { + while ((scanner.token != EOF) && scanNext) { + switch (scanner.token) { + case CONST: + // Parse constant declarations + scanner.scan(); + parseConstDef(); + explicitCP = true; + break; + case SEMICOLON: + // Empty fields are allowed + scanner.scan(); + break; + case ANNOTATION: + packageAnnotations = annotParser.parseAnnotations(); + break; + case PACKAGE: + // Package statement + scanner.scan(); + long where = scanner.pos; + String id = parseIdent(); + if (scanner.token != SEMICOLON) { + parseVersion(); + scanner.expect(SEMICOLON); + } + if (pkg == null) { + pkg = id; + pkgPrefix = id + "/"; + } else { + environment.error(where, "err.package.repeated"); + } + traceMethodInfoLn("{PARSED} package-prefix: \"" + pkgPrefix + "\""); + default: + scanNext = false; + } // end switch + } // while + } catch (SyntaxError e) { + recoverFile(); + } + + // skip bogus semi colons + while (scanner.token == SEMICOLON) { + scanner.scan(); + } + + // checks that we compile module or package compilation unit + if (scanner.token == EOF) { + environment.traceln("Scanner: EOF"); + String sourceName = environment.getSimpleInputFileName(); + // package-info + if (sourceName.contains("package-info")) { + environment.traceln(() -> "Creating \"package-info.jasm\": package: " + pkg + " " + classData.cfv.asString()); + // Interface package-info should be marked ACC_INTERFACE and ACC_ABSTRACT flags + int mod = ACC_INTERFACE.getFlag() | ACC_ABSTRACT.getFlag(); + // If the class file version number is less than 50.0, then the ACC_SYNTHETIC flag is unset; + // if the class file version number is 50.0 or above, then the ACC_SYNTHETIC flag is set. + if (classData.cfv.major_version() > 49) { + mod |= SYNTHETIC_ATTRIBUTE.getFlag(); + } + classData.initAsPackageInfo(mod, pkgPrefix + "package-info"); + if (packageAnnotations != null) { + classData.addAnnotations(packageAnnotations); + } + endPackageInfo(); + } + return; + } + if (pkg == null && packageAnnotations != null) { // RemoveModules + classAnnotations = packageAnnotations; + packageAnnotations = null; + } + } + } + + /** + * Parse an Jasm file. + * 1. File FILENAME or class file CLASSNAME takes the highest priority. This filename cannot be overridden. + * 2. Public class CLASSNAME { }– class name is CLASSNAME, and this CLASSNAME will be used to generate the filename (i.e., CLASSNAME.class). + * 3. this_class – The filename will be CLASSNAME.class, but the class name will be this_class. + */ + void parseFile() { + try { + initializeClassData(); + // First parse the first line + // file FILENAME || classfile CLASSNAME + String destinationFileName = parseResultingFile(); + if (destinationFileName != null) { + if (environment.getToolOutput() instanceof NamedToolOutput namedToolOutput) { + namedToolOutput.setDestinationFileName(destinationFileName); + } + } + + // parse any package identifiers (and associated package annotations) + parseJasmPackages(); + + while (scanner.token != EOF) { + // Second, parse any class identifiers (and associated class annotations) + try { + // Parse annotations + if (scanner.token == ANNOTATION) { + classAnnotations = annotParser.parseAnnotations(); + } + + // Parse class modifiers + int mod = scanModifiers(); + if (mod == 0) { + switch (scanner.token) { + case OPEN: + case MODULE: + case CLASS: + case INTERFACE: + case CPINDEX: + case STRINGVAL: + case IDENT: + // this is a class declaration anyway + break; + case SEMICOLON: + // Bogus semi colon + scanner.scan(); + continue; + default: + // no class declaration found + environment.error(scanner.pos, "err.toplevel.expected"); + throw new SyntaxError(); + } + } else if (EModifier.isInterface(mod) && (scanner.token != CLASS)) { + // rare syntactic sugar: + // interface == abstract interface class + mod |= ACC_ABSTRACT.getFlag(); + } + if (scanner.token == MODULE || scanner.token == OPEN) + parseModule(mod); + else + parseClass(mod); + classAnnotations = null; + + } catch (SyntaxError e) { + environment.traceln("^^^^^^^ Syntax Error ^^^^^^^^^^^^"); + if (scanner.environment.getVerboseFlag()) + e.printStackTrace(); + if (!e.isFatal()) { + recoverFile(); + } + break; + } + } + } catch (IOException e) { + environment.error(scanner.pos, "io.exception", environment.getSimpleInputFileName()); + } catch (Error er) { + er.printStackTrace(); + } + } //end parseFile + + + /** + * The source text file can be free form (newlines are considered blanks) and may contain Java-style commenting. + * The first line of a JASM file represents the name of the resulting file in the destination directory. + * This name does not affect the content of the resulting file. This line has two forms: + * file FILENAME; + * or + * classfile CLASSNAME; + * In the latter case, extension .class will be added to form FILENAME. + */ + private String parseResultingFile() throws IOException { + boolean addExtension = false; + String name = null; + if (scanner.token.in(FILE, CLASS_FILE)) { + while ((scanner.token != EOF)) { + switch (scanner.token) { + case FILE -> { + if (name != null) { + environment.throwErrorException(scanner.pos, "err.token.expected", SEMICOLON.parseKey()); + } + } + case CLASS_FILE -> { + if (name != null) { + environment.throwErrorException(scanner.pos, "err.token.expected", SEMICOLON.printValue()); + } + addExtension = true; + } + case IDENT, CLASS -> { + name = name == null ? scanner.stringValue : name + scanner.stringValue; + } + case FIELD -> { // "." is recognized as FIELD token + name = name == null ? "." : name + "."; + } + case SEMICOLON -> { + if (name == null) { + environment.throwErrorException(scanner.pos, "err.token.expected", + addExtension ? "CLASSNAME" : "FILENAME"); + } + scanner.scan(); + return name.concat(addExtension ? ".class" : ""); + } + default -> { + if (name == null) { + environment.throwErrorException(scanner.pos, "err.token.expected", + addExtension ? "CLASSNAME" : "FILENAME"); + } else { + environment.throwErrorException(scanner.pos, "err.token.expected", SEMICOLON.printValue()); + } + } + } // end switch + scanner.scan(); + } // while + } + return name; + } + + private void initializeClassData() { + // parser environment and copy of the parser cfv. + classData = new ClassData(this.environment, copyOf(this.currentCFV)); + pool = classData.pool; + } + + @FunctionalInterface + interface NameSupplier { + NameInfo get() throws IOException; + } + + @FunctionalInterface + interface Method { + void call() throws IOException; + } + + /** + * The main compile error for the parser + */ + static class CompilerError extends Error { + CompilerError(String message) { + super(message); + } + } +} //end Parser diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/PermittedSubclassesAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/PermittedSubclassesAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/PermittedSubclassesAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/PermittedSubclassesAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.util.List; + +/** + * The "classes[]" data of attributes + * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubclasses_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + */ +public class PermittedSubclassesAttr extends ArrayAttr { + public PermittedSubclassesAttr(ConstantPool pool, List classes) { + super(pool, EAttribute.ATT_PermittedSubclasses, classes); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/RecordData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/RecordData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/RecordData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/RecordData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.ELocation; +import org.openjdk.asmtools.common.structure.EModifier; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.openjdk.asmtools.common.structure.EModifier.*; + +/** + * The record attribute (JEP 359 since class file 58.65535) + */ +public class RecordData extends AttrData { + private ClassData classData; + private List components = new ArrayList<>(); + + /** + * @param classData callback reference to class data to manipulate signature attribute + */ + public RecordData(ClassData classData) { + super(classData.pool, EAttribute.ATT_Record); + this.classData = classData; + } + + public void addComponent(ConstCell nameCell, + ConstCell descCell, + ConstCell signature, + ArrayList annotations) { + // Define a field if absent + FieldData fd = classData.addFieldIfAbsent(EModifier.getFlags(ACC_MANDATED, ACC_PRIVATE, ACC_FINAL), nameCell, descCell); + ComponentData cd = new ComponentData(classData, fd); + if( annotations != null ) { + cd.addAnnotations(annotations); + } + if( signature != null ) { + cd.setSignatureAttr(signature); + } + components.add(cd); + } + + public boolean isEmpty() { + return components.isEmpty(); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeShort(components.size()); + for (ComponentData cd : components) { + cd.write(out); + } + } + + @Override + public int attrLength() { + int compsLength = components.stream().mapToInt(c -> c.getLength()).sum(); + return 2 + compsLength; + } + + class ComponentData extends MemberData { + private ClassData classData; + private FieldData field; + + public ComponentData(ClassData classData, FieldData field) { + super(classData.pool, classData.getEnvironment()); + this.attributeLocation = ELocation.record_component_info; + this.classData = classData; + this.field = field; + } + + @Override + protected DataVector getAttrVector() { + return classData.getDataVector(signatureAttr); + } + + public void write(CheckedDataOutputStream out) throws IOException, Parser.CompilerError { + out.writeShort(field.getNameDesc().value.first.cpIndex); + out.writeShort(field.getNameDesc().value.second.cpIndex); + DataVector attrs = getAttrVector(); + attrs.write(out); + } + + public int getLength() { + return 4 + getAttrVector().getLength(); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Scanner.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Scanner.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Scanner.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/Scanner.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,962 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.asmutils.StringUtils; +import org.openjdk.asmtools.common.SyntaxError; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static org.openjdk.asmtools.common.CompilerConstants.EOF; +import static org.openjdk.asmtools.jasm.JasmTokens.Token; +import static org.openjdk.asmtools.jasm.JasmTokens.keyword_token_ident; + +/** + * A Scanner for Jasm tokens. Errors are reported to the environment object.

+ *

+ * The scanner keeps track of the current token, the value of the current token (if any), + * and the start position of the current token.

+ *

+ * The scan() method advances the scanner to the next token in the input.

+ *

+ * The match() method is used to quickly match opening brackets (ie: '(', '{', or '[') + * with their closing counterpart. This is useful during error recovery.

+ *

+ * The compiler treats either "\n", "\r" or "\r\n" as the end of a line.

+ */ +public class Scanner extends ParseBase { + + // The current character + protected int ch; + + // Current token + protected Token token; + + // The position of the current token + protected long pos; + + // Token values. + protected int intValue; + protected long longValue; + protected float floatValue; + protected double doubleValue; + protected String stringValue; + protected String idValue; + protected int radix; // Radix, when reading int or long + + /* doc comment preceding the most recent token */ + protected String docComment; + /** + * The position of the previous token + */ + protected long prevPos; + protected int sign; // sign, when reading number + protected boolean inBits; // inBits prefix, when reading number + + /* A growable character buffer. */ + private int count; + private char[] buffer = new char[32]; + // + private Predicate escapingAllowed; + private final Predicate noFunc = (ch) -> false; + private final Predicate yesAndProcessFunc = (ch) -> { + boolean res = ((ch == '\\') || (ch == ':') || (ch == '@')); + if (res) + putCh('\\'); + return res; + }; + + /** + * main constructor. + *

+ * Create a scanner to scan an input stream. + */ + protected Scanner(JasmEnvironment environment) { + super.init(environment); + escapingAllowed = noFunc; + ch = environment.read(); + xscan(); + } + + protected void scanModuleStatement() { + try { + escapingAllowed = yesAndProcessFunc; + scan(); + } finally { + escapingAllowed = noFunc; + } + } + + /** + * Scan the next token. + */ + protected void scan() { + int signloc = 1; + prevPos = pos; + prefix: + for (; ; ) { + xscan(); + switch (token) { + case SIGN: + signloc = signloc * intValue; + break; + default: + break prefix; + } + } + switch (token) { + case INTVAL, LONGVAL, FLOATVAL, DOUBLEVAL, INF, NAN -> sign = signloc; + default -> { + } + } + } + + /** + * Check the token may be identifier + */ + protected final boolean checkTokenIdent() { + return token.isPossibleJasmIdentifier(); + } + + /** + * Expects the token, scans the next token or throws an exception. + */ + protected final void expect(Token t) throws SyntaxError { + check(t); + scan(); + } + + /** + * Expects an identifier token with parsed content of the token, + * scans the next token or throws an exception. + */ + protected final void expectIdentContent(Token t) throws SyntaxError { + if (token != Token.IDENT || !stringValue.equals(t.parseKey())) { + environment.throwErrorException(pos, "err.token.expected", "\"" + t.parseKey() + "\""); + } + scan(); + } + + protected final void expectOneOf(List identifiers, Token... tokens) throws SyntaxError { + boolean foundTokens = expectOneOfToken(tokens), + foundIdents = expectOneOfIdent(identifiers.toArray(new String[0])); + + if (!foundTokens && !foundIdents) { + String list = identifiers.stream().map("\"%s\""::formatted). + collect(Collectors.joining(",")); + list = "[ %s,%s ]".formatted(list, Arrays.stream(tokens). + map(t -> "\"%s\"".formatted(t.parseKey())). + collect(Collectors.joining(","))); + environment.error(pos, "err.one.of.N.token.expected", list); + } + } + + /** + * Expects one of the token in the list, scans the next token or throws an exception. + */ + protected final boolean expectOneOfToken(Token... tokens) throws SyntaxError { + for (Token t : tokens) { + if (token == t) { + return true; + } + } + return false; + } + + /** + * Expects one of Identifier in the list, scans the next token or throws an exception. + */ + protected final boolean expectOneOfIdent(String... identifiers) throws SyntaxError { + if (token == Token.IDENT) { + for (String ident : identifiers) { + if (stringValue.equals(ident)) { + return true; + } + } + } + return false; + } + + /** + * Checks the token, throws an exception if different + */ + protected final void check(Token t) throws SyntaxError { + if (token != t) { + if ((t != Token.IDENT) || !checkTokenIdent()) { + environment.traceln("expect: " + t + " instead of " + token); + if (t == Token.IDENT) { + environment.error(pos, "err.identifier.expected"); + } else { + environment.error(pos, "err.token.expected", "<" + t.parseKey() + ">"); + } + } + } + } + + private void putCh(int ch) { + if (count == buffer.length) { + char[] newBuffer = new char[buffer.length * 2]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[count++] = (char) ch; + } + + private String bufferString() { + char[] buf = new char[count]; + System.arraycopy(buffer, 0, buf, 0, count); + return new String(buf); + } + + /** + * Scan a comment. This method should be called once the initial /, * and the next + * character have been read. + */ + private void skipComment() { + while (true) { + switch (ch) { + case EOF: + environment.error(pos, "err.eof.in.comment"); + return; + case '*': + if ((ch = environment.read()) == '/') { + ch = environment.read(); + return; + } + break; + default: + ch = environment.read(); + break; + } + } + } + + /** + * Scan a doc comment. This method should be called once the initial /, * and * have + * been read. It gathers the content of the comment (without leading spaces and '*'s) + * in the string buffer. + */ + @SuppressWarnings("empty-statement") + private String scanDocComment() { + count = 0; + + if (ch == '*') { + do { + ch = environment.read(); + } while (ch == '*'); + if (ch == '/') { + ch = environment.read(); + return ""; + } + } + switch (ch) { + case '\n', ' ' -> ch = environment.read(); + } + + boolean seenstar = false; + int c = count; + while (true) { + switch (ch) { + case EOF: + environment.error(pos, "err.eof.in.comment"); + return bufferString(); + case '\n': + putCh('\n'); + ch = environment.read(); + seenstar = false; + c = count; + break; + case ' ': + case '\t': + putCh(ch); + ch = environment.read(); + break; + case '*': + if (seenstar) { + if ((ch = environment.read()) == '/') { + ch = environment.read(); + count = c; + return bufferString(); + } + putCh('*'); + } else { + seenstar = true; + count = c; + while ((ch = environment.read()) == '*') ; + switch (ch) { + case ' ' -> ch = environment.read(); + case '/' -> { + ch = environment.read(); + count = c; + return bufferString(); + } + } + } + break; + default: + if (!seenstar) { + seenstar = true; + } + putCh(ch); + ch = environment.read(); + c = count; + break; + } + } + } + + /** + * Scan a decimal at this point + */ + private void scanCPRef() { + int prevCh = ch; + switch (ch = environment.read()) { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { + boolean overflow = false; + long value = ch - '0'; + count = 0; + putCh(ch); // save character in buffer + numberLoop: + for (; ; ) { + switch (ch = environment.read()) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + putCh(ch); + if (overflow) { + break; + } + value = (value * 10) + (ch - '0'); + overflow = (value > 0xFFFF); + break; + default: + break numberLoop; + } + } // while true + intValue = (int) value; + stringValue = bufferString(); + token = Token.CPINDEX; + if (overflow) { + environment.error(pos, "err.overflow"); + } + } + default -> { + stringValue = Character.toString((char) prevCh); + environment.throwErrorException(environment.getPosition(), "err.invalid.number", stringValue); + intValue = 0; + token = Token.CPINDEX; + ch = environment.read(); + } + } + } // scanCPRef() + + /** + * Scan a number. The first digit of the number should be the current character. We + * may be scanning hex, decimal, or octal at this point + */ + private void scanNumber() { + boolean seenNonOctal = false; + boolean overflow = false; + radix = (ch == '0' ? 8 : 10); + long value = ch - '0'; + count = 0; + putCh(ch); // save character in buffer + numberLoop: + for (; ; ) { + switch (ch = environment.read()) { + case '.': + if (radix == 16) { + break numberLoop; // an illegal character + } + scanReal(); + return; + + case '8': + case '9': + // We can't yet throw an error if reading an octal. We might + // discover we're really reading a real. + seenNonOctal = true; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + putCh(ch); + if (radix == 10) { + overflow = overflow || (value * 10) / 10 != value; + value = (value * 10) + (ch - '0'); + overflow = overflow || (value - 1 < -1); + } else if (radix == 8) { + overflow = overflow || (value >>> 61) != 0; + value = (value << 3) + (ch - '0'); + } else { + overflow = overflow || (value >>> 60) != 0; + value = (value << 4) + (ch - '0'); + } + break; + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + if (radix != 16) { + scanReal(); + return; + } + // fall through + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + putCh(ch); + if (radix != 16) { + break numberLoop; // an illegal character + } + overflow = overflow || (value >>> 60) != 0; + value = (value << 4) + 10 + + Character.toLowerCase((char) ch) - 'a'; + break; + case 'l': + case 'L': + ch = environment.read(); // skip over 'l' + longValue = value; + token = Token.LONGVAL; + break numberLoop; + case 'x': + case 'X': + // if the first character is a '0' and this is the second + // letter, then read in a hexadecimal number. Otherwise, error. + if (count == 1 && radix == 8) { + radix = 16; + break; + } else { + // we'll get an illegal character error + break numberLoop; + } + default: + intValue = (int) value; + token = Token.INTVAL; + break numberLoop; + } + } // while true + // we have just finished reading the number. The next thing better + // not be a letter or digit. + if (Character.isLetterOrDigit(ch) || ch == '.') { + environment.error(environment.getPosition(), "err.invalid.number", Character.toString((char) ch)); + do { + ch = environment.read(); + } while (Character.isLetterOrDigit(ch) || ch == '.'); + intValue = 0; + token = Token.INTVAL; + } else if (radix == 8 && seenNonOctal) { + intValue = 0; + token = Token.INTVAL; + environment.error(environment.getPosition(), "err.invalid.octal.number"); + } else if (overflow + || (token == Token.INTVAL + && ((radix == 10) ? (intValue - 1 < -1) + : ((value & 0xFFFFFFFF00000000L) != 0)))) { + intValue = 0; // so we don't get second overflow in Parser + longValue = 0; + environment.error(pos, "err.overflow"); + } + } // scanNumber() + + /** + * Scan a float. We are either looking at the decimal, or we have already seen it and + * put it into the buffer. We haven't seen an exponent. Scan a float. Should be called + * with the current character is either the 'e', 'E' or '.' + */ + private void scanReal() { + boolean seenExponent = false; + boolean isSingleFloat = false; + char lastChar; + if (ch == '.') { + putCh(ch); + ch = environment.read(); + } + + numberLoop: + for (; ; ch = environment.read()) { + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + putCh(ch); + break; + case 'e': + case 'E': + if (seenExponent) { + break numberLoop; // we'll get a format error + } + putCh(ch); + seenExponent = true; + break; + case '+': + case '-': + lastChar = buffer[count - 1]; + if (lastChar != 'e' && lastChar != 'E') { + break numberLoop; // this isn't an error, though! + } + putCh(ch); + break; + case 'f': + case 'F': + ch = environment.read(); // skip over 'f' + isSingleFloat = true; + break numberLoop; + case 'd': + case 'D': + ch = environment.read(); // skip over 'd' + // fall through + default: + break numberLoop; + } // sswitch + } // loop + + // we have just finished reading the number. The next thing better + // not be a letter or digit. + if (Character.isLetterOrDigit(ch) || ch == '.') { + environment.error(environment.getPosition(), "err.invalid.number", Character.toString((char) ch)); + do { + ch = environment.read(); + } while (Character.isLetterOrDigit(ch) || ch == '.'); + doubleValue = 0; + token = Token.DOUBLEVAL; + } else { + token = isSingleFloat ? Token.FLOATVAL : Token.DOUBLEVAL; + try { + lastChar = buffer[count - 1]; + if (lastChar == 'e' || lastChar == 'E' + || lastChar == '+' || lastChar == '-') { + environment.error(environment.getPosition() - 1, "err.float.format"); + } else if (isSingleFloat) { + floatValue = Float.parseFloat(bufferString()); + if (Float.isInfinite(floatValue)) { + environment.error(pos, "err.overflow"); + } + } else { + doubleValue = Double.parseDouble(bufferString()); + if (Double.isInfinite(doubleValue)) { + environment.error(pos, "err.overflow"); + environment.error(pos, "err.overflow"); + } + } + } catch (NumberFormatException ee) { + environment.error(pos, "err.float.format"); + doubleValue = 0; + floatValue = 0; + } + } + } // scanReal + + /** + * Scan an escape character. + * + * @return the character or '\\' + */ + private long scanEscapeChar() { + long p = environment.getPosition(); + + switch (ch = environment.read()) { + case '0', '1', '2', '3', '4', '5', '6', '7' -> { + int n = ch - '0'; + for (int i = 2; i > 0; i--) { + switch (ch = environment.read()) { + case '0', '1', '2', '3', '4', '5', '6', '7' -> n = (n << 3) + ch - '0'; + default -> { + if (n > 0xFF) { + environment.error(p, "err.invalid.escape.char"); + } + return n; + } + } + } + ch = environment.read(); + if (n > 0xFF) { + environment.error(p, "err.invalid.escape.char"); + } + return n; + } + case 'r' -> { + ch = environment.read(); + return '\r'; + } + case 'n' -> { + ch = environment.read(); + return '\n'; + } + case 'f' -> { + ch = environment.read(); + return '\f'; + } + case 'b' -> { + ch = environment.read(); + return '\b'; + } + case 't' -> { + ch = environment.read(); + return '\t'; + } + case '\\' -> { + ch = environment.read(); + return '\\'; + } + case '\"' -> { + ch = environment.read(); + return '\"'; + } + case '\'' -> { + ch = environment.read(); + return '\''; + } + case 'u' -> { + int unich = environment.convertUnicode(); + ch = environment.read(); + return unich; + } + } + return '\\'; + } + + /** + * Scan a string. The current character should be the opening " of the string. + */ + private void scanString() { + token = Token.STRINGVAL; + count = 0; + ch = environment.read(); + + // Scan a String + while (true) { + switch (ch) { + case EOF -> { + environment.error(pos, "err.eof.in.string"); + stringValue = bufferString(); + return; + } + case '\n' -> { + ch = environment.read(); + environment.error(pos, "err.newline.in.string"); + stringValue = bufferString(); + return; + } + case '"' -> { + ch = environment.read(); + stringValue = bufferString(); + return; + } + case '\\' -> { + long c = scanEscapeChar(); + if (c >= 0) { + putCh((char) c); + } + } + default -> { + putCh(ch); + ch = environment.read(); + } + } + } + } + + /** + * Scan an Identifier. The current character should be the first character of the + * identifier. + */ + private void scanIdentifier(char[] prefix) { + int firstChar; + count = 0; + if (prefix != null) { + for (; ; ) { + for (char c : prefix) putCh(c); + ch = environment.read(); + if (ch == '\\') { + ch = environment.read(); + if (ch == 'u') { + ch = environment.convertUnicode(); + if (!Character.isLetterOrDigit(ch)) { + prefix = new char[]{(char) ch}; + continue; + } + } else if (escapingAllowed.test(ch)) { + prefix = new char[]{(char) ch}; + continue; + } + long p = environment.getPosition(); + environment.error(p, "err.invalid.escape.char"); + } + break; + } + } + firstChar = ch; + boolean firstIteration = true; + scanloop: + while (true) { + putCh(ch); + ch = environment.read(); + + // Check to see if the annotation marker is at + // the front of the identifier. + if (firstIteration && firstChar == '@') { + // Maybe a type annotation + if (ch == 'T') { // type annotation + putCh(ch); + ch = environment.read(); + } + + // is either a runtime visible or invisible annotation + if (ch == '+' || ch == '-') { // regular annotation + // possible annotation - + // need to eat up the '@+' or '@-' + putCh(ch); + ch = environment.read(); + } + idValue = bufferString(); + stringValue = idValue; + token = Token.ANNOTATION; + return; + } + firstIteration = false; + if (!Character.isJavaIdentifierPart(ch) && !StringUtils.isOneOf(ch, '-', '[', ']', '(', ')', '<', '>')) { + switch (ch) { + case '/': {// may be comment right after identifier + int c = environment.lookForward(); + if ((c == '*') || (c == '/')) { + break scanloop; // yes, comment + } + break; // no, continue to parse identifier + } + case '\\': + ch = environment.read(); + if (ch == 'u') { + ch = environment.convertUnicode(); + if (!Character.isLetterOrDigit(ch)) { + break; + } + } else if (escapingAllowed.test(ch)) { + break; + } + long p = environment.getPosition(); + environment.error(p, "err.invalid.escape.char"); + default: + break scanloop; + } // end switch + } + } // end scanloop + idValue = bufferString(); + stringValue = idValue; + token = keyword_token_ident(idValue); + traceMethodInfoLn("token = %s value = '%s'".formatted(token, idValue)); + } // end scanIdentifier + + //============================== + @SuppressWarnings("empty-statement") + protected final void xscan() { // throws IOException { + docComment = null; + loop: + for (; ; ) { + pos = environment.getPosition(); + if (Character.isLetter(ch) || StringUtils.isOneOf(ch, '$', '_', '@', '[', ']', '(', ')', '<', '>')) { + scanIdentifier(null); + break; + } else if (ch == EOF) { + token = Token.EOF; + break; + } else if (ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t' || ch == '\f') { + ch = environment.read(); + } else if (ch == '/') { + switch (ch = environment.read()) { + case '/': + // Parse a // comment + while (((ch = environment.read()) != EOF) && (ch != '\n')) ; + break; + case '*': + ch = environment.read(); + if (ch == '*') { + docComment = scanDocComment(); + } else { + skipComment(); + } + break; + default: + token = Token.DIV; + break loop; + } + } else if (ch == '"') { + scanString(); + break; + } else if (ch == '-') { + intValue = -1; + token = Token.SIGN; + ch = environment.read(); + break; + } else if (ch == '+') { + intValue = 1; + ch = environment.read(); + token = Token.SIGN; + break; + } else if (ch == '0' || ch == '1' || ch == '2' || ch == '3' || ch == '4' || ch == '5' || + ch == '6' || ch == '7' || ch == '8' || ch == '9') { + scanNumber(); + break; + } else if (ch == '.') { + switch (ch = environment.read()) { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { + count = 0; + putCh('.'); + scanReal(); + } + default -> token = Token.FIELD; + } + break; + } else if (ch == '{') { + ch = environment.read(); + token = Token.LBRACE; + break; + } else if (ch == '}') { + ch = environment.read(); + token = Token.RBRACE; + break; + } else if (ch == ',') { + ch = environment.read(); + token = Token.COMMA; + break; + } else if (ch == ';') { + ch = environment.read(); + token = Token.SEMICOLON; + break; + } else if (ch == ':') { + ch = environment.read(); + token = Token.COLON; + break; + } else if (ch == '=') { + if ((ch = environment.read()) == '=') { + ch = environment.read(); + token = Token.EQ; + break; + } + token = Token.ASSIGN; + break; + } else if (ch == '\u001a') {// Our one concession to DOS. + if ((ch = environment.read()) == EOF) { + token = Token.EOF; + break; + } + environment.warning(prevPos, "warn.funny.char", ch); + ch = environment.read(); + } else if (ch == '#') { + int c = environment.lookForward(); + if (c == '{') { + // '#' char denotes a "paramMethod name" token + ch = environment.read(); + token = Token.PARAM_NAME; + break loop; + } + // otherwise, it is a normal cpref + scanCPRef(); + break loop; + } else if (ch == '\\') { + ch = environment.read(); + if (ch == 'u') { + ch = environment.convertUnicode(); + if (Character.isLetterOrDigit(ch) && !Character.isDigit(ch)) { + scanIdentifier(null); + break; + } + } else if (escapingAllowed.test(ch)) { + scanIdentifier(new char[]{'\\', (char) ch}); + break; + } +// if ((ch = in.read()) == 'u') { +// ch = in.convertUnicode(); +// if (isUCLetter(ch)) { +// scanIdentifier(); +// break loop; +// } +// } + long ln = environment.lineNumber(pos); + long lineOffset = environment.lineOffset(ln, pos); + environment.traceln(() -> "Funny char with code='%c' at %d:%d".formatted(ch, ln, lineOffset)); + environment.warning(pos, "warn.funny.char", ch); + ch = environment.read(); + } else { + long ln = environment.lineNumber(pos); + long lineOffset = environment.lineOffset(ln, pos); + environment.traceln(() -> "Funny char with code='%c' at %d:%d".formatted(ch, ln, lineOffset)); + environment.warning(pos, "warn.funny.char", ch); + ch = environment.read(); + } + } + } + + protected void debugScan(String debStr) { + if (environment.isTraceFlag()) { + if (token == null) { + environment.traceln(debStr.concat("<<>>")); + return; + } + environment.trace(debStr.concat(token.toString())); + switch (token) { + case IDENT -> environment.traceln(" = '" + stringValue + "' {idValue = '" + idValue + "'}"); + case STRINGVAL -> environment.traceln(" = {stringValue}: \"" + stringValue + "\""); + case INTVAL -> environment.traceln(" = {intValue}: " + intValue); + case FLOATVAL -> environment.traceln(" = {floatValue}: " + floatValue); + case DOUBLEVAL -> environment.traceln(" = {doubleValue}: " + doubleValue); + default -> environment.traceln(""); + } + } + } + + protected void debugScan(long position, String debStr) { + if (environment.isTraceFlag()) { + long lineNumber = environment.lineNumber(position); + long linePos = environment.lineOffset(lineNumber, position); + debugScan("[%4d,%-2d] ".formatted(lineNumber,linePos).concat(debStr)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceDebugExtensionAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceDebugExtensionAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceDebugExtensionAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceDebugExtensionAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.openjdk.asmtools.asmutils.HexUtils.toByteArray; + +/** + * SourceDebugExtension_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u1 debug_extension[attribute_length]; + * The debug_extension array holds extended debugging information which has no semantic effect on the JVM. + * The information is represented using a modified UTF-8 string (§4.4.7) with no terminating zero byte. + * } + */ +public class SourceDebugExtensionAttr extends AttrData { + + StringBuilder utf8DebugExtension = new StringBuilder(); + List byteDebugExtension = new ArrayList<>(); + + // Defines type of the attribute either it is presented as UTF8 string or Byte array. + public enum Type { + NONE, UTF8, BYTE; + } + + // by default the type isn't defined. First append operation will define the type. + Type type = Type.NONE; + + SourceDebugExtensionAttr(ConstantPool pool) { + super(pool, EAttribute.ATT_SourceDebugExtension); + } + + public boolean isEmpty() { + return switch (type) { + case UTF8 -> utf8DebugExtension.isEmpty(); + case BYTE -> byteDebugExtension.isEmpty(); + case NONE -> true; // not initialized + }; + } + + public void append(String str) throws IllegalArgumentException { + if (type == Type.BYTE) + throw new IllegalArgumentException("The valid modified UTF-8 string is expected."); + utf8DebugExtension.append(str); + type = Type.UTF8; + } + + public void append(int value) { + if (type == Type.UTF8) + throw new IllegalArgumentException("The byte representation of the string is expected."); + byteDebugExtension.add((byte) value); + type = Type.BYTE; + } + + public int attrLength() { + // 4.4.7. The CONSTANT_Utf8_info Structure + // u2 length; + (u1 bytes[length]).length(); + return switch (type) { + case UTF8 -> utf8DebugExtension.toString().getBytes(UTF_8).length; + case BYTE -> byteDebugExtension.size(); + case NONE -> 0; + }; + } + + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); // attr name, attr length + switch (type) { + case UTF8 -> out.writeBytes(utf8DebugExtension.toString()); + case BYTE -> out.write(toByteArray(byteDebugExtension)); + case NONE -> out.write(0); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceFileAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceFileAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceFileAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SourceFileAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; +import java.util.function.Function; + +/** + * SourceFile_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 sourcefile_index; + * } + */ +public class SourceFileAttr extends AttrData { + private String sourceFileName; + private ConstCell sourceFileNameCell = null; + + /** + * Constructs SourceFile Attribute without creating Constant Pool UTF8 SourceFile + * + * @param pool constant pool of parsed class data + * @param sourceFileName a name of a parsed file + */ + public SourceFileAttr(ConstantPool pool, String sourceFileName) { + super(pool, EAttribute.ATT_SourceFile); + this.sourceFileName = sourceFileName; + } + + /** + * Constructs SourceFile Attribute without creating Constant Pool UTF8 SourceFile + * + * @param pool constant pool of parsed class data + * @param sourceFileNameCell ConstantPool UTF8 cell + */ + public SourceFileAttr(ConstantPool pool, ConstCell sourceFileNameCell) { + super(pool, EAttribute.ATT_SourceFile); + this.sourceFileNameCell = sourceFileNameCell; + } + + + /** + * Finds CP UTF cell with string that applies to the rule. + * If such UTF8 string exists then replaces it with a new source file name + * otherwise creates a new UTF8 cell to fill out Source File Attribute + */ + public SourceFileAttr updateIfFound(ConstantPool pool, Function rule) { + sourceFileNameCell = pool.lookupUTF8Cell(rule); + if( sourceFileNameCell != null ) { + sourceFileNameCell.ref.value = sourceFileName; + } else { + sourceFileNameCell = pool.findUTF8Cell(this.sourceFileName); + } + return this; + } + + @Override + public int attrLength() { return 2; } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + if( sourceFileNameCell != null ) { + super.write(out); // attribute name & length + out.writeShort(sourceFileNameCell.cpIndex); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/StackMapData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/StackMapData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/StackMapData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/StackMapData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,427 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + + +import org.openjdk.asmtools.common.structure.StackMap; + +import java.io.IOException; +import java.util.Objects; + +import static org.openjdk.asmtools.common.structure.StackMap.EntryType.*; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; + +/** + * 4.7.4. The StackMapTable Attribute + *

+ * StackMapTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_entries; + * stack_map_entry entries[number_of_entries]; + * } + */ +public class StackMapData implements DataWriter { + static final int UNDEFINED = -1; + final JasmEnvironment environment; + private long scannerPosition = 0; + // Indicates that a method's Code attribute has a StackMapTable attribute (CFV >= 50.0) or has + // StackMap_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 number_of_entries; + // stack_map_entry entries[number_of_entries]; + //} where + // stack_map_entry { + // u2 offset; + // u2 number_of_locals; + // verification_type_info locals[number_of_locals]; + // u2 number_of_stack_items; + // verification_type_info stack[number_of_stack_items]; + //} + final boolean hasStackMapTable; + private int pc = UNDEFINED; + private int offset = UNDEFINED; + private StackMap.EntryType entryType = UNKNOWN_TYPE; + DataVector localsMap, stackMap, unsetFields; + + /** + * In a class file whose version number is 50.0 or above, if a method's Code attribute does not have a StackMapTable attribute, + * it has an implicit stack map attribute (§4.10.1). This implicit stack map attribute is equivalent to a StackMapTable + * attribute with number_of_entries equal to zero. + * + * @param hasStackMapTable false if a method's Code attribute does not have a StackMapTable attribute + */ + StackMapData(JasmEnvironment environment, boolean hasStackMapTable) { + this.environment = environment; + this.hasStackMapTable = hasStackMapTable; + } + + StackMapData setOffset(StackMapData prevFrame) { + offset = (prevFrame == null) ? pc : (pc - prevFrame.pc - 1); + return this; + } + + StackMapData setOffset(int offset) { + this.offset = offset; + return this; + } + + StackMapData setPC(int pc) { + this.pc = pc; + return this; + } + + StackMapData setStackFrameTypeByName(String stackFrameTypeName) { + Objects.requireNonNull(stackFrameTypeName, + () -> this.environment.getLogger().getResourceString("err.obj.is.null", "String stackFrameType")); + this.entryType = StackMap.getEntryTypeByName(stackFrameTypeName); + if (this.entryType == UNKNOWN_TYPE) { + environment.error(scannerPosition, "err.invalid.stack.frame.type", stackFrameTypeName); + } + return this; + } + + /** + * Sets Stack Frame type by number in table presentation: frame_type = 252 + * + * @param stackFrameTypeValue frame type tag + * @return StackMapData object + */ + StackMapData setStackFrameType(int stackFrameTypeValue) { + this.entryType = StackMap.EntryType.getByTag(stackFrameTypeValue); + if (this.entryType == SAME_FRAME) { + this.offset = stackFrameTypeValue; + } else if (this.entryType == SAME_LOCALS_1_STACK_ITEM_FRAME) { + this.offset = stackFrameTypeValue - SAME_LOCALS_1_STACK_ITEM_FRAME.fromTag(); + } + return this; + } + + StackMapData setScannerPosition(long scannerPosition) { + this.scannerPosition = scannerPosition; + return this; + } + + /** + * Checks whether a method's Code attribute has a StackMapTable attribute. + * + * @return true if a method's Code attribute has a StackMapTable attribute. + */ + boolean isFrameTypeSet() { + return hasStackMapTable ? this.entryType != UNKNOWN_TYPE : this.pc != UNDEFINED; + } + + /** + * The early_larval_frame wraps a base_frame. + * As a wrapper, it doesn't supply the offset_delta. + * + * @return true if the StackMapData is a base_frame wrapper. + */ + boolean isWrapper() { + return hasStackMapTable && entryType == EARLY_LARVAL; + } + + @Override + public boolean isCountable() { + return !isWrapper(); + } + /** + * Checks whether all fields corresponding to the current frame type are set. + * + * @return null if all fields are sufficiently valid to be written for the current stack map entry otherwise + * expected token + */ + JasmTokens.Token checkIntegrity() { + switch (entryType) { + case SAME_FRAME -> { // 0-63 + return null; + } + case SAME_LOCALS_1_STACK_ITEM_FRAME -> { // 64 - 127 + return isFull(stackMap) ? null : STACKMAP; + } + case EARLY_LARVAL -> { // 246 + return isFull(unsetFields) ? null : UNSETFIELDS; + } + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED -> { // 247 + if (offset == UNDEFINED) { + return OFFSETDELTA; + } + return isFull(stackMap) ? null : STACKMAP; + } + case CHOP_1_FRAME, CHOP_2_FRAME, CHOP_3_FRAME, // 248-250 + SAME_FRAME_EXTENDED -> { // 251 + return (offset == UNDEFINED) ? OFFSETDELTA : null; + } + case APPEND_FRAME -> { // 252-254 + if (offset == UNDEFINED) { + return OFFSETDELTA; + } + return isFull(localsMap) ? null : LOCALSMAP; + } + case FULL_FRAME -> { // 255 + if (offset == UNDEFINED) { + return OFFSETDELTA; + } + if (!isFull(localsMap)) { + return LOCALSMAP; + } + if (!isFull(stackMap)) { + return STACKMAP; + } + } + } + return null; + } + + private boolean isFull(DataVector... maps) { + for (DataVector map : maps) { + if (map == null) + return false; + } + return true; + } + + @Override + public int getLength() { + int length = (hasStackMapTable) ? 1 : 0; + if (!isFrameTypeSet() || !hasStackMapTable) { + // in the case when either stack_frame_type or frame_type wasn't meet or + // StackMap_attribute instead of StackMapTable_attribute + entryType = FULL_FRAME; + } + switch (entryType) { + case SAME_FRAME: + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME: + length += stackMap.getLength() - 2; + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + length += stackMap.getLength(); + break; + case EARLY_LARVAL: + length += 2 + (unsetFields == null ? 0 : unsetFields.getLength()-2); + break; + case CHOP_1_FRAME: + case CHOP_2_FRAME: + case CHOP_3_FRAME: + case SAME_FRAME_EXTENDED: + length += 2; + break; + case APPEND_FRAME: + length += 2 + (localsMap == null ? 0 : (localsMap.getLength() - 2)); + break; + case FULL_FRAME: + length += 2; + length += (localsMap == null ? 2 : localsMap.getLength()); + length += (stackMap == null ? 2 : stackMap.getLength()); + break; + default: + } + return length; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + if (!hasStackMapTable) { + // Indicates that a method's Code attribute doesn't have a StackMapTable attribute (CFV >= 50.0) + // but has + // StackMap_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 number_of_entries; + // stack_map_entry entries[number_of_entries]; + //} where + // stack_map_entry { + // u2 offset; + // u2 number_of_locals; + // verification_type_info locals[number_of_locals]; + // u2 number_of_stack_items; + // verification_type_info stack[number_of_stack_items]; + //} + entryType = FULL_FRAME; + } + + switch (entryType) { + case EARLY_LARVAL -> { + out.writeByte(entryType.fromTag()); + if (unsetFields == null) { + out.writeShort(0); + } else { + unsetFields.write(out); + } + } + case SAME_FRAME -> { + if (!SAME_FRAME.inRange(offset)) { + environment.error(scannerPosition, "err.invalid.offset.frame.type", offset, entryType.printName()); + break; + } + out.writeByte(offset); + } + case SAME_LOCALS_1_STACK_ITEM_FRAME -> { + if (stackMap == null) { + environment.error(scannerPosition, "err.no.stack.map", entryType.printName()); + break; + } + if (stackMap.elements.size() != 1) { + environment.error(scannerPosition, "err.should.be.only.one.stack.map.element", entryType.printName()); + break; + } + // The offset_delta value for the frame is given by the formula frame_type - 64. + if (offset >= 64) { + environment.error(scannerPosition, "err.invalid.offset.frame.type", offset, entryType.printName()); + break; + } + out.writeByte(entryType.fromTag() + offset); + stackMap.writeElements(out); + } + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED -> { + if (stackMap == null) { + environment.error(scannerPosition, "err.no.locals.map", entryType.printName()); + break; + } + if (stackMap.elements.size() != 1) { + environment.error(scannerPosition, "err.should.be.only.one.stack.map.element", entryType.printName()); + break; + } + out.writeByte(entryType.fromTag()); + out.writeShort(offset); + stackMap.writeElements(out); + } + case CHOP_1_FRAME, CHOP_2_FRAME, CHOP_3_FRAME, SAME_FRAME_EXTENDED -> { + boolean error = false; + if (stackMap != null) { + environment.error(scannerPosition, "err.unexpected.stack.maps", entryType.printName()); + error = true; + } + if (localsMap != null) { + environment.error(scannerPosition, "err.unexpected.locals.maps", entryType.printName()); + error = true; + } + if (error) { + break; + } + out.writeByte(entryType.fromTag()); + out.writeShort(offset); + } + case APPEND_FRAME -> { + if (localsMap == null) { + environment.error(scannerPosition, "err.no.locals.map", entryType.printName()); + break; + } + if (localsMap.elements.size() > 3) { + environment.error(scannerPosition, "err.more.locals.map.elements"); + break; + } + out.writeByte(entryType.fromTag() + localsMap.elements.size() - 1); + out.writeShort(offset); + localsMap.writeElements(out); + } + case FULL_FRAME -> { + if (hasStackMapTable) { + // method's Code attribute has a StackMapTable attribute (CFV >= 50.0) + out.writeByte(entryType.fromTag()); + out.writeShort(offset); + } else { + // method's Code attribute doesn't has a StackMap attribute (CFV < 50.0) + out.writeShort(pc); + } + if (localsMap == null) { + out.writeShort(0); + } else { + localsMap.write(out); + } + if (stackMap == null) { + out.writeShort(0); + } else { + stackMap.write(out); + } + } + default -> environment.error(scannerPosition, "err.stackmap.entry.type.not.set", entryType.fromTag()); + } + } + + public StackMap.EntryType getFrameType() { + return entryType; + } + + /** + * verification_type_info: + * Top_variable_info, Integer_variable_info, Float_variable_info, Null_variable_info, + * UninitializedThis_variable_info, Long_variable_info, Double_variable_info + * Common format: + * *_info { + * u1 tag = ITEM_*; // from 0 to 6 + * } + */ + static public class StackMapItemTagged implements DataWriter { + + StackMap.VerificationType itemVerificationType; + + StackMapItemTagged(StackMap.VerificationType itemVerificationType) { + this.itemVerificationType = itemVerificationType; + } + + @Override + public int getLength() { + return 1; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(itemVerificationType.tag()); + } + } + + /** + * verification_type_info: + * Object_variable_info, Uninitialized_variable_info + * Common Format: + * *_info { + * u1 tag = ITEM_*; // from 7 to 8 + * u2 cpool_index/offset; + * } + */ + static public class StackMapItemTaggedPointer implements DataWriter { + + StackMap.VerificationType itemVerificationType; + // Object_variable_info.cpool_index, ITEM_Uninitialized.offset + Indexer arg; + + StackMapItemTaggedPointer(StackMap.VerificationType itemVerificationType, Indexer arg) { + this.itemVerificationType = itemVerificationType; + this.arg = arg; + } + + @Override + public int getLength() { + return 3; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(itemVerificationType.tag()); + out.writeShort(arg.cpIndex); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SwitchTable.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SwitchTable.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SwitchTable.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/SwitchTable.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + + +import java.io.IOException; +import java.util.ArrayList; + +/** + * tableswitch + * <0-3 byte pad> + * defaultbyte1 + * defaultbyte2 + * defaultbyte3 + * defaultbyte4 + * lowbyte1 + * lowbyte2 + * lowbyte3 + * lowbyte4 + * highbyte1 + * highbyte2 + * highbyte3 + * highbyte4 + * jump offsets... + * + * tableswitch + * default: u4 + * low: u4 + * high: u4 + * jump offsets: + * + * + * ... + * + * or + * lookupswitch + * <0-3 byte pad> + * defaultbyte1 + * defaultbyte2 + * defaultbyte3 + * defaultbyte4 + * npairs1 + * npairs2 + * npairs3 + * npairs4 + * match-offset pairs... + * + * lookupswitch + * default: u4 + * match_count: u4 + * match_1: + * match_2: + * ... + * match_n: + * */ +class SwitchTable { + + Indexer defLabel = null; + ArrayList labels = new ArrayList<>(); + ArrayList keys = new ArrayList<>(); + + // for tableswitch: + Indexer[] resLabels; + int high, low; + + int pc, pad; + JasmEnvironment environment; + + SwitchTable(JasmEnvironment environment) { + this.environment = environment; + } + + void addEntry(int key, Indexer label) { + keys.add(key); + labels.add(label); + } + + // for lookupswitch: + int calcLookupSwitch(int pc) { + this.pc = pc; + pad = ((3 - pc) & 0x3); + int len = 1 + pad + (keys.size() + 1) * 8; + if (defLabel == null) { + defLabel = new Indexer(pc + len); + } + return len; + } + + void writeLookupSwitch(CheckedDataOutputStream out) throws IOException { + environment.traceln(() -> " writeLookupSwitch: pc=" + pc + " pad=" + pad + " deflabel=" + defLabel.cpIndex); + int k; + for (k = 0; k < pad; k++) { + out.writeByte(0); + } + out.writeInt(defLabel.cpIndex - pc); + out.writeInt(keys.size()); + for (k = 0; k < keys.size(); k++) { + out.writeInt(keys.get(k)); + out.writeInt((labels.get(k)).cpIndex - pc); + } + } + + int recalcTableSwitch(int pc) { + int k; + int numpairs = keys.size(); + int high1 = Integer.MIN_VALUE, low1 = Integer.MAX_VALUE; + int numslots = 0; + if (numpairs > 0) { + for (k = 0; k < numpairs; k++) { + int key = keys.get(k); + if (key > high1) { + high1 = key; + } + if (key < low1) { + low1 = key; + } + } + numslots = high1 - low1 + 1; + } + environment.traceln(" recalcTableSwitch: low=%d high=%d".formatted(low1, high1)); + this.pc = pc; + pad = ((3 - pc) & 0x3); + int len = 1 + pad + (numslots + 3) * 4; + if (defLabel == null) { + defLabel = new Indexer(pc + len); + } + Indexer[] resLabels1 = new Indexer[numslots]; + for (k = 0; k < numslots; k++) { + resLabels1[k] = defLabel; + } + for (k = 0; k < numpairs; k++) { + environment.traceln(" keys.data[%d]=%s".formatted(k, keys.get(k))); + resLabels1[keys.get(k) - low1] = labels.get(k); + } + this.resLabels = resLabels1; + this.labels = null; + this.keys = null; + this.high = high1; + this.low = low1; + return len; + } + + void writeTableSwitch(CheckedDataOutputStream out) throws IOException { + int k; + for (k = 0; k < pad; k++) { + out.writeByte(0); + } + out.writeInt(defLabel.cpIndex - pc); + out.writeInt(low); + out.writeInt(high); + for (k = 0; k < resLabels.length; k++) { + out.writeInt(resLabels[k].cpIndex - pc); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TableFormatModel.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TableFormatModel.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TableFormatModel.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TableFormatModel.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.jdis.*; +import org.openjdk.asmtools.jdis.BootstrapMethodData; +import org.openjdk.asmtools.jdis.ConstantPool; +import org.openjdk.asmtools.jdis.ExceptionData; +import org.openjdk.asmtools.jdis.FieldData; +import org.openjdk.asmtools.jdis.InnerClassData; +import org.openjdk.asmtools.jdis.LineNumberData; +import org.openjdk.asmtools.jdis.LocalVariableData; +import org.openjdk.asmtools.jdis.MethodData; +import org.openjdk.asmtools.jdis.RecordData; +import org.openjdk.asmtools.jdis.StackMapData; + +/** + * The TableFormatModel class stores and manages attributes that support a tabular (javap-like) format, + * which can be switched on using the --table option. + */ +public class TableFormatModel { + public enum Token { + NOT_SUPPORTED("NotSupported", null, null, null), + SOURCE_FILE("SourceFile", EAttribute.ATT_SourceFile, JasmTokens.Token.SOURCEFILE, SourceFileData.class), + ENCLOSING_METHOD("EnclosingMethod", EAttribute.ATT_EnclosingMethod, JasmTokens.Token.ENCLOSINGMETHOD, EnclosingMethodData.class), + NEST_MEMBERS("NestMembers", EAttribute.ATT_NestMembers, JasmTokens.Token.NESTMEMBERS, NestMembersData.class), + NEST_HOST("NestHost", EAttribute.ATT_NestHost, JasmTokens.Token.NESTHOST, NestHostData.class), + INNER_CLASSES("InnerClasses", EAttribute.ATT_InnerClasses, JasmTokens.Token.INNERCLASS, InnerClassData.class), + SIGNATURE("Signature", EAttribute.ATT_Signature, JasmTokens.Token.SIGNATURE, SignatureData.class), + CONSTANT_POOL("Constant pool", null, null, ConstantPool.class), + METHOD_DATA("Method_info", null, null, MethodData.class), + FIELD_DATA("Field_info", null, null, FieldData.class), + RECORD_DATA("record_component_info", null, null, RecordData.class), + LINE_NUMBERS("LineNumberTable", EAttribute.ATT_LineNumberTable, JasmTokens.Token.LINETABLE_HEADER, LineNumberData.class), + LOCAL_VARIABLES("LocalVariableTable", EAttribute.ATT_LocalVariableTable, JasmTokens.Token.LOCALVARIABLES_HEADER, LocalVariableData.class), + LOCAL_VARIABLE_TYPES("LocalVariableTypeTable", EAttribute.ATT_LocalVariableTypeTable, JasmTokens.Token.LOCALVARIABLETYPES_HEADER, LocalVariableTypeData.class), + EXCEPTIONS("throws", null, JasmTokens.Token.THROWS, ExceptionData.class), + STACK_MAP("StackMap", EAttribute.ATT_StackMap, JasmTokens.Token.STACKMAP, StackMapData.class), + STACK_MAP_TABLE("StackMapTable", EAttribute.ATT_StackMapTable, JasmTokens.Token.STACKMAPTABLE_HEADER, StackMapData.class), + BOOTSTRAP_METHOD("BootstrapMethods", EAttribute.ATT_BootstrapMethods, JasmTokens.Token.BOOTSTRAPMETHOD, BootstrapMethodData.class); + + final private String parseKey; + final private EAttribute attribute; + + final private JasmTokens.Token jasmToken; + final private String printKey; + final private Class owner; + + Token(String parseKey, EAttribute attribute, JasmTokens.Token jasmToken, Class owner) { + this.parseKey = parseKey; + this.attribute = attribute; + this.jasmToken = jasmToken; + this.printKey = "%s".formatted(parseKey); + this.owner = owner; + } + + public String parseKey() { + return parseKey; + } + + public String printKey() { + return printKey; + } + + public boolean isExtendedPrintingSupported() { + return owner != null; + } + + public EAttribute getAttribute() { + return attribute; + } + + public JasmTokens.Token getJasmToken() { + return jasmToken; + } + + public static Token getBy(Class cls) { + for (Token item : Token.values()) { + if (cls.equals(item.owner)) { + return item; + } + } + return NOT_SUPPORTED; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.jasm.TypeAnnotationTypes.ETargetType; +import org.openjdk.asmtools.jasm.TypeAnnotationTypes.TypePathEntry; + +import java.io.IOException; + +import static java.lang.String.format; +import static org.openjdk.asmtools.asmutils.StringUtils.repeat; + +/** + * JVMS 4.7.20. + * type_annotation { + * u1 target_type; + * union { + * type_parameter_target; + * supertype_target; + * type_parameter_bound_target; + * empty_target; + * formal_parameter_target; + * throws_target; + * localvar_target; + * catch_target; + * offset_target; + * type_argument_target; + * } target_info; + * type_path target_path; + * u2 type_index; + * // + * // + * u2 num_element_value_pairs; + * { u2 element_name_index; + * element_value value; + * } element_value_pairs[num_element_value_pairs]; + * } + */ +public class TypeAnnotationData extends AnnotationData { + + protected ETargetType targetType; + protected TypeAnnotationTargetInfoData targetInfo; + protected TypeAnnotationTypePathData typePath; + + public TypeAnnotationData(Indexer typeCPX, boolean invisible) { + super(typeCPX, invisible); + typePath = new TypeAnnotationTypePathData(); + } + + @Override + public int getLength() { + // lengthOf(annotations[]) + lengthOf(targetType) + lengthOf(targetInfo) + lengthOf(targetInfo) + return super.getLength() + 1 + targetInfo.getLength() + typePath.getLength(); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(targetType.value); + targetInfo.write(out); + typePath.write(out); + super.write(out); + } + + public void addTypePathEntry(TypePathEntry path) { + typePath.addTypePathEntry(path); + } + + @Override + public String toString() { + return format("%s %s %s", targetType.toString(), targetInfo.toString(), typePath.toString()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTargetInfoData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTargetInfoData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTargetInfoData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTargetInfoData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import java.io.IOException; +import java.util.ArrayList; + +import static java.lang.String.format; + +/** + * TargetInfo (4.7.20.1. The target_info union) + *

+ * BaseClass for any Type Annotation Target-Info. + */ +public abstract class TypeAnnotationTargetInfoData implements DataWriter { + + protected TypeAnnotationTypes.ETargetType targetType; + + public TypeAnnotationTargetInfoData(TypeAnnotationTypes.ETargetType targetType) { + this.targetType = targetType; + } + + public TypeAnnotationTypes.ETargetType getTargetType() { + return targetType; + } + + public String toPrintString() { + // print the TargetType and TargetInfo + String targetInfo = _toPrintString(); + return (targetInfo.isBlank()) ? format(" { %s } ", targetType._toPrintString()) : + format(" { %s %s } ", targetType._toPrintString(), targetInfo); + } + + public abstract void write(CheckedDataOutputStream out) throws IOException; + + @Override + public String toString() { + return format("%s_target %s", targetType.targetInfo().printValue(), _toString()); + } + + protected abstract String _toPrintString(); + + protected abstract String _toString(); + + /** + * type_parameter_target (4.7.20.1. The target_info union) + *

+ * The type_parameter_target item indicates that an annotation appears on the declaration of the i'th type parameter + * of a generic class, generic interface, generic method, or generic constructor. + *

+ * type_parameter_target { + * u1 type_parameter_index; + * } + */ + public static class type_parameter_target extends TypeAnnotationTargetInfoData { + + int typeParamIndex; + + public type_parameter_target(TypeAnnotationTypes.ETargetType tt, int index) { + super(tt); + typeParamIndex = index; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(typeParamIndex); + } + + @Override + public int getLength() { + return 1; + } + + @Override + protected String _toString() { + return format("{ type_parameter_index: %d; }", typeParamIndex); + } + + @Override + protected String _toPrintString() { + return String.valueOf(typeParamIndex); + } + } + + /** + * supertype_target (4.7.20.1. The target_info union) + *

+ * The supertype_target item indicates that an annotation appears on a type in the extends or implements clause of + * a class or interface declaration. + *

+ * supertype_target { + * u2 supertype_index; + * } + */ + public static class supertype_target extends TypeAnnotationTargetInfoData { + + int superTypeIndex; + + public supertype_target(TypeAnnotationTypes.ETargetType tt, int index) { + super(tt); + superTypeIndex = index; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(superTypeIndex); + } + + @Override + public int getLength() { + return 2; + } + + @Override + protected String _toString() { + return format("{ supertype_index: %d; }", superTypeIndex); + } + + @Override + protected String _toPrintString() { + return String.valueOf(superTypeIndex); + } + } + + /** + * type_parameter_bound_target (4.7.20.1. The target_info union) + *

+ * The type_parameter_bound_target item indicates that an annotation appears on the i'th bound of the j'th type + * parameter declaration of a generic class, interface, method, or constructor. + *

+ * type_parameter_bound_target { + * u1 type_parameter_index; + * u1 bound_index; + * } + */ + public static class type_parameter_bound_target extends TypeAnnotationTargetInfoData { + + int typeParamIndex; + int boundIndex; + + public type_parameter_bound_target(TypeAnnotationTypes.ETargetType tt, int pindx, int bindx) { + super(tt); + typeParamIndex = pindx; + boundIndex = bindx; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(typeParamIndex); + out.writeByte(boundIndex); + } + + @Override + protected String _toPrintString() { + return typeParamIndex + " " + boundIndex; + } + + @Override + public int getLength() { + return 2; + } + + @Override + protected String _toString() { + return format("{ type_parameter_index: %d; bound_index: %d; }", typeParamIndex, boundIndex); + } + } + + /** + * empty_target (4.7.20.1. The target_info union) + *

+ * The empty_target item indicates that an annotation appears on either the type in a field declaration, + * the return type of a method, the type of a newly constructed object, or the receiver type of a method or constructor. + *

+ * empty_target { + * } + */ + public static class empty_target extends TypeAnnotationTargetInfoData { + + public empty_target(TypeAnnotationTypes.ETargetType tt) { + super(tt); + } + + @Override + protected String _toPrintString() { + return ""; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + // do nothing + } + + @Override + public int getLength() { + return 0; + } + + @Override + protected String _toString() { + return "{ }"; + } + } + + /** + * formal_parameter_target (4.7.20.1. The target_info union) + *

+ * The formal_parameter_target item indicates that an annotation appears on the type in a formal parameter + * declaration of a method, constructor, or lambda expression. + *

+ * formal_parameter_target { + * u1 formal_parameter_index; + * } + */ + public static class formal_parameter_target extends TypeAnnotationTargetInfoData { + + int formalParamIndex; + + public formal_parameter_target(TypeAnnotationTypes.ETargetType tt, int index) { + super(tt); + formalParamIndex = index; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(formalParamIndex); + } + + @Override + protected String _toPrintString() { + return String.valueOf(formalParamIndex); + } + + @Override + public int getLength() { + return 1; + } + + @Override + protected String _toString() { + return format("{ formal_parameter_index: %d; }", formalParamIndex); + } + } + + /** + * throws_target (4.7.20.1. The target_info union) + *

+ * The throws_target item indicates that an annotation appears on the i'th type in the throws clause of a method or + * constructor declaration. + *

+ * throws_target { + * u2 throws_type_index; + * } + */ + public static class throws_target extends TypeAnnotationTargetInfoData { + + int throwsTypeIndex; + + public throws_target(TypeAnnotationTypes.ETargetType tt, int index) { + super(tt); + throwsTypeIndex = index; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(throwsTypeIndex); + } + + @Override + public int getLength() { + return 2; + } + + @Override + protected String _toString() { + return format("{ throws_type_index: %d; }", throwsTypeIndex); + } + + @Override + protected String _toPrintString() { + return String.valueOf(throwsTypeIndex); + } + } + + /** + * localvar_target (4.7.20.1. The target_info union) + *

+ * The localvar_target item indicates that an annotation appears on the type in a local variable declaration, + * including a variable declared as a resource in a try-with-resources statement. + *

+ * localvar_target { + * u2 table_length; + * { u2 start_pc; + * u2 length; + * u2 index; + * } table[table_length]; + * } + */ + public static class localvar_target extends TypeAnnotationTargetInfoData { + + ArrayList table; + + public localvar_target(TypeAnnotationTypes.ETargetType tt, int size) { + super(tt); + table = new ArrayList<>(size); + } + + public void addEntry(int startPC, int length, int cpx) { + LocalVar_Entry entry = new LocalVar_Entry(startPC, length, cpx); + table.add(entry); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(table.size()); + for (LocalVar_Entry entry : table) { + entry.write(out); + } + } + + @Override + public int getLength() { + return 2 + // U2 for table size + (6 * table.size()); // (3 * U2) for each table entry + } + + @Override + protected String _toString() { + int i = 0; + String str = format("{ %d {", table.size()); + for (LocalVar_Entry entry : table) { + str = str.concat(format(" [%d]: %s;", i++, entry.toString())); + } + return str.concat(" } }"); + } + + @Override + protected String _toPrintString() { + final StringBuilder sb = new StringBuilder(); + table.stream().forEach(e -> sb.append(e._toPrintString())); + return sb.toString(); + } + + public static class LocalVar_Entry { + + public int startPC; + public int length; + public int cpx; + + public LocalVar_Entry(int st, int len, int index) { + startPC = st; + length = len; + cpx = index; + } + + void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(startPC); + out.writeShort(length); + out.writeShort(cpx); + } + + public String toString() { + return format("start_pc: %d, length: %d, index: %d", startPC, length, cpx); + } + + protected String _toPrintString() { + return "{ " + startPC + " " + length + " " + cpx + " }"; + } + + } + } + + /** + * catch_target (4.7.20.1. The target_info union) + *

+ * The catch_target item indicates that an annotation appears on the i'th type in an exception parameter declaration. + *

+ * catch_target { + * u2 exception_table_index; + * } + */ + public static class catch_target extends TypeAnnotationTargetInfoData { + + int exceptionTableIndex; + + public catch_target(TypeAnnotationTypes.ETargetType tt, int index) { + super(tt); + exceptionTableIndex = index; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(exceptionTableIndex); + } + + @Override + public int getLength() { + return 2; + } + + @Override + protected String _toString() { + return format("{ exception_table_index: %d; }", exceptionTableIndex); + } + + @Override + protected String _toPrintString() { + return String.valueOf(exceptionTableIndex); + } + } + + /** + * offset_target (4.7.20.1. The target_info union) + *

+ * The offset_target item indicates that an annotation appears on either the type in an instanceof expression or + * a new expression, or the type before the :: in a method reference expression. + *

+ * offset_target { + * u2 offset; + * } + */ + public static class offset_target extends TypeAnnotationTargetInfoData { + + int offset; + + public offset_target(TypeAnnotationTypes.ETargetType tt, int offset) { + super(tt); + this.offset = offset; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(offset); + } + + @Override + protected String _toPrintString() { + return String.valueOf(offset); + } + + @Override + public int getLength() { + return 2; + } + + @Override + protected String _toString() { + return format("{ offset: %d; }", offset); + } + } + + /** + * type_argument_target (4.7.20.1. The target_info union) + *

+ * The type_argument_target item indicates that an annotation appears either on the i'th type in a cast expression, + * or on the i'th type argument in the explicit type argument list for any of the following: a new expression, + * an explicit constructor invocation statement, a method invocation expression, or a method reference expression + *

+ * type_argument_target { + * u2 offset; + * u1 type_argument_index; + * } + */ + public static class type_argument_target extends TypeAnnotationTargetInfoData { + + int offset; + int typeArgumentIndex; + + public type_argument_target(TypeAnnotationTypes.ETargetType targetType, int offset, int index) { + super(targetType); + this.offset = offset; + typeArgumentIndex = index; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeShort(offset); + out.writeByte(typeArgumentIndex); + } + + @Override + protected String _toPrintString() { + return offset + " " + typeArgumentIndex; + } + + @Override + public int getLength() { + return 3; + } + + @Override + protected String _toString() { + return format("{ offset: %d; type_argument_index: %d; }", offset, typeArgumentIndex); + } + } +} + diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypePathData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypePathData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypePathData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypePathData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.openjdk.asmtools.jasm.TypeAnnotationTypes.TypePathEntry; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.stream.Collectors; + +/** + * JVMS 4.7.20.2. The type_path structure + *

+ * type_path { + * u1 path_length; + * { u1 type_path_kind; + * u1 type_argument_index; + * } path[path_length]; + * } + */ +public class TypeAnnotationTypePathData implements DataWriter { + + private ArrayList typePathEntries = new ArrayList<>(); + + public void addTypePathEntry(TypePathEntry entry) { + typePathEntries.add(entry); + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + out.writeByte(typePathEntries.size()); + for (TypePathEntry entry : typePathEntries) { + out.writeByte(entry.getTypePathKind()); + out.writeByte(entry.getTypeArgumentIndex()); + } + } + + @Override + public int getLength() { + return 1 + typePathEntries.size() * 2; + } + + @Override + public String toString() { + if (typePathEntries.size() > 0) { + StringBuilder sb = new StringBuilder("{ "); + sb.append(typePathEntries.stream().map(e -> e.toString()).collect(Collectors.joining(", "))); + sb.append(" }"); + return sb.toString(); + } + return ""; + } + + /** + * jdis: get a string representation of type path structure for kids printing + */ + public String toPrintString() { + return toString(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypes.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypes.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypes.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/TypeAnnotationTypes.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,302 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +/** + * Type annotation types: target_type, target_info and target_path + */ +public class TypeAnnotationTypes { + + /** + * Interpretation of type_path_kind values (Table 4.7.20.2-A) + */ + public enum EPathKind { + ARRAY(0), + INNER_TYPE(1), + WILDCARD(2), + TYPE_ARGUMENT(3); + + private final int tag; + public static final int maxLen = 3; + + EPathKind(int tag) { + this.tag = tag; + } + + public int tag() { + return tag; + } + + public String parseKey() { + return this.toString(); + } + + static EPathKind getPathKind(String token) { + for (EPathKind pk : values()) { + if( pk.parseKey().equals(token)) { + return pk; + } + } + return null; + } + } + + // will throw ArrayIndexOutOfBounds if i < 0 or i > 3 + static public EPathKind getPathKind(int i) { + return EPathKind.values()[i]; + } + + static public class TypePathEntry { + + private final EPathKind kind; + private final int typeArgumentIndex; + + public TypePathEntry(int kind, int typeArgumentIndex) { + this.kind = getPathKind(kind); + this.typeArgumentIndex = typeArgumentIndex; + } + + public TypePathEntry(EPathKind kind, int typeArgumentIndex) { + this.kind = kind; + this.typeArgumentIndex = typeArgumentIndex; + } + + public int getTypePathKind() { + return kind.tag(); + } + + public int getTypeArgumentIndex() { + return typeArgumentIndex; + } + + @Override + public String toString() { + // Chapter 4.7.20.2 The type_path structure + // if the value of the type_path_kind is 0,1, or 2, then the value of the + // type_argument_index item is 0. + return kind.parseKey() + ( kind.tag == 3 ? "{" + typeArgumentIndex +"}" : ""); + } + } + + /** + * union { + * type_parameter_target; + * supertype_target; + * type_parameter_bound_target; + * empty_target; + * method_formal_parameter_target; + * throws_target; + * localvar_target; + * catch_target; + * offset_target; + * type_argument_target; + * } target_info; + */ + public enum ETargetInfo { + TYPEPARAM ("TYPEPARAM", "type_parameter"), + SUPERTYPE ("SUPERTYPE", "supertype"), + TYPEPARAM_BOUND ("TYPEPARAM_BOUND", "type_parameter_bound"), + EMPTY ("EMPTY", "empty"), + METHODPARAM ("METHODPARAM", "formal_parameter"), + EXCEPTION ("EXCEPTION", "throws"), + LOCALVAR ("LOCALVAR", "localvar"), + CATCH ("CATCH", "catch"), + OFFSET ("OFFSET", "offset"), + TYPEARG ("TYPEARG", "type_argument"); + + private final String parseKey; + private final String printValue; + + ETargetInfo(String parse, String printValue) { + parseKey = parse; + this.printValue = printValue; + } + public String parseKey() { + return this.parseKey; + } + + public String printValue() { + return this.printValue; + } + } + + /** + * Interpretation of target_type values (Table 4.7.20-A./B.) + */ + static public enum ETargetType { + class_type_param (0x00, "CLASS_TYPE_PARAMETER", ETargetInfo.TYPEPARAM, "class/interface type parameter"), + meth_type_param (0x01, "METHOD_TYPE_PARAMETER", ETargetInfo.TYPEPARAM, "method/constructor type parameter"), + class_exts_impls (0x10, "CLASS_EXTENDS", ETargetInfo.SUPERTYPE, "class extends/implements"), + class_type_param_bnds (0x11, "CLASS_TYPE_PARAMETER_BOUND", ETargetInfo.TYPEPARAM_BOUND, "class/interface type parameter bounds"), + meth_type_param_bnds (0x12, "METHOD_TYPE_PARAMETER_BOUND", ETargetInfo.TYPEPARAM_BOUND, "method/constructor type parameter bounds"), + field (0x13, "FIELD", ETargetInfo.EMPTY, "field"), + meth_ret_type (0x14, "METHOD_RETURN", ETargetInfo.EMPTY, "method return type"), + meth_receiver (0x15, "METHOD_RECEIVER", ETargetInfo.EMPTY, "method receiver"), + meth_formal_param (0x16, "METHOD_FORMAL_PARAMETER", ETargetInfo.METHODPARAM, "method formal parameter type"), + throws_type (0x17, "THROWS", ETargetInfo.EXCEPTION, "exception type in throws"), + + local_var (0x40, "LOCAL_VARIABLE", ETargetInfo.LOCALVAR, "local variable"), + resource_var (0x41, "RESOURCE_VARIABLE", ETargetInfo.LOCALVAR, "resource variable"), + exception_param (0x42, "EXCEPTION_PARAM", ETargetInfo.CATCH, "exception parameter"), + type_test (0x43, "INSTANCEOF", ETargetInfo.OFFSET, "type test (instanceof)"), + obj_creat (0x44, "NEW", ETargetInfo.OFFSET, "object creation (new)"), + constr_ref_receiver (0x45, "CONSTRUCTOR_REFERENCE_RECEIVER", ETargetInfo.OFFSET, "constructor reference receiver"), + meth_ref_receiver (0x46, "METHOD_REFERENCE_RECEIVER", ETargetInfo.OFFSET, "method reference receiver"), + cast (0x47, "CAST", ETargetInfo.TYPEARG, "cast"), + constr_invoc_typearg (0x48, "CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT", ETargetInfo.TYPEARG, "type argument in constructor call"), + meth_invoc_typearg (0x49, "METHOD_INVOCATION_TYPE_ARGUMENT", ETargetInfo.TYPEARG, "type argument in method call"), + constr_ref_typearg (0x4A, "CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT", ETargetInfo.TYPEARG, "type argument in constructor reference"), + meth_ref_typearg (0x4B, "METHOD_REFERENCE_TYPE_ARGUMENT", ETargetInfo.TYPEARG, "type argument in method reference"); + + public static final int maxTag = 0x9A; + public static final int maxLen = 36; + + public final int value; + private final String parseKey; + private final ETargetInfo targetInfo; + private final String printVal; + + ETargetType(int val, String parse, ETargetInfo targetInfo, String printVal) { + value = val; + parseKey = parse; + this.targetInfo = targetInfo; + this.printVal = printVal; + } + + public String parseKey() { + return parseKey; + } + + public ETargetInfo targetInfo() { + return targetInfo; + } + + public String _toPrintString() { return this.parseKey; } + + @Override + public String toString() { + return String.format("%s[%#x]", parseKey, value); + } + + public static ETargetType getTargetType(int typeCode) { + for( ETargetType type: ETargetType.values() ) { + if (type.value == typeCode) { + return type; + } + } + return null; + } + + static public ETargetType getTargetType(String typeName) { + for( ETargetType type: ETargetType.values() ) { + if (type.parseKey.equals(typeName)) { + return type; + } + } + return null; + } + }; + + /* TypeAnnotationVisitor Methods */ + public static class TypeAnnotationTargetVisitor { + + public final void visit(ETargetType tt) { + switch (tt) { + case class_type_param: + case meth_type_param: + visit_type_param_target(tt); + break; + case class_exts_impls: + visit_supertype_target(tt); + break; + case class_type_param_bnds: + case meth_type_param_bnds: + visit_typeparam_bound_target(tt); + break; + case field: + case meth_ret_type: + case meth_receiver: + visit_empty_target(tt); + break; + case meth_formal_param: + visit_methodformalparam_target(tt); + break; + case throws_type: + visit_throws_target(tt); + break; + case local_var: + case resource_var: + visit_localvar_target(tt); + break; + case exception_param: + visit_catch_target(tt); + break; + case type_test: + case obj_creat: + case constr_ref_receiver: + case meth_ref_receiver: + visit_offset_target(tt); + break; + + case cast: + case constr_invoc_typearg: + case meth_invoc_typearg: + case constr_ref_typearg: + case meth_ref_typearg: + + visit_typearg_target(tt); + break; + } + } + + public void visit_type_param_target(ETargetType tt) { + } + + public void visit_supertype_target(ETargetType tt) { + } + + public void visit_typeparam_bound_target(ETargetType tt) { + } + + public void visit_empty_target(ETargetType tt) { + } + + public void visit_methodformalparam_target(ETargetType tt) { + } + + public void visit_throws_target(ETargetType tt) { + } + + public void visit_localvar_target(ETargetType tt) { + } + + public void visit_catch_target(ETargetType tt) { + } + + public void visit_offset_target(ETargetType tt) { + } + + public void visit_typearg_target(ETargetType tt) { + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/i18n.properties jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/i18n.properties --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/i18n.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jasm/i18n.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,277 @@ +# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +info.usage=\ +Usage: java -jar asmtools.jar jasm [options] |- compile into class file(s)\n\ +\ if - is provided, is used\n\ +where possible options include: +# see also shared section in asmtools/i18 +info.opt.nowrite=\ +\ -nowrite Do not write generated class files +info.opt.strict=\ +\ -strict Consider warnings as errors +info.opt.nowarn=\ +\ -nowarn Do not print warnings +info.opt.cv=\ +\ -cv Set operating class file version if not specified in the source file (by default {0}.{1}) +info.opt.fixcv=\ +\ -fixcv Override class file version in source file(s) +info.opt.fixcv.full=\ +\ -fixcv Update class file version to major.minor if file''s version is below the threshold() + +err.cv_requires_arg=-cv option requires the argument +err.fix_cv_requires_arg=-fixcv option requires the argument either or - +err.invalid_major_minor_param=Invalid parameter +err.invalid_threshold_major_minor_param=Invalid parameter \"-fixcv '{-}'\" +err.invalid_option=Invalid option: {0} +err.byte.limit=Unspecified byte-limit + +# I/O errors +err.cannot.read=Cannot read {0} +err.cannot.write=Cannot write to {0} +err.cannot.create=Cannot create {0} + +# Scanner: +err.invalid.escape.char=Invalid escape character +err.eof.in.comment=Comment isn't terminated at the end of input +err.invalid.number=Invalid character "{0}" in number +err.invalid.octal.number=Invalid character in octal number +err.overflow=Numeric overflow +err.float.format=Invalid floating point format +err.eof.in.string=String isn't terminated at the end of input +err.newline.in.string=String isn't terminated at the end of line +warn.funny.char=Invalid character with code {0} in input +err.unbalanced.paren=Unbalanced parentheses +# Parser: +err.package.repeated=Package statement repeated +warn.intf.repeated=Interface {0} repeated +warn.exc.repeated=Exception repeated in throws clause +warn.record.repeated=Record attribute repeated +warn.method_info.attribute.repeated=The {0} attribute repeated in the method_info structure +err.method_info.attribute.repeated=The {0} attribute repeated in the method_info structure + +err.toplevel.expected=Class, module or interface declaration expected +err.const.def.expected=Constant declaration expected +err.field.expected=Class member declaration expected +err.token.expected=\"{0}\" token is expected +err.token.isnot.expected=\"{0}\" token is not expected +err.identifier.expected=Jasm identifier expected +err.one.of.two.token.expected=Either \"{0}\" or \"{1}\" token is expected +err.one.of.N.token.expected=One of {0} tokens is expected +warn.one.of.two.token.expected=Expected \"{0}\" or \"{1}\" token; interpreted as \"{2}\" +err.field.descriptor.expected=Either a field descriptor or Constant Pool index expected, got {0} +err.class.name.expected=Either a class name or Constant Pool index expected, got {0} +err.module.name.expected=Either a module name or Constant Pool index expected, got {0} +err.package.name.expected=Either package name or Constant Pool index expected, got {0} +err.name.expected=Either name or Constant Pool index expected, got {0} +err.int.expected=Integer expected +err.value.expected=Value expected near \"{0}\" +err.subtag.expected=Subtag expected +warn.cannot.delete.class.cell=Cannot delete Constant Pool entry \"{0}\" because only class cells are accepted +err.wrong.sourcefile.ref= SourceFile attribute incorrectly points to the ConstantPool + +# SourceDebugExtension +warn.empty.debug.extension=The SourceDebugExtension attribute has the empty debug_extension structure. + +#Local var index #name_index:#descriptor_index; [ var index name:descriptor; ] +#Local type index #name_index:#signature_index; [ var index name:signature; ] +err.locvar.expected=A valid index into the local variable array of the current frame expected +err.locvar.wrong.index=The index in the local variable array \"{0}\" is not in the range [0..{1}] [0..Code_attribute.max_locals-1] +err.locvar.unknown.field.descriptor=Valid field descriptor of the local variable \"{0}\" expected instead of \"{1}\" +warn.loctype.wrong.field.signature=Invalid field signature found for local variable in slot \"{0}\": \"{1}\" +err.locvar.slot.occupied=The slot \"{0}\" is occupied by another local variable +err.locvar.undecl=Local variable isn't declared for the slot \"{0}\" +err.fieldType.undecl=Field type isn't declared for the slot \"{0}\" + +warn.locvar.ambiqous=endvar {0}; expected for the local variable +warn.loctype.ambiqous=endtype {0}; expected for the local variable + +# +warn.multiple.inherit=Multiple inheritance is not supported +err.const.undecl=Constant #{0} not declared +err.const.redecl=Constant Pool entry {0} has been redeclared or overlaps with entry {1} +warn.const.fill=Missing Constant Pool entry(ies) {0} might be auto-filled with Utf8[null] +warn.const0.redecl=Re-declaration of Constant #0 cannot be written to the class file +err.extra.attribute=There may be at most one \"{0}\" attribute in the attributes table of a \"{1}\" structure. +warn.redeclared.attribute=The new attribute \"{0}\" overwrites an already declared one in the \"{1}\" structure. +warn.extra.attribute=The \"{0}\" attribute is already declared in the constant pool structure. A new value \"{1}\" is used. + +err.both.nesthost.nestmembers.found=The attribute table of a ClassFile structure must not contain both a NestMembers attribute and a NestHost attribute +warn.no.components.in.record.attribute=Record should have at least one component +warn.modifiers.ignored=The class access modifier(s) {0} ignored + +err.neg.forbidden=Negative integer is not allowed +err.value.large={0} value {1} does not fit in {2} +err.array.type.expected=Array type code expected +err.wrong.mnemocode=Invalid mnemocode ({0}) +err.unknown.bytecode=Unknown bytecode ({0}) +err.default.redecl=Default statement already declared in this table +err.long.switchtable=Switch table is too long {0} +err.io.exception=I/O error in {0} +err.wrong.tag=Wrong tag: {0} expected +err.wrong.tag2=Wrong tag: Either {0} or {1} expected +warn.wrong.tag=Wrong tag: {0} expected +warn.wrong.tag2=Wrong tag: Either {0} or {1} expected + +err.constant.kind.expected=Expected one of the valid constant kinds from the constant pool + +# Code Gen: +err.label.redecl=Label {0} redeclared +err.label.undecl=Label {0} not declared +err.label.expected=Label expected + +err.trap.tryredecl= redeclared +err.trap.endtryredecl= redeclared +err.trap.notry=No found +err.trap.noendtry=No found +warn.trap.notref=No declared + +err.msig.malformed=Malformed method signature at position {0}. {1} +err.no.classname=Class name isn't defined +warn.msig.more255=Number of parameters too large ({0}>255) + +warn.repeated.modifier=Ambiguous use of similar modifiers +#Interface/class +warn.value.object.defined=Class file version {0} does not conform to the new kind of objects; expected version {1} +warn.invalid.modifier.interface.set=\"{0}\": If the ACC_INTERFACE flag is set, the ACC_FINAL, ACC_SUPER, ACC_ENUM, and ACC_MODULE flags must not be set. +warn.invalid.modifier.interface.set.vo=\"{0}\": If the ACC_INTERFACE flag is set, the ACC_FINAL, ACC_IDENTITY, ACC_ENUM, and ACC_MODULE flags must not be set. +warn.invalid.modifier.not.interface.set=\"{0}\": If the ACC_INTERFACE flag is not set ACC_ANNOTATION, and ACC_MODULE flags must not be set. +warn.invalid.modifier.not.interface.set.vo=\"{0}\": If the ACC_INTERFACE flag is not set a value class must have at least one of its ACC_FINAL, ACC_IDENTITY, or ACC_ABSTRACT flags set +warn.invalid.modifier.int.abs=\"{0}\": If the ACC_INTERFACE flag is set, the ACC_ABSTRACT flag must also be set +warn.invalid.modifier.class=Invalid modifier(s) for a class: \"{0}\" +warn.invalid.modifier.class.finabs=\"{0}\": Class cannot be both abstract and final +# Field +warn.invalid.modifier.intfield=\"{0}\": Interface field must be ACC_PUBLIC, ACC_STATIC, and ACC_FINAL only and may have ACC_STRICT_INIT or ACC_SYNTHETIC flag set +warn.invalid.modifier.for.value=\"{0}\": Each field of a value class must have at least one of its ACC_STATIC or ACC_STRICT_INIT flags set +warn.repeat.signature.field=Signature attribute repeated +warn.invalid.modifier.field=Invalid modifier(s) for a field {0} +warn.invalid.modifier.acc=\"{0}\": Each field of a class may have at most one of its ACC_PUBLIC, ACC_PRIVATE, and ACC_PROTECTED flags set +warn.invalid.modifier.fiva=\"{0}\": Each field of a class must not have both its ACC_FINAL and ACC_VOLATILE flags set +# Methods +warn.invalid.modifier.mth=Invalid modifier(s) for a method {0} +warn.init.in_int= method cannot be an interface method +warn.clinit.static=In a class file whose version number is 51.0 or above, a method whose name is must have its ACC_STATIC flag set {0} +warn.invalid.modifier.method=Methods of interfaces must not have ACC_PROTECTED, ACC_FINAL, ACC_SYNCHRONIZED and ACC_NATIVE flags set {0} +warn.invalid.modifier.intmth.less.52=In a class file whose version number is less than 52.0, each method of interface must be abstract public only {0} +warn.invalid.modifier.intmth.is.52=In a class file whose version number is 52.0 or above, each method of an interface must have exactly one of its ACC_PUBLIC and ACC_PRIVATE flags set {0} +warn.invalid.modifier.init=Invalid modifier(s) for method {0} +warn.invalid.modifier.abst=Invalid modifier(s) for abstract method {0} +warn.invalid.modifier.mth.acc=Each method of a class may have at most one of its ACC_PUBLIC, ACC_PRIVATE, and ACC_PROTECTED flags set {0} +warn.invalid.modifier.strict=If a method of a class or interface (whose major version number is at least 46 and at most 60) has its ACC_ABSTRACT flag set, it must not have its ACC_STRICT flag set +#Code attribute +warn.instruction.operand.value.overflow={0} - The argument {2} of the ''{1}'' instruction is written. It is larger than allowed {3} + +# Inner class +warn.invalid.modifier.innerclass=Invalid modifier(s) for an inner class {0} +warn.invalid.modifier.innerclasses=Modifier(s) are ignored as they cannot be applied to a group of inner classes +warn.no.classes.in.innnerclasses=InnerClasses group should have at least one inner class +warn.both.modifiers.apply= Combined \"{0}\" modifiers apply to the InnerClass + +# Stack frame +err.invalid.offset.frame.type=Offset value {0} is not valid for the \"{1}\" entry type +err.no.stack.map=Stack map element for the \"{0}\" entry type is absent +err.no.locals.map=Locals map element for the \"{0}\" entry type is absent +err.should.be.only.one.stack.map.element=Should be only one stack map element for the \"{0}\" entry type +err.unexpected.stack.maps=There are unexpected stack maps for the \"{0}\" entry type +err.unexpected.locals.maps=There are unexpected locals maps for the \"{0}\" entry type +err.more.locals.map.elements=There are more than locals map elements for the \"append_frame\" entry type +err.itemtype.expected=StackMap entry type expected instead of {0} + +err.stackmap.entity.repeated={0} redeclared +err.stackmap.entry.type.not.set=StackMap entry type is not set +err.invalid.stack.frame.type=Unknown entry type \"{0}\" of the StackMapTable +err.stackmaptable.repeated=A method''s Code attribute already has a StackMapTable attribute + +err.stackmap.map.eligible={0} are only eligible in stack_map_frame {1} +# +err.stackmap.expected={0} is expected +warn.stackmap.expected={0} is expected +warn.stackmap.redeclared=The {0} overwrites an already declared one. +err.base.frame.expected=base_frame is expected +err.larvar.frame.expected=early_larval_frame must be declared before the wrapped base_frame. + +err.version.expected=class file version expected +err.invalid.innerclass=Invalid declaration of Inner Class +err.bootstrap.arg.expected=BootstrapMethod argument is expected +err.bootstrap.arg.is.not.expected=BootstrapMethod argument is not expected +warn.bootstrapmethod.attr.bad=Bad bootstrap method attribute index {0} +warn.bootstrapmethod.attr.expected=Invoke dynamic \"{0}\" has undefined method attribute index + +err.invalid.paramnum=Invalid Parameter Number: {0} +err.duplicate.paramnum=Duplicate Parameter Number: {0} +err.paramname.constnum.invaltype=ParameterName CPX at {0} is not a ConstantString +err.paramname.token.unexpected=Incorrect ParamName, unrecognized token: \"{0}\" + +#LineNumber table +err.expected.linetable=The LineNumberTable format is incorrect; \"{0}\" is expected +#LocalValue table +err.header.locvars=The table header is incorrect; \"Start Length Slot Name {0}\" is expected +err.header.expected.locvars=The table header is expected: \"Start Length Slot Name {0}\" +err.expected.locvars=The {0} format is incorrect; {1} is expected + +# annotations Errors +err.incorrect.annot.class=Incorrect Annotation (class), expected class name or CP index, got \"{0}\" +err.incorrect.annot.enum.type=Incorrect Annotation (enum), expected type_name or CP index, got \"{0}\" +err.incorrect.annot.enum.name==Incorrect Annotation (enum), expected const_name or CP index, got \"{0}\" + +err.incorrect.annot.token=Incorrect Annotation, unrecognized token: \"{0}\" +err.incorrect.annotation=Incorrect Annotation ({0}), expected {1}, got \"{2}\" +err.incorrect.annot.keyword=Incorrect Annotation keyword \"{0}\" +err.incorrect.typeannot.target=Incorrect TypeAnnotation target \"{0}\" +err.incorrect.typeannot.targtype.string=Incorrect TypeAnnotation \"{0}\" argument: (expected String), \"{1}\" +err.incorrect.typeannot.targtype.int=Incorrect TypeAnnotation \"{0}\" argument: (expected Integer), \"{1}\" +err.incorrect.typeannot.pathentry=Incorrect TypeAnnotation TargetPath PathEntry \"{0}\" +err.incorrect.typeannot.pathentry.argindex=Incorrect TypeAnnotation TargetPath PathEntry ArgIndex (expected Integer), \"{0}\" + +# moduleContent Errors +warn.default.cfv=Class file version not specified in file or by -cv parameter. Defaulting to version \"{0}\" +warn.isset.cfv=The class file version is set to {0} using the \"-fixcv {1}\" option. +err.module.statement.expected= Module statement expected +err.requires.expected=Module statement \"requires [transitive | static | mandated | synthetic] ModuleName;\" expected +err.exports.expected=Module statement \"exports [mandated | synthetic] PackageName [to ModuleName(1)[,ModuleName(2)[...]]];\" expected +err.provides.expected=Module statement \"provides ClassName with ClassName(1)[,ClassName(2)[...]]];\" expected +err.opens.expected=Module statement \"opens [mandated | synthetic] PackageName [to ModuleName(1)[,ModuleName(2)[...]]];\" expected +err.uses.expected=Module statement \"uses ClassName;\" expected + +# +warn.dot.will.be.converted=Forward slash \"/\" expected instead of dot \".\". The dot is replaced by \"/\" + +# Compiler Errors +err.constcell.empty.nameInfo={0} emptyInfo +err.constcell.null.val=Constant Pool Cell {0} without value +err.constcell.invarg=Cell[{0}] has #{1} +err.entity.not.in.cp=\"{0}\" not found in Constant Pool + +err.constcell.is.undef=Const Cell has undefined Constant pool index and null value +err.constcell.is.null=ConstCell.value can''t be null +err.values.not.eq=Seeking value {0} is not equal to found {1} +err.instr.null.arg=Null arg for {0} +err.instr.wrong.arg={0} has the wrong index #{1} into the Constant Pool +warn.instr.wrong.arg={0} has the wrong index #{1} into the Constant Pool +err.instr.arg.long=Too long argument of {0}: {1} +err.instr.opc.len={0} has wrong length {1} +err.instr.opc.unknown={0} has an unknown type +err.cpindex.notfound=Constant Pool index {0} is not found + +err.instr.oversize=The length of the {0} instruction {1} exceeds the allowed limit of {2} bytes + +# Common errors +err.obj.is.null=Fatal Error: Object reference \"{0}\" is null +err.invalid.type=Invalid type of Constant Pool Constant {0} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/ByteBuffer.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/ByteBuffer.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/ByteBuffer.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/ByteBuffer.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jcoder; + +/** + * Compiles just 1 source file + */ +class ByteBuffer extends java.io.OutputStream { + + String className; + /** + * The buffer where elements are stored. + */ + byte data[]; + /** + * The number of elements in the buffer. + */ + int length; + /** + * The size of the increment. If it is 0 the size of the buffer is doubled + * everytime it needs to grow. + */ + protected int capacityIncrement; + + /** + * Constructs an empty vector with the specified storage capacity and the specified + * capacityIncrement. + * + * @param initialCapacity the initial storage capacity of the vector + * @param capacityIncrement how much to increase the element's size by. + */ + public ByteBuffer(int initialCapacity, int capacityIncrement) { + this.data = new byte[initialCapacity]; + this.capacityIncrement = capacityIncrement; + } + + /** + * Constructs an empty vector with the specified storage capacity. + * + * @param initialCapacity the initial storage capacity of the vector + */ + public ByteBuffer(int initialCapacity) { + this(initialCapacity, 0); + } + + /** + * Constructs an empty vector. + */ + public ByteBuffer() { + this(30); + } + + /** + * Constructs a full vector. + */ + public ByteBuffer(byte data[], int capacityIncrement) { + this.length = data.length; + this.data = data; + this.capacityIncrement = capacityIncrement; + } + + /** + * Constructs a full vector. + */ + public ByteBuffer(byte data[]) { + this(data, 0); + } + + /** + * Returns the number of elements in the vector. Note that this is not the same as the + * vector's capacity. + */ + public final int size() { + return length; + } + + /** + * Ensures that the vector has at least the specified capacity. + * + * @param minCapacity the desired minimum capacity + */ + public final synchronized void ensureCapacity(int minCapacity) { + int oldCapacity = data.length; + if (minCapacity <= oldCapacity) { + return; + } + byte oldData[] = data; + int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement) : (oldCapacity * 2); + if (newCapacity < minCapacity) { + newCapacity = minCapacity; + } + data = new byte[newCapacity]; + System.arraycopy(oldData, 0, data, 0, length); + } + + /*======================================*/ + public void write(int val) { + ensureCapacity(length + 1); + data[length++] = (byte) val; + } + + public void writeAt(int index, long val, int width) { + for (int i = 0; i < width; i++) { + data[index + i] = (byte) (val >> (width - 1 - i) * 8); + } + } + + public void append(long val, int width) { + ensureCapacity(length + width); + writeAt(length, val, width); + length += width; + } +} // end ByteBuffer diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcodTokens.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcodTokens.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcodTokens.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcodTokens.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,275 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jcoder; + +import org.openjdk.asmtools.common.structure.StackMap; +import org.openjdk.asmtools.jasm.ClassFileConst; + +import java.util.HashMap; + +/** + * JcodTokens + *

+ * This class contains tokens specific to parsing JCOD syntax. + *

+ * The classes in JcodTokens are following a Singleton Pattern. These classes are Enums, + * and they are contained in private hash maps (lookup tables and reverse lookup tables). + * These hash maps all have public accessors, which clients use to look-up enums. + *

+ * Tokens in this table carry no external state, and are typically treated as constants. + * They do not need to be reset. + */ +public class JcodTokens { + + /*-------------------------------------------------------- */ + /* Marker: describes the type of Keyword */ + static public enum KeywordType { + + TOKEN(0, "TOKEN"), + KEYWORD(3, "KEYWORD"); + + private final Integer value; + private final String printval; + + KeywordType(Integer val, String print) { + value = val; + printval = print; + } + + public String printval() { + return printval; + } + } + + /*-------------------------------------------------------- */ + /* Marker - describes the type of token */ + /* this is rather cosmetic, no function currently. */ + static public enum TokenType { + VALUE(0, "Value"), + KEYWORDS(1, "Keywords"), + PUNCTUATION(2, "Punctuation"), + JDEC(3, "JDec"), + STACKMAP(4, "StackMap"), + MISC(5, "Misc"); + + private final Integer value; + private final String printVal; + + TokenType(Integer val, String printVal) { + value = val; + this.printVal = printVal; + } + + public String printVal() { + return printVal; + } + } + + /*-------------------------------------------------------- */ + + /** + * Scanner Tokens (Definitive List) + */ + static public enum Token { + EOF(-1, "EOF", "EOF", TokenType.MISC), + IDENT(60, "IDENT", "IDENT", TokenType.VALUE), + LONGSTRINGVAL(61, "LONGSTRINGVAL", "LONGSTRING", TokenType.VALUE), + INTVAL(65, "INTVAL", "INT", TokenType.VALUE), + LONGVAL(66, "LONGVAL", "LONG", TokenType.VALUE), + STRINGVAL(69, "STRINGVAL", "STRING", TokenType.VALUE), + + CLASS(70, "CLASS", "class", TokenType.KEYWORDS, KeywordType.KEYWORD), + INTERFACE(71, "INTERFACE", "interface", TokenType.KEYWORDS, KeywordType.KEYWORD), + DIV(72, "DIV", "div", TokenType.KEYWORDS), + EQ(73, "EQ", "eq", TokenType.KEYWORDS), + ASSIGN(74, "ASSIGN", "assign", TokenType.KEYWORDS), + MODULE(75, "MODULE", "module", TokenType.KEYWORDS, KeywordType.KEYWORD), + + COLON(134, "COLON", ":", TokenType.PUNCTUATION), + SEMICOLON(135, "SEMICOLON", ";", TokenType.PUNCTUATION, KeywordType.KEYWORD), + COMMA(0, "COMMA", ",", TokenType.PUNCTUATION, KeywordType.KEYWORD), + LBRACE(138, "LBRACE", "{", TokenType.PUNCTUATION, KeywordType.KEYWORD), + RBRACE(139, "RBRACE", "}", TokenType.PUNCTUATION, KeywordType.KEYWORD), + LPAREN(140, "LPAREN", "(", TokenType.PUNCTUATION, KeywordType.KEYWORD), + RPAREN(141, "RPAREN", ")", TokenType.PUNCTUATION, KeywordType.KEYWORD), + LSQBRACKET(142, "LSQBRACKET", "[", TokenType.PUNCTUATION, KeywordType.KEYWORD), + RSQBRACKET(143, "RSQBRACKET", "]", TokenType.PUNCTUATION, KeywordType.KEYWORD), + + + BYTEINDEX(156, "BYTEINDEX", "b", TokenType.JDEC, KeywordType.KEYWORD), + SHORTINDEX(157, "SHORTINDEX", "s", TokenType.JDEC, KeywordType.KEYWORD), + ATTR(158, "ATTR", "Attr", TokenType.JDEC, KeywordType.KEYWORD), + BYTES(159, "BYTES", "Bytes", TokenType.JDEC, KeywordType.KEYWORD), + MACRO(160, "MACRO", "Attr", TokenType.JDEC), + COMP(161, "COMP", "Component", TokenType.JDEC, KeywordType.KEYWORD), + FILE(162, "FILE", "file", TokenType.JDEC, KeywordType.KEYWORD), + + ZEROINDEX(163, "ZEROINDEX", "z", TokenType.STACKMAP, KeywordType.KEYWORD); + + private Integer value; + private String printval; + private String parsekey; + private TokenType tk_type; + private KeywordType key_type; + + // By default, if a KeywordType is not specified, it has the value 'TOKEN' + Token(Integer val, String print, String op) { + init(val, print, op, TokenType.VALUE, KeywordType.TOKEN); + } + + Token(Integer val, String print, String op, TokenType tt) { + init(val, print, op, tt, KeywordType.TOKEN); + } + + Token(Integer val, String print, String op, TokenType tt, KeywordType kt) { + init(val, print, op, tt, kt); + } + + private void init(Integer val, String print, String op, TokenType tt, KeywordType kt) { + value = val; + printval = print; + parsekey = op; + tk_type = tt; + key_type = kt; + } + + public String printval() { + return printval; + } + + public String parsekey() { + return parsekey; + } + + public int value() { + return value; + } + + @Override + public String toString() { + return "<" + printval + "> [" + value + "]"; + } + + } + + /** + * Initialized keyword and token Hash Maps (and Reverse Tables) + */ + protected static final int MaxTokens = 172; + private static HashMap TagToTokens = new HashMap<>(MaxTokens); + private static HashMap SymbolToTokens = new HashMap<>(MaxTokens); + private static HashMap ParsekeyToTokens = new HashMap<>(MaxTokens); + + protected static final int MaxKeywords = 40; + private static HashMap TagToKeywords = new HashMap<>(MaxKeywords); + private static HashMap SymbolToKeywords = new HashMap<>(MaxKeywords); + private static HashMap ParsekeyToKeywords = new HashMap<>(MaxKeywords); + + static { + + // register all the tokens + for (Token tk : Token.values()) { + registerToken(tk); + } + + SymbolToKeywords.put(Token.INTVAL.printval(), Token.INTVAL); + ParsekeyToKeywords.put(Token.INTVAL.parsekey(), Token.INTVAL); + SymbolToKeywords.put(Token.STRINGVAL.printval(), Token.STRINGVAL); + ParsekeyToKeywords.put(Token.STRINGVAL.parsekey(), Token.STRINGVAL); + } + + private static void registerToken(Token tk) { + // Tag is a keyword + if (tk.key_type == KeywordType.KEYWORD) { + TagToKeywords.put(tk.value, tk); + SymbolToKeywords.put(tk.printval, tk); + if (tk.parsekey != null) { + ParsekeyToKeywords.put(tk.parsekey, tk); + } + } + + // Finally, register all tokens + TagToTokens.put(tk.value, tk); + SymbolToTokens.put(tk.printval, tk); + ParsekeyToTokens.put(tk.printval, tk); + } + + /* Token accessors */ + public static Token token(int tk) { + return TagToTokens.get(tk); + } + + public static Token keyword_token(int tk) { + return TagToKeywords.get(tk); + } + + /* Reverse lookup accessors */ + public static Token token(String parsekey) { + return ParsekeyToTokens.get(parsekey); + } + + public static Token keyword_token(String parsekey) { + return ParsekeyToKeywords.get(parsekey); + } + + /* Reverse lookup by ID accessors */ + public static Token token_ID(String ID) { + return ParsekeyToTokens.get(ID); + } + + public static Token keyword_token_ID(String ID) { + return ParsekeyToKeywords.get(ID); + } + + public static String keywordName(int token) { + String retval = ""; + if (token > TagToTokens.size()) { + retval = null; + } else { + Token tk = keyword_token(token); + if (tk != null) { + retval = tk.parsekey; + } + } + return retval; + } + + public static Token keyword_token_ident(String idValue) { + Token kwd = keyword_token(idValue); + + if (kwd == null) { + kwd = Token.IDENT; + } + return kwd; + } + + public static int keyword_token_int(String idValue) { + return keyword_token_ident(idValue).value(); + } + + public static int getConstTagByParseString(String stringValue) { + ClassFileConst.ConstType constType = ClassFileConst.getByParseKey(stringValue); + return constType != null ? constType.getTag() : + StackMap.VerificationType.getByParseKey(stringValue).tag(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Jcoder.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Jcoder.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Jcoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Jcoder.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,774 @@ +/* + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jcoder; + +import org.openjdk.asmtools.common.SyntaxError; +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.*; +import java.nio.charset.Charset; +import java.util.*; + +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.CONSTANT_CLASS; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.CONSTANT_UTF8; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.SEMICOLON; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.STRINGVAL; +import static org.openjdk.asmtools.jcoder.JcodTokens.Token; + +/** + * Compiles just 1 source file + */ +class Jcoder { + + protected JcoderEnvironment environment; + protected Scanner scanner; + protected Hashtable attributes = new Hashtable<>(); + + /*-------------------------------------------------------- */ + /* Jcoder Fields */ + private final ArrayList Classes = new ArrayList<>(); + private ByteBuffer buf; + private DataOutputStream outStream; + private int depth = 0; + private String tabStr = ""; + private final Context context; + + /*-------------------------------------------------------- */ + /* Jcoder inner classes */ + + /*-------------------------------------------------------- */ + /* ContextTag (marker) - describes the type of token */ + /* this is rather cosmetic, no function currently. */ + private enum ContextTag { + NULL(""), + CLASS("Class"), + CONSTANTPOOL("Constant-Pool"), + INTERFACES("Interfaces"), + INTERFACE("Interface"), + METHODS("Methods"), + METHOD("Method"), + FIELDS("Fields"), + FIELD("Field"), + ATTRIBUTE("Attribute"); + + private final String printValue; + + ContextTag(String value) { + printValue = value; + } + + public String printval() { + return printValue; + } + } + + /* ContextVal (marker) - Specific value on a context stack */ + private static class ContextVal { + + public ContextTag tag; + int compCount; + ContextVal owner; + + ContextVal(ContextTag tg) { + tag = tg; + compCount = 0; + owner = null; + } + + ContextVal(ContextTag tg, ContextVal ownr) { + tag = tg; + compCount = 0; + owner = ownr; + } + } + + /* Context - Context stack */ + public static class Context { + + Stack stack; + + private boolean hasCP; + private boolean hasMethods; + private boolean hasInterfaces; + private boolean hasFields; + + // Index of the constant pool entry, used for identity of the Attribute + private int cpIndex = 0; + + Context() { + stack = new Stack<>(); + init(); + } + + boolean isConstantPool() { + return !stack.empty() && (stack.peek().tag == ContextTag.CONSTANTPOOL); + } + + boolean isAttribute() { + return !stack.empty() && (stack.peek().tag == ContextTag.ATTRIBUTE); + } + + public void init() { + stack.removeAllElements(); + hasCP = false; + hasMethods = false; + hasInterfaces = false; + hasFields = false; + cpIndex = 0; + } + + void update() { + if (stack.empty()) { + stack.push(new ContextVal(ContextTag.CLASS)); + return; + } + + ContextVal currentCtx = stack.peek(); + switch (currentCtx.tag) { + case CLASS -> { + if (!hasCP) { + stack.push(new ContextVal(ContextTag.CONSTANTPOOL)); + hasCP = true; + } else if (!hasInterfaces) { + stack.push(new ContextVal(ContextTag.INTERFACES)); + hasInterfaces = true; + } else if (!hasFields) { + stack.push(new ContextVal(ContextTag.FIELDS)); + hasFields = true; + } else if (!hasMethods) { + stack.push(new ContextVal(ContextTag.METHODS)); + hasMethods = true; + } else { + // must be class attributes + currentCtx.compCount += 1; + stack.push(new ContextVal(ContextTag.ATTRIBUTE, currentCtx)); + } + } + case INTERFACES -> { + currentCtx.compCount += 1; + stack.push(new ContextVal(ContextTag.INTERFACE, currentCtx)); + } + case FIELDS -> { + currentCtx.compCount += 1; + stack.push(new ContextVal(ContextTag.FIELD, currentCtx)); + } + case METHODS -> { + currentCtx.compCount += 1; + stack.push(new ContextVal(ContextTag.METHOD, currentCtx)); + } + case FIELD, METHOD, ATTRIBUTE -> { + currentCtx.compCount += 1; + stack.push(new ContextVal(ContextTag.ATTRIBUTE, currentCtx)); + } + } + } + + void exit() { + if (!stack.isEmpty()) { + stack.pop(); + } + } + + public String toString() { + if (stack.isEmpty()) { + return ""; + } + ContextVal currentCtx = stack.peek(); + String retval = currentCtx.tag.printval(); + switch (currentCtx.tag) { + case INTERFACE, METHOD, FIELD, ATTRIBUTE -> { + if (currentCtx.owner != null) { + retval += "[" + currentCtx.owner.compCount + "]"; + } + } + } + return retval; + } + + public void setConstantPoolIndex(int cpx) { + cpIndex = cpx; + } + + public int getConstantPoolIndex() { + return cpIndex; + } + } + + /* Jcoder */ + + /** + * Create a parser + */ + Jcoder(JcoderEnvironment environment, HashMap macros) throws IOException { + scanner = new Scanner(environment, macros); + this.environment = environment; + context = new Context(); + + } + + /** + * Expect a token, return its value, scan the next token or throw an exception. + */ + private void expect(Token t) throws SyntaxError, IOException { + if (scanner.token != t) { + environment.traceln(() -> "expect: %s instead of %s".formatted(t.printval(), scanner.token.printval())); + if (t == Token.IDENT) { + environment.error(scanner.pos, "err.identifier.expected"); + } else { + environment.error(scanner.pos, "err.token.expected", t.toString()); + } + throw new SyntaxError(); + } + scanner.scan(); + } + + private void recoverField() throws SyntaxError, IOException { + while (true) { + switch (scanner.token) { + case LBRACE -> { + scanner.match(Token.LBRACE, Token.RBRACE); + scanner.scan(); + } + case LPAREN -> { + scanner.match(Token.LPAREN, Token.RPAREN); + scanner.scan(); + } + case LSQBRACKET -> { + scanner.match(Token.LSQBRACKET, Token.RSQBRACKET); + scanner.scan(); + } + case RBRACE, EOF, INTERFACE, CLASS -> + // begin of something outside a class, panic more + throw new SyntaxError(); + default -> + // don't know what to do, skip + scanner.scan(); + } + } + } + + /** + * Parse an array of struct. + */ + private void parseArray() throws IOException { + scanner.scan(); + int length0 = buf.length; + long pos0 = scanner.pos; + int num_expected; + if (scanner.token == Token.INTVAL) { + num_expected = scanner.intValue; + scanner.scan(); + } else { + num_expected = -1; + } + expect(Token.RSQBRACKET); + int numSize; + switch (scanner.token) { + case BYTEINDEX -> { + scanner.scan(); + numSize = 1; + } + case SHORTINDEX -> { + scanner.scan(); + numSize = 2; + } + case ZEROINDEX -> { + scanner.scan(); + numSize = 0; + } + default -> numSize = 2; + } + buf.append(num_expected, numSize); + + int num_present = parseStruct(); + if (num_expected == -1) { + environment.trace(" buf.writeAt(" + length0 + ", " + num_present + ", " + numSize + "); "); + // skip array size + if (numSize > 0) { + buf.writeAt(length0, num_present, numSize); + } + } else if (num_expected != num_present) { + if (context.isConstantPool() && num_expected == num_present + 1) return; + environment.warning(pos0, "warn.array.wronglength", num_expected, num_present); + } + } + + /** + * Parse a byte array. + */ + private void parseByteArray() throws IOException { + scanner.scan(); + expect(Token.LSQBRACKET); + int length0 = buf.length; + long pos0 = scanner.pos; + int len_expected; + if (scanner.token == Token.INTVAL) { + len_expected = scanner.intValue; + scanner.scan(); + } else { + len_expected = -1; + } + expect(Token.RSQBRACKET); + int lenSize; + switch (scanner.token) { + case BYTEINDEX -> { + scanner.scan(); + lenSize = 1; + } + case SHORTINDEX -> { + scanner.scan(); + lenSize = 2; + } + case ZEROINDEX -> { + scanner.scan(); + lenSize = 0; + } + default -> lenSize = 4; + } + + // skip array size + if (lenSize > 0) { + buf.append(len_expected, lenSize); + } + int length1 = buf.length; + parseStruct(); + int len_present = buf.length - length1; + if (len_expected == -1) { + environment.trace(" buf.writeAt(" + length0 + ", " + len_present + ", " + lenSize + "); "); + // skip array size + if (lenSize > 0) { + buf.writeAt(length0, len_present, lenSize); + } + } else if (len_expected != len_present) { + environment.warning(pos0, "warn.array.wronglength", len_expected, len_present); + } + } + + /** + * Parse an Attribute. + */ + private void parseAttr() throws IOException { + scanner.scan(); + expect(Token.LPAREN); + int cpx; // index int const. pool + if (scanner.token == Token.INTVAL) { + cpx = scanner.intValue; + context.setConstantPoolIndex(cpx); + scanner.scan(); + } else { + environment.error(scanner.pos, "err.attrname.expected"); + throw new SyntaxError(); + } + buf.append(cpx, 2); + long pos0 = scanner.pos; + int length0 = buf.length; + int len_expected; + if (scanner.token == Token.COMMA) { + scanner.scan(); + len_expected = scanner.intValue; + expect(Token.INTVAL); + } else { + len_expected = -1; + } + buf.append(len_expected, 4); + expect(Token.RPAREN); + parseStruct(); + int len_present = buf.length - (length0 + 4); + if (len_expected == -1) { + buf.writeAt(length0, len_present, 4); + } else if (len_expected != len_present) { + environment.warning(pos0, "warn.attr.wronglength", len_expected, len_present); + } + } // end parseAttr + + /** + * Parse a Component of JavaCard .cap file. + */ + private void parseComp() throws IOException { + scanner.scan(); + expect(Token.LPAREN); + int tag = scanner.intValue; // index int const. pool + expect(Token.INTVAL); + buf.append(tag, 1); + long pos0 = scanner.pos; + int length0 = buf.length; + int len_expected; + if (scanner.token == Token.COMMA) { + scanner.scan(); + len_expected = scanner.intValue; + expect(Token.INTVAL); + } else { + len_expected = -1; + } + buf.append(len_expected, 2); + expect(Token.RPAREN); + parseStruct(); + int len_present = buf.length - (length0 + 2); + if (len_expected == -1) { + buf.writeAt(length0, len_present, 2); + } else if (len_expected != len_present) { + environment.warning(pos0, "warn.attr.wronglength", len_expected, len_present); + } + } // end parseComp + + private void adjustDepth(boolean up) { + if (up) { + depth += 1; + context.update(); + scanner.setDebugCP(context.isConstantPool()); + } else { + depth -= 1; + context.exit(); + } + int tabAmt = 4; + int len = depth * tabAmt; + tabStr = " ".repeat(Math.max(0, len)); + } + + /** + * Parse a structure. + */ + private int parseStruct() throws IOException { + int scanedCFV = 0; + int minor = 0; + int major = 0; + adjustDepth(true); + environment.traceln(" "); + environment.traceln(tabStr + "MapStruct { <" + context + "> "); + expect(Token.LBRACE); + int num = 0; + int addElem = 0; + while (true) { + try { + switch (scanner.token) { + case COMMA: // ignored + scanner.scan(); + break; + case SEMICOLON: + num++; + addElem = 0; + scanner.scan(); + break; + case CLASS: + scanner.addConstDebug(CONSTANT_CLASS); + environment.trace("class "); + scanner.longValue = CONSTANT_CLASS.getTag(); + scanner.intSize = 1; + case INTVAL: + environment.trace("int [" + scanner.longValue + "] "); + if (scanner.longValue == 0xCAFEBABEl && environment.cfv.isSetByParameter()) { + scanedCFV++; + } else { + if (scanedCFV > 0) { + if (scanedCFV == 1) { + scanedCFV++; + minor = scanner.intValue; + // skip writing until major analysis + scanner.scan(); + break; + } else { + scanedCFV = 0; + major = scanner.intValue; + environment.trace(" Got file version: " + major + ":" + minor); + // check version update if needed and go on + environment.cfv.setFileVersion((short) major, (short) minor); + buf.append(environment.cfv.minor_version(), scanner.intSize); + buf.append(environment.cfv.major_version(), scanner.intSize); + scanner.scan(); + addElem = 1; + break; + } + } + } + buf.append(scanner.longValue, scanner.intSize); + scanner.scan(); + addElem = 1; + break; + case STRINGVAL: + String name = parseUTF(); + if (context.isConstantPool()) { + EAttribute attr = EAttribute.get(name); + if (attr != EAttribute.ATT_Unrecognized) { + attributes.put(num, attr); + } + } + // SEMICOLON was already parsed in + num++; + addElem = 0; + break; + case LONGSTRINGVAL: + scanner.scan(); + environment.traceln(tabStr + "LongString [\"" + Arrays.toString(scanner.longStringValue.data) + "\"] "); + buf.write(scanner.longStringValue.data, 0, scanner.longStringValue.length); + addElem = 1; + break; + case LBRACE: + parseStruct(); + addElem = 1; + break; + case LSQBRACKET: + parseArray(); + addElem = 1; + break; + case BYTES: + environment.trace("bytes "); + parseByteArray(); + addElem = 1; + break; + case ATTR: + environment.trace("attr "); + parseAttr(); + addElem = 1; + break; + case COMP: + environment.trace("comp "); + parseComp(); + addElem = 1; + break; + case RBRACE: + scanner.scan(); + environment.traceln(System.lineSeparator() + tabStr + "} // MapStruct <" + context + "> ]"); + adjustDepth(false); + return num + addElem; + default: + environment.traceln("unexp token=" + scanner.token); + environment.traceln(" scanner.stringval = \"" + scanner.stringValue + "\""); + environment.error(scanner.pos, "err.element.expected"); + throw new SyntaxError(); + } + } catch (SyntaxError e) { + recoverField(); + } + } + } // end parseStruct + + String decodeText(String input, String encoding) throws IOException { + return + new BufferedReader( + new InputStreamReader( + new ByteArrayInputStream(input.getBytes()), + Charset.forName(encoding))) + .readLine(); + } + + // Parse multiline UTF strings + private String parseUTF() throws IOException { + StringBuilder sb = new StringBuilder(); + boolean prevSemicolonParsed = true; + while (true) { + switch (scanner.token) { + case STRINGVAL: + if (!prevSemicolonParsed) { + environment.error(scanner.pos, "err.token.expected", SEMICOLON.parseKey()); + throw new SyntaxError(); + } + scanner.scan(); + scanner.addConstDebug(CONSTANT_UTF8); + environment.traceln(tabStr + "UTF8 [\"" + scanner.stringValue + "\"] "); + sb.append(scanner.stringValue); + prevSemicolonParsed = false; + break; + case SEMICOLON: + if (prevSemicolonParsed) { + environment.error(scanner.pos, "err.token.expected", STRINGVAL.parseKey()); + throw new SyntaxError(); + } + prevSemicolonParsed = true; + scanner.scan(); + break; + default: + if (!prevSemicolonParsed) { + environment.error(scanner.pos, "err.token.expected", SEMICOLON.parseKey()); + throw new SyntaxError(); + } + if (context.isAttribute() && + attributes.get(context.getConstantPoolIndex()) == EAttribute.ATT_SourceDebugExtension) { + outStream.writeBytes(sb.toString()); + } else { + outStream.writeUTF(sb.toString()); + } + return sb.toString(); + } + } + } + + /** + * Recover after a syntax error in the file. This involves discarding tokens until an + * EOF or a possible legal continuation is encountered. + */ + private void recoverFile() throws IOException { + while (true) { + switch (scanner.token) { + case CLASS, INTERFACE, EOF -> { + // Start of a new source file statement, continue or EOF + return; + } + case LBRACE -> { + scanner.match(Token.LBRACE, Token.RBRACE); + scanner.scan(); + } + case LPAREN -> { + scanner.match(Token.LPAREN, Token.RPAREN); + scanner.scan(); + } + case LSQBRACKET -> { + scanner.match(Token.LSQBRACKET, Token.RSQBRACKET); + scanner.scan(); + } + default -> + // Don't know what to do, skip + scanner.scan(); + } + } + } + + /** + * Parse module declaration + */ + private void parseModule() throws IOException { + // skip module name as a redundant element + scanner.skipTill(Scanner.LBRACE); + buf = new ByteBuffer(); + outStream = new DataOutputStream(buf); + buf.className = "module-info.class"; + scanner.scan(); + environment.traceln("starting " + buf.className); + // Parse the clause + parseClause(); + environment.traceln("ending " + buf.className); + } + + /** + * Parse a class or interface declaration. + */ + private void parseClass(Token prev) throws IOException { + scanner.scan(); + buf = new ByteBuffer(); + outStream = new DataOutputStream(buf); + // Parse the class name + switch (scanner.token) { + case BYTEINDEX, SHORTINDEX, ATTR, BYTES, MACRO, COMP, FILE, IDENT -> { + if (prev == Token.FILE) { + buf.className = scanner.stringValue; + } else { + buf.className = scanner.stringValue + ".class"; + } + } + case STRINGVAL -> buf.className = scanner.stringValue; + default -> { + environment.error(scanner.prevPos, "err.name.expected", "\"" + scanner.token.parsekey() + "\""); + throw new SyntaxError(); + } + } + scanner.scan(); + environment.traceln("starting class " + buf.className); + // Parse the clause + parseClause(); + environment.traceln("ending class " + buf.className); + + + } // end parseClass + + private void parseClause() throws IOException { + switch (scanner.token) { + case LBRACE -> parseStruct(); + case LSQBRACKET -> parseArray(); + case BYTES -> parseByteArray(); + case ATTR -> parseAttr(); + case COMP -> parseComp(); + default -> environment.error(scanner.pos, "err.struct.expected"); + } + } + + // Parse an Jcoder file. + void parseFile() { + environment.traceln("PARSER"); + context.init(); + if (scanner.token == Token.EOF) { + environment.error("err.file.empty", environment.getSimpleInputFileName()); + return; + } + try { + while (scanner.token != Token.EOF) { + try { + switch (scanner.token) { + case CLASS, MODULE, INTERFACE, FILE -> { + Token t = scanner.token; + if (t == Token.MODULE) { + parseModule(); + } else { + parseClass(t); + } + // End of the class,interface or module + Classes.add(buf); + } + case SEMICOLON -> + // Bogus semi colon + scanner.scan(); + case EOF -> { + return; // The end + } + default -> { + environment.traceln("unexpected token=" + scanner.token); + environment.error(scanner.pos, "err.toplevel.expected"); + throw new SyntaxError(); + } + } + } catch (SyntaxError e) { + String msg = e.getMessage(); + environment.traceln(() -> "SyntaxError %s".formatted(msg == null ? "" : msg)); + environment.printException(e); + recoverFile(); + } + } + } catch (IOException e) { + environment.error(scanner.pos, "err.io.exception", environment.getSimpleInputFileName()); + } + } //end parseFile + + /** + * write to the directory passed with -d option + */ + public void write(ByteBuffer cls) throws IOException { + String myname = cls.className; + if (myname == null) { + environment.error("err.cannot.write"); + return; + } + try (BufferedOutputStream bos = new BufferedOutputStream(environment.getToolOutput().getDataOutputStream())) { + bos.write(cls.data, 0, cls.length); + } catch (IOException ignored) { + } + } + + /** + * Writes the classes + */ + public void write() throws IOException { + for (ByteBuffer cls : Classes) { + environment.getToolOutput().startClass(cls.className, Optional.empty(), environment); + write(cls); + environment.getToolOutput().finishClass(cls.className); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderEnvironment.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderEnvironment.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderEnvironment.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderEnvironment.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110EOF301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jcoder; + +import org.openjdk.asmtools.common.CompilerLogger; +import org.openjdk.asmtools.common.EMessageKind; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.inputs.TextInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.structure.CFVersion; + +import java.io.DataInputStream; +import java.io.IOException; +import java.net.URISyntaxException; + +import static org.openjdk.asmtools.common.CompilerConstants.*; + +public class JcoderEnvironment extends Environment { + + final CFVersion cfv; + InputFile inputFile; + + /** + * @param builder the jcoder environment builder + */ + private JcoderEnvironment(Builder builder) { + super(builder); + cfv = new CFVersion(); + } + + @Override + public void setToolInput(ToolInput toolInput) throws IOException, URISyntaxException { + try { + // content of the jcod input file + super.setToolInput(toolInput); + this.inputFile = new InputFile(getDataInputStream()); + } catch (IOException ioe) { + error("err.cannot.read", toolInput); + throw ioe; + } + } + + // proxy methods + @Override + public void warning(long where, String id, Object... args) { + getLogger().warning(where, id, args); + } + + @Override + public void error(long where, String id, Object... args) { + getLogger().error(where, id, args); + } + + @Override + public void warning(String id, Object... args) { + getLogger().warning(NOWHERE, id, args); + } + + @Override + public void error(String id, Object... args) { + getLogger().error(NOWHERE, id, args); + } + + // Jcoder specific methods + public long getErrorCount() { + return getLogger().getCount(EMessageKind.ERROR); + } + + public boolean hasMessages() { + return !super.getLogger().noMessages(); + } + + /** + * @param printTotals whether to print the total line: N warning(s), K error(s) + * @return 0 if there are no errors otherwise a number of errors + */ + public int flush(boolean printTotals) { + return super.getLogger().flush(printTotals); + } + + public long getPosition() { + return inputFile == null ? 0 : inputFile.position; + } + + public int read() throws IOException { + return inputFile.readUTF(); + } + + static class JcoderBuilder extends Builder { + + public JcoderBuilder(ToolOutput toolOutput, DualStreamToolOutput log) { + super(toolOutput, new CompilerLogger("jcoder", JcoderEnvironment.class, log)); + } + + @Override + public JcoderEnvironment build() { + return new JcoderEnvironment(this); + } + } + + class InputFile extends TextInput { + + private int pushBack = EOF; + + private int index = 0; + + InputFile(DataInputStream dataInputStream) throws IOException { + super(dataInputStream); + } + + private int getChar() { + try { + return strData.charAt(index++); + } catch (StringIndexOutOfBoundsException e) { + return EOF; + } + } + + @Override + public int readUTF() { + position = ((long) linepos << OFFSET_BITS) | charPos; + charPos += OFFSET_INC; + int c = pushBack; + if (c == EOF) { + c = getChar(); + } else { + pushBack = EOF; + } + + // parse special characters + switch (c) { + case BACKSLASH -> { + // BACKSLASH is a special code indicating a pushback of a backslash that + // definitely isn't the start of a unicode sequence. + return '\\'; + } + case '\\' -> { + if ((c = getChar()) != 'u') { + pushBack = (c == '\\' ? BACKSLASH : c); + return '\\'; + } + // we have a unicode sequence + charPos += OFFSET_INC; + while ((c = getChar()) == 'u') { + charPos += OFFSET_INC; + } + + // unicode escape sequence + int d = 0; + for (int i = 0; i < 4; i++, charPos += OFFSET_INC, c = getChar()) { + switch (c) { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> d = (d << 4) + c - '0'; + case 'a', 'b', 'c', 'd', 'e', 'f' -> d = (d << 4) + 10 + c - 'a'; + case 'A', 'B', 'C', 'D', 'E', 'F' -> d = (d << 4) + 10 + c - 'A'; + default -> { + error(position, "err.invalid.escape.char"); + pushBack = c; + return d; + } + } + } + pushBack = c; + return d; + } + case '\n' -> { + linepos++; + return '\n'; + } + case '\r' -> { + if ((c = getChar()) != '\n') { + pushBack = c; + } else { + charPos += OFFSET_INC; + } + linepos++; + return '\n'; + } + default -> { + return c; + } + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderTool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderTool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderTool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/JcoderTool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jcoder; + +import org.openjdk.asmtools.common.Compiler; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; + +public abstract class JcoderTool extends Compiler { + + protected JcoderTool(ToolOutput toolOutput) { + super(toolOutput, new StderrLog()); + } + + protected JcoderTool(ToolOutput toolOutput, DualStreamToolOutput logger) { + super(toolOutput, logger); + } + + @Override + public JcoderEnvironment getEnvironment(ToolOutput toolOutput, DualStreamToolOutput log) { + JcoderEnvironment.JcoderBuilder builder = new JcoderEnvironment.JcoderBuilder(toolOutput, log); + return builder.build(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Main.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Main.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Main.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Main.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jcoder; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.inputs.FileInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.PrintWriterOutput; +import org.openjdk.asmtools.common.outputs.StdoutOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualOutputStreamOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.regex.PatternSyntaxException; + +import static org.openjdk.asmtools.Main.*; +import static org.openjdk.asmtools.common.Environment.FAILED; +import static org.openjdk.asmtools.common.Environment.OK; +import static org.openjdk.asmtools.common.outputs.FSOutput.FSDestination.DIR; +import static org.openjdk.asmtools.util.ProductInfo.FULL_VERSION; + +/** + * Jcoder is an assembler that accepts a text file based on the JCod Specification, + * and produces a .class file for use with a Java Virtual Machine. + *

+ * Main entry point of the JCoder assembler :: jcod to class + */ +public class Main extends JcoderTool { + + + HashMap macros = new HashMap<>(1); + // tool options + private boolean noWriteFlag = false; // Do not write generated class files + private boolean ignoreFlag = false; // Ignore non-fatal error(s) that suppress writing class files + + public Main(ToolOutput toolOutput, String... argv) { + super(toolOutput); + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, String... argv) { + this(toolOutput, log, null, argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput, String... argv) { + super(toolOutput, log); + if (toolInput != null) { + fileList.add(toolInput); + } + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput... toolInputs) { + super(toolOutput, log); + Collections.addAll(fileList, toolInputs); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput) { + super(toolOutput, log); + fileList.add(toolInput); + } + + /** + * Deprecated method to support external tools having it + * + * @param ref A stream to which to write reference output + * @param toolName the tool's name (ignored) + */ + @Deprecated + public Main(PrintWriter ref, String toolName) { + super(new PrintWriterOutput(ref)); + } + + /** + * Deprecated method to support external tools having it + * + * @param out A stream to which to write reference output + * @param toolName the tool's name (ignored) + */ + @Deprecated + public Main(PrintStream out, String toolName) { + this(new PrintWriter(out), toolName); + } + + // jcoder entry point + public static void main(String... argv) { + Main compiler = new Main(new StdoutOutput(), argv); + System.exit(compiler.compile()); + } + + @Override + public void usage() { + environment.flush(false); + environment.usage(List.of( + "info.usage", + "info.opt.d", + "info.opt.w", + "info.opt.nowrite", + "info.opt.ignore", + "info.opt.fixcv", + "info.opt.fixcv.full", + "info.opt.t", + "info.opt.v", + "info.opt.version" + )); + } + + // Run jcoder compiler when args already parsed + @Override + public synchronized int compile() { + macros.put("VERSION", "3;45"); + // compile all input files + int rc = OK; + try { + for (ToolInput inputFileName : fileList) { + environment.setToolInput(inputFileName); + Jcoder parser = new Jcoder(environment, macros); + parser.parseFile(); + if (noWriteFlag || (environment.getErrorCount() > 0 && !ignoreFlag)) { + continue; + } + parser.write(); + if (environment.hasMessages()) + rc += environment.flush(true); + } + } catch (IOException | URISyntaxException | Error exception) { + environment.printException(exception); + } catch (Throwable exception) { + // all untrapped exception/errors that escaped CompilerLogger + environment.printException(exception); + environment.error(exception); + } + if (environment.hasMessages()) + rc += environment.flush(true); + return rc; + } + + @Override + protected void parseArgs(String... argv) { + try { + // Parse arguments + for (int i = 0; i < argv.length; i++) { + String arg = argv[i]; + switch (arg) { + // public options + case "-v" -> setVerboseFlag(true); + case "-t" -> { + setVerboseFlag(true); + setTraceFlag(true); + } + case DIR_SWITCH -> { + setFSDestination(DIR, ++i, argv); + } + case WRITE_SWITCH -> { // -w + environment.setIgnorePackage(true); + setFSDestination(DIR, ++i, argv); + } + case DUAL_LOG_SWITCH -> environment.setOutputs(new DualOutputStreamOutput()); + // TODO: restore using macro's + case "-m" -> { + if ((i + 1) >= argv.length) { + environment.error("err.m_requires_macro"); + usage(); + throw new IllegalArgumentException(); + } + try { + String[] macroPair = argv[++i].split("[.:]+", 2); + if (macroPair.length == 2) { + macros.put(macroPair[0], macroPair[1]); + } else { + throw new NumberFormatException(); + } + } catch (PatternSyntaxException | NumberFormatException exception) { + environment.error("err.invalid_macro"); + usage(); + throw new IllegalArgumentException(); + } + } + case "-nowrite" -> noWriteFlag = true; + case "-ignore" -> ignoreFlag = true; + case VERSION_SWITCH -> { + environment.println(FULL_VERSION); + System.exit(OK); + } + case "-h", "-help", "-?" -> { + usage(); + System.exit((OK)); + } + case STDIN_SWITCH -> { + addStdIn(); + } + // overrides cf version even if it's defined in the source file. + case "-fixcv" -> { + if ((i + 1) >= argv.length) { + environment.error("err.fix_cv_requires_arg"); + usage(); + throw new IllegalArgumentException(); + } + String cfvArg = argv[++i]; + boolean withThreshold = cfvArg.contains("-"); + try { + if (withThreshold) { + String[] versions = cfvArg.split("-", 2); + String[] versionsThreshold = versions[0].split("[.:]+", 2); + String[] versionsUpdate = versions[1].split("[.:]+", 2); + if (versionsThreshold.length != 2 || versionsUpdate.length != 2) { + throw new NumberFormatException(); + } + Pair versionsPair = new Pair<>(Integer.parseInt(versionsThreshold[0]), + Integer.parseInt(versionsThreshold[1])); + if (versionsPair.second > 0xFFFF || versionsPair.first > 0xFFFF) { + throw new NumberFormatException(); + } + environment.cfv.setThreshold(versionsPair.first, versionsPair.second); + versionsPair = new Pair<>(Integer.parseInt(versionsUpdate[0]), Integer.parseInt(versionsUpdate[1])); + if (versionsPair.second > 0xFFFF || versionsPair.first > 0xFFFF) { + throw new NumberFormatException(); + } + environment.cfv.setVersion(versionsPair.first, versionsPair.second).setByParameter(true).setFrozen(true); + } else { + String[] versions = cfvArg.split("[.:]+", 2); + if (versions.length == 2) { + Pair versionsPair = new Pair<>(Integer.parseInt(versions[0]), Integer.parseInt(versions[1])); + if (versionsPair.second > 0xFFFF || versionsPair.first > 0xFFFF) { + throw new NumberFormatException(); + } + environment.cfv.setVersion(Integer.parseInt(versions[0]), Integer.parseInt(versions[1])). + setByParameter(true).setFrozen(true); + } else { + throw new NumberFormatException(); + } + } + } catch (PatternSyntaxException | NumberFormatException exception) { + environment.error("err.invalid_threshold_major_minor_param"); + usage(); + throw new IllegalArgumentException(); + } + } + default -> { + if (arg.startsWith("-")) { + environment.error("err.invalid_option", arg); + usage(); + throw new IllegalArgumentException(); + } else { + fileList.add(new FileInput(argv[i])); + } + } + } + } + if (fileList.isEmpty()) { + usage(); + System.exit(FAILED); + } + } catch (IllegalArgumentException iae) { + if (environment.hasMessages()) { + environment.flush(false); + } + System.exit(FAILED); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Scanner.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Scanner.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Scanner.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/Scanner.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,833 @@ +/* + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jcoder; + +import org.openjdk.asmtools.common.SyntaxError; +import org.openjdk.asmtools.jasm.ClassFileConst; + +import java.io.IOException; +import java.util.HashMap; + +import static org.openjdk.asmtools.jcoder.JcodTokens.*; + +/** + * A Scanner for Jcoder tokens. Errors are reported to the environment object.

+ *

+ * The scanner keeps track of the current token, the value of the current token (if any), + * and the start position of the current token.

+ *

+ * The scan() method advances the scanner to the next token in the input.

+ *

+ * The match() method is used to quickly match opening brackets (ie: '(', '{', or '[') + * with their closing counter part. This is useful during error recovery.

+ *

+ * The compiler treats either "\n", "\r" or "\r\n" as the end of a line.

+ */ +public class Scanner { + // End of input + public static final int EOF = -1; + public static final int LBRACE = 123; // "{" + // Where errors are reported + protected JcoderEnvironment environment; + // Input stream + protected JcoderEnvironment.InputFile inputFile; + // The current character + protected int ch, prevCh = -1; + protected String macro; + protected int indexMacro; + // Current token + protected Token token; + // The position of the current token + protected long pos; + // The position of the previous token + protected long prevPos; + // Token values. + protected long longValue; + protected int intValue; + protected int intSize; + protected String stringValue; + protected ByteBuffer longStringValue; + protected int sign; // sign, when reading number + /* A doc comment preceding the most recent token */ + protected String docComment; + HashMap macros = new HashMap<>(); + private boolean debugCP = false; + private int numCPentrs = 0; + /** + * A growable character buffer. + */ + private int count; + private char[] buffer = new char[32]; + + // Create a scanner to scan an input stream. + protected Scanner(JcoderEnvironment environment, HashMap macros) + throws IOException { + this(environment); + this.macros = macros; + } + + // for use in jcfront. + protected Scanner(JcoderEnvironment environment) + throws IOException { + this.environment = environment; + this.inputFile = environment.inputFile; + ch = environment.read(); + prevPos = environment.getPosition(); + scan(); + } + + /* *********************************************** */ + void setDebugCP(boolean enable) { + if (enable) { + numCPentrs = 0; + } + debugCP = enable; + + } + + void addConstDebug(ClassFileConst.ConstType ct) { + numCPentrs++; + environment.traceln("\n Const[" + numCPentrs + "] = " + ct.printVal()); + } + + void setMacro(String macro) { + this.macro = macro; + indexMacro = 0; + prevCh = ch; + } + + void readCh() throws IOException { + if (macro != null) { + if (indexMacro < macro.length()) { + ch = macro.charAt(indexMacro); + } + macro = null; + } + if (prevCh >= 0) { + ch = prevCh; + prevCh = -1; + } else { + ch = inputFile.readUTF(); + } + } + + private void putc(int ch) { + if (count == buffer.length) { + char[] newBuffer = new char[buffer.length * 2]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[count++] = (char) ch; + } + + private String bufferString() { + char[] buf = new char[count]; + System.arraycopy(buffer, 0, buf, 0, count); + return new String(buf); + } + + /** + * Scan a comment. This method should be called once the initial /, * and the next + * character have been read. + */ + private void skipComment() throws IOException { + while (true) { + switch (ch) { + case EOF -> { + environment.error(pos, "err.eof.in.comment"); + return; + } + case '*' -> { + readCh(); + if (ch == '/') { + readCh(); + return; + } + } + default -> readCh(); + } + } + } + + /** + * Scan a doc comment. This method should be called once the initial /, * and * have + * been read. It gathers the content of the comment (witout leading spaces and '*'s) + * in the string buffer. + */ + private String scanDocComment() throws IOException { + count = 0; + + if (ch == '*') { + do { + readCh(); + } while (ch == '*'); + if (ch == '/') { + readCh(); + return ""; + } + } + switch (ch) { + case '\n', ' ' -> readCh(); + } + + boolean seenstar = false; + int c = count; + while (true) { + switch (ch) { + case EOF: + environment.error(pos, "err.eof.in.comment"); + return bufferString(); + + case '\n': + putc('\n'); + readCh(); + seenstar = false; + c = count; + break; + + case ' ': + case '\t': + putc(ch); + readCh(); + break; + + case '*': + if (seenstar) { + readCh(); + if (ch == '/') { + readCh(); + count = c; + return bufferString(); + } + putc('*'); + } else { + seenstar = true; + count = c; + do { + readCh(); + } while (ch == '*'); + switch (ch) { + case ' ' -> readCh(); + case '/' -> { + readCh(); + count = c; + return bufferString(); + } + } + } + break; + + default: + if (!seenstar) { + seenstar = true; + } + putc(ch); + readCh(); + c = count; + break; + } + } + } + + /** + * Scan a decimal number + */ + private void scanDecNumber() throws IOException { + boolean overflow = false; + long value = ch - '0'; + count = 0; + token = Token.INTVAL; + intSize = 2; // default + putc(ch); // save character in buffer + numberLoop: + for (; ; ) { + readCh(); + switch (ch) { + case '8': + case '9': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + putc(ch); + overflow = overflow || (value * 10) / 10 != value; + value = (value * 10) + (ch - '0'); + overflow = overflow || (value - 1 < -1); + break; + case 'b': + readCh(); + intSize = 1; + break numberLoop; + case 's': + readCh(); + intSize = 2; + break numberLoop; + case 'i': + readCh(); + intSize = 4; + break numberLoop; + case 'l': + readCh(); + intSize = 8; + break numberLoop; + default: + break numberLoop; + } + } + longValue = value; + intValue = (int) value; + // we have just finished reading the number. The next thing better + // not be a letter or digit. + if (Character.isJavaIdentifierPart((char) ch) || ch == '.') { + environment.error(inputFile.position, "err.invalid.number", Character.toString((char) ch)); + do { + readCh(); + } while (Character.isJavaIdentifierPart((char) ch) || ch == '.'); + return; + } + if (overflow) { + environment.error(pos, "err.overflow"); + } + } // scanNumber() + + /** + * Scan a hex number. + */ + private void scanHexNumber() throws IOException { + boolean overflow = false; + long value = 0; + int cypher; + count = 0; + token = Token.INTVAL; + intSize = 2; // default + putc(ch); // save character in buffer + numberLoop: + for (int k = 0; ; k++) { + readCh(); + switch (ch) { + case '8': + case '9': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + cypher = (char) ch - '0'; + break; + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + cypher = 10 + Character.toLowerCase((char) ch) - 'a'; + break; + + default: + break numberLoop; + } + putc(ch); + overflow = overflow || ((value >>> 60) != 0); + value = (value << 4) + cypher; + intSize = (k + 1) / 2; + } + longValue = value; + intValue = (int) value; + // we have just finished reading the number. The next thing better + // not be a letter or digit. + if (Character.isJavaIdentifierPart((char) ch) || ch == '.') { + environment.error(inputFile.position, "err.invalid.number", Character.toString((char) ch)); + do { + readCh(); + } while (Character.isJavaIdentifierPart((char) ch) || ch == '.'); + intValue = 0; +// } else if ( overflow || (intValue - 1 < -1) ) { + } else if (overflow) { + intValue = 0; // so we don't get second overflow in Parser + environment.error(pos, "err.overflow"); + } + } // scanNumber() + + /** + * Scan an escape character. + * + * @return the character or -1 if it escaped an end-of-line. + */ + private int scanEscapeChar() throws IOException { + long p = inputFile.position; + + readCh(); + switch (ch) { + case '0', '1', '2', '3', '4', '5', '6', '7' -> { + int n = ch - '0'; + for (int i = 2; i > 0; i--) { + readCh(); + switch (ch) { + case '0', '1', '2', '3', '4', '5', '6', '7' -> n = (n << 3) + ch - '0'; + default -> { + if (n > 0xFF) { + environment.error(p, "err.invalid.escape.char"); + } + return n; + } + } + } + readCh(); + if (n > 0xFF) { + environment.error(p, "err.invalid.escape.char"); + } + return n; + } + case 'r' -> { + readCh(); + return '\r'; + } + case 'n' -> { + readCh(); + return '\n'; + } + case 'f' -> { + readCh(); + return '\f'; + } + case 'b' -> { + readCh(); + return '\b'; + } + case 't' -> { + readCh(); + return '\t'; + } + case '\\' -> { + readCh(); + return '\\'; + } + case '\"' -> { + readCh(); + return '\"'; + } + case '\'' -> { + readCh(); + return '\''; + } + } + + environment.error(p, "err.invalid.escape.char"); + readCh(); + return -1; + } + + /** + * Scan a string. The current character should be the opening " of the string. + */ + private void scanString() throws IOException { + token = Token.STRINGVAL; + count = 0; + readCh(); + + loop: + for (; ; ) { + switch (ch) { + case EOF: + environment.error(pos, "err.eof.in.string"); + break loop; + + case '\n': + readCh(); + environment.error(pos, "err.newline.in.string"); + break loop; + + case '"': + readCh(); + break loop; + + case '\\': { + int c = scanEscapeChar(); + if (c >= 0) { + putc((char) c); + } + break; + } + + default: + putc(ch); + readCh(); + break; + } + } + stringValue = bufferString(); + } + + /** + * Scan a character array. The current character should be the opening ' of the array. + */ + private void scanCharArray() throws IOException { + token = Token.LONGSTRINGVAL; + ByteBuffer buf = new ByteBuffer(); + count = 0; + readCh(); + + loop: + for (; ; ) { + int c = ch; + switch (ch) { + case EOF: + environment.error(pos, "err.eof.in.string"); + break loop; + + case '\n': + readCh(); + environment.error(pos, "err.newline.in.string"); + break loop; + + case '\'': + readCh(); + break loop; + + case '\\': + c = scanEscapeChar(); + if (c < 0) { + break; + } + // no break - continue + default: + // see description of java.io.DataOutput.writeUTF() + if ((c > 0) && (c <= 0x7F)) { + buf.write(c); + } else if ((c == 0) || ((c >= 0x80) && (c <= 0x7FF))) { + buf.write(0xC0 | (0x1F & (c >> 6))); + buf.write(0x80 | (0x3f & c)); + } else { + buf.write(0xc0 | (0x0f & (c >> 12))); + buf.write(0x80 | (0x3f & (c >> 6))); + buf.write(0x80 | (0x3f & c)); + } + readCh(); + } + } + longStringValue = buf; + } + + /** + * Scan an Identifier. The current character should be the first character of the + * identifier. + */ + private void scanIdentifier() throws IOException { + count = 0; + boolean compound = false; + for (; ; ) { + putc(ch); + readCh(); + if ((ch == '/') || (ch == '.') || (ch == '-')) { + compound = true; + } else if (!Character.isJavaIdentifierPart((char) ch)) { + break; + } + } + stringValue = bufferString(); + if (compound) { + token = Token.IDENT; + } else { + token = keyword_token_ident(stringValue); + if (token == Token.IDENT) { + intValue = getConstTagByParseString(stringValue); + if (intValue != -1) { + // this is a constant + if (debugCP) { + ClassFileConst.ConstType constType = ClassFileConst.getByParseKey(stringValue); + if (constType != null) { + addConstDebug(constType); + } + } + token = Token.INTVAL; + intSize = 1; + longValue = intValue; + } + } + } + } // end scanIdentifier + + // skip till symbol + protected void skipTill(int sym) throws IOException { + while (true) { + if (ch == EOF) { + environment.error(pos, "err.eof.in.comment"); + return; + } else if (ch == sym) { + return; + } + readCh(); + } + } + + protected long xscan() throws IOException { + long retPos = pos; + prevPos = inputFile.position; + docComment = null; + sign = 1; + for (; ; ) { + pos = inputFile.position; + + switch (ch) { + case EOF: + token = Token.EOF; + return retPos; + + case '\n': + case ' ': + case '\t': + case '\f': + readCh(); + break; + + case '/': + readCh(); + switch (ch) { + case '/': + // Parse a // comment + do { + readCh(); + } while ((ch != EOF) && (ch != '\n')); + break; + + case '*': + readCh(); + if (ch == '*') { + docComment = scanDocComment(); + } else { + skipComment(); + } + break; + + default: + token = Token.DIV; + return retPos; + } + break; + + case '"': + scanString(); + return retPos; + + case '\'': + scanCharArray(); + return retPos; + + case '-': + sign = -sign; // hack: no check that numbers only are allowed after + case '+': + readCh(); + break; + + case '0': + readCh(); + token = Token.INTVAL; + longValue = intValue = 0; + switch (ch) { + case 'x', 'X' -> scanHexNumber(); + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> scanDecNumber(); + case 'b' -> { + readCh(); + intSize = 1; + } + case 's' -> { + readCh(); + intSize = 2; + } + case 'i' -> { + readCh(); + intSize = 4; + } + case 'l' -> { + readCh(); + intSize = 8; + } + default -> intSize = 2; + } + return retPos; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + scanDecNumber(); + return retPos; + + case '{': + readCh(); + token = Token.LBRACE; + return retPos; + + case '}': + readCh(); + token = Token.RBRACE; + return retPos; + + case '(': + readCh(); + token = Token.LPAREN; + return retPos; + + case ')': + readCh(); + token = Token.RPAREN; + return retPos; + + case '[': + readCh(); + token = Token.LSQBRACKET; + return retPos; + + case ']': + readCh(); + token = Token.RSQBRACKET; + return retPos; + + case ',': + readCh(); + token = Token.COMMA; + return retPos; + + case ';': + readCh(); + token = Token.SEMICOLON; + return retPos; + + case ':': + readCh(); + token = Token.COLON; + return retPos; + + case '=': + readCh(); + if (ch == '=') { + readCh(); + token = Token.EQ; + return retPos; + } + token = Token.ASSIGN; + return retPos; + + case '\u001a': + // Our one concession to DOS. + readCh(); + if (ch == EOF) { + token = Token.EOF; + return retPos; + } + environment.error(pos, "err.funny.char"); + readCh(); + break; + + case '#': + readCh(); + scanDecNumber(); + return retPos; + + case '&': { + readCh(); + retPos = pos; + if (!Character.isJavaIdentifierStart((char) ch)) { + environment.error(pos, "err.identifier.expected"); + } + scanIdentifier(); + String macroId = stringValue; + String macro = macros.get(macroId); + if (macro == null) { + environment.error(pos, "err.macro.undecl", macroId); + throw new SyntaxError(); + } + setMacro(macro); + readCh(); + } + break; + + default: + if (Character.isJavaIdentifierStart((char) ch)) { + scanIdentifier(); + return retPos; + } + environment.error(pos, "err.funny.char"); + readCh(); + break; + } + } + } + + /** + * Scan to a matching '}', ']' or ')'. The current token must be a '{', '[' or '('; + */ + protected void match(Token open, Token close) throws IOException { + int depth = 1; + + while (true) { + scan(); + if (token == open) { + depth++; + } else if (token == close) { + if (--depth == 0) { + return; + } + } else if (token == Token.EOF) { + environment.error(pos, "err.unbalanced.paren"); + return; + } + } + } + + /** + * Scan the next token. + * + * @return the position of the previous token. + */ + protected long scan() throws IOException { + return xscan(); + } + + /** + * Scan the next token. + * + * @return the position of the previous token. + */ + protected long scanMacro() throws IOException { + return xscan(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/i18n.properties jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/i18n.properties --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/i18n.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jcoder/i18n.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,66 @@ +# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +info.usage=\ +Usage: java -jar asmtools.jar jcoder [options] |- compile into class file(s)\n\ +\ if - is provided, is used\n\ +where possible options include: +# see also shared section in asmtools/i18 +info.opt.nowrite=\ +\ -nowrite Do not write generated class files +info.opt.ignore=\ +\ -ignore Ignore non-fatal error(s) that suppress writing class files +info.opt.fixcv=\ +\ -fixcv Override class file version in source file(s) +info.opt.fixcv.full=\ +\ -fixcv Update class file version to major:minor if file''s version is below the threshold() + +err.invalid_option=invalid option: {0} +err.m_requires_macro=-m requires argument \"id:\" +err.invalid_macro=Invalid parameter id:[.] + +err.fix_cv_requires_arg=-fixcv option requires the argument either or - +err.invalid_threshold_major_minor_param=Invalid parameter \"-fixvc '{-}'\" + +# I/O errors +err.cannot.read=Cannot read {0} +err.cannot.write=Cannot write to {0} +err.fatal_exception=fatal exception +err.file.empty=The file is empty: {0} + +err.eof.in.comment=Comment not terminated at end of input. +err.invalid.number=Invalid character \"{0}\" in number. +err.overflow=Numeric overflow. +err.eof.in.string=String not terminated at end of input. +err.newline.in.string=String not terminated at end of line. +err.funny.char=Invalid character in input. +err.unbalanced.paren=Unbalanced parentheses. +err.toplevel.expected=Class or interface declaration expected. +err.token.expected=\"{0}\" expected. +err.identifier.expected=Identifier expected. +err.name.expected=Name expected. +err.io.exception=I/O error in {0}. +warn.array.wronglength=Expected array length \"{0}\" does not match the actual length \"{1}\"; expected length written. +warn.attr.wronglength=Expected attribute length \"{0}\" does not match the actual length \"{1}\"; expected length written. +err.attrname.expected=Attribute's name or index expected. +err.element.expected=The primary element of the ClassFile structure is expected. +err.struct.expected=A structured element of the ClassFile is expected. +err.macro.undecl=Macro \"{0}\" undefined. +err.invalid.escape.char=Invalid escape char. diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/ClassData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/ClassData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/ClassData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/ClassData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,1496 @@ +/* + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdec; + +import org.openjdk.asmtools.asmutils.StringUtils; +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.outputs.StdoutOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.structure.*; +import org.openjdk.asmtools.jcoder.JcodTokens; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.Optional; + +import static java.lang.Math.min; +import static java.lang.String.format; +import static org.openjdk.asmtools.Main.sharedI18n; +import static org.openjdk.asmtools.asmutils.StringUtils.*; +import static org.openjdk.asmtools.common.structure.ClassFileContext.MODULE_DIRECTIVES; +import static org.openjdk.asmtools.common.structure.ClassFileContext.VALUE_OBJECTS; +import static org.openjdk.asmtools.jasm.ClassFileConst.*; +import static org.openjdk.asmtools.jasm.ClassFileConst.AnnotationElementType.AE_UNKNOWN; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.CONSTANT_MODULE; +import static org.openjdk.asmtools.jasm.ClassFileConst.ConstType.CONSTANT_UTF8; +import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.ETargetInfo; +import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.ETargetType; +import static org.openjdk.asmtools.jcoder.JcodTokens.Token.IDENT; + +/** + * Class data of the Java Decoder + */ +class ClassData { + + private static final int COMMENT_OFFSET = 42; + private static final int BYTES_IN_LINE_SPACED_OUT = 12; // Format: 0x04 0x3C 0x04 0x3D; + private static final int BYTES_IN_LINE_CONDENSED = 8; // Format: 0x043C043D043E1B1C; + private static final String ERROR_PREFIX = " // The ConstantPoll Index "; + + private static final String INDENT_STRING = " "; + private static final int INDENT_LENGTH = INDENT_STRING.length(); + /*========================================================*/ + + private final NestedByteArrayInputStream arrayInputStream; + private final DataInputStream inputStream; + protected JdecEnvironment environment; + /* ====================================================== */ + private byte[] types; + private Object[] cpool; + private int CPlen; + private int[] cpe_pos; + private String entityType = ""; + private String entityName = ""; + /*========================================================*/ + private int indent = 0; + + ClassData(JdecEnvironment environment) throws IOException, URISyntaxException { + this.environment = environment; + // + try (DataInputStream dis = environment.getToolInput().getDataInputStream(Optional.empty())) { + byte[] buf = new byte[dis.available()]; + if (dis.read(buf) <= 0) { + throw new FormatError(environment.getLogger(), + "err.file.empty", environment.getSimpleInputFileName()); + } + arrayInputStream = new NestedByteArrayInputStream(buf); + inputStream = new DataInputStream(arrayInputStream); + } + } + + private String toHex(long val, int width) { + StringBuilder s = new StringBuilder(); + for (int i = width * 2 - 1; i >= 0; i--) { + s.append(hexTable[((int) (val >> (4 * i))) & 0xF]); + } + return "0x" + s; + } + + private String toHex(long val) { + int width; + for (width = 8; width > 0; width--) { + if ((val >> (width - 1) * 8) != 0) { + break; + } + } + return toHex(val, width); + } + + private void printByteHex(int b) { + environment.print(hexTable[(b >> 4) & 0xF]); + environment.print(hexTable[b & 0xF]); + } + + /** + * @param in input stream to get bytes for printing + * @param len number of bytes + * @param printSeparately defines a format of printed lines which will be either 0x04 0x3C 0x04 0x3D; or 0x043C043D043E1B1C; + * @param ignoreException Whether to propagate the exception or ignore it + * @throws IOException exception might happen while reading DataInputStream + **/ + private void printBytes(DataInputStream in, int len, boolean printSeparately, boolean ignoreException) throws IOException { + int i = 0; + boolean printed = false; + final int BYTES_IN_LINE = printSeparately ? BYTES_IN_LINE_SPACED_OUT : BYTES_IN_LINE_CONDENSED; + try { + for (; i < len; i++) { + byte b = in.readByte(); + if (i % BYTES_IN_LINE == 0) { + out_print(printSeparately ? "" : "0x"); + } + if (printSeparately) { + environment.print("0x"); + } + printByteHex(b); + printed = true; + if (printSeparately) { + if (i % BYTES_IN_LINE == BYTES_IN_LINE - 1) { + environment.println(";"); + } else if (i + 1 != len) { + environment.print(" "); + } + } else { + if (i % BYTES_IN_LINE == BYTES_IN_LINE - 1) { + environment.println(";"); + } + } + } + } catch (EOFException ignored) { + if (!ignoreException) { + throw ignored; + } + } finally { + if (printed) { + if (len % 8 != 0) { + if (i > 0) + environment.println(";"); + else + out_println(";"); + } + } + } + } + + private void printUtf8String(DataInputStream in, int len) throws IOException { + final int CHARS_IN_LINE = 78; + readUtf8String(in, len, CHARS_IN_LINE).forEach(s -> environment.println(getOutString("") + s)); + } + + private void printRestOfBytes() { + for (int i = 0; ; i++) { + try { + byte b = inputStream.readByte(); + if (i % BYTES_IN_LINE_SPACED_OUT == 0) + environment.print(INDENT_STRING); + else + environment.print(" "); + environment.print("0x"); + printByteHex(b); + if (i % BYTES_IN_LINE_SPACED_OUT == BYTES_IN_LINE_SPACED_OUT - 1) + environment.println(";"); + } catch (IOException e) { + environment.println(";"); + return; + } + } + } + + private void printBytes(byte[] buf) { + boolean newline = false; + for (int i = 0; i < buf.length; i++) { + if (i % BYTES_IN_LINE_SPACED_OUT == 0) + environment.print(INDENT_STRING); + else + environment.print(" "); + environment.print("0x"); + printByteHex(buf[i]); + if (i % BYTES_IN_LINE_SPACED_OUT == BYTES_IN_LINE_SPACED_OUT - 1) { + newline = true; + environment.println(";"); + } else { + newline = false; + } + } + if (!newline) + environment.println(";"); + } + + private void printUtf8InfoIndex(int index, String indexName) { + out_print("#" + index + "; // "); + String comment = indexName; + try { + if (environment.printDetailsFlag) { + comment = format("%-16s", indexName) + " : " + cpool[index]; + } + } catch (Exception ignored) { + } + environment.println(comment); + } + + private void out_begin(String s) { + environment.println(getOutString(s)); + indent++; + } + + private void out_print(String s) { + environment.print(getOutString(s)); + } + + private void out_println(String s) { + environment.println(getOutString(s)); + } + + private String getOutString(String s) { + s = formatComments(s, indent); + return repeat(INDENT_STRING, indent) + s; + } + + private void out_end(String s) { + s = formatComments(s, indent - 1); + environment.println(repeat(INDENT_STRING, --indent) + s); + } + + private String startArray(int length) { + return "[" + (environment.printDetailsFlag ? Integer.toString(length) : "") + "]"; + } + + private void startArrayCmt(int length, String comment) { + out_begin(startArray(length) + format(" {%s", comment == null ? "" : " // " + comment)); + } + + private void startArrayCmtB(int length, String comment) { + out_begin(startArray(length) + format("b {%s", comment == null ? "" : " // " + comment)); + } + + private void readCP(byte[] alreadyRead, DataInputStream in) throws IOException { + int length = in.readUnsignedShort(); + CPlen = length; + environment.traceln("jdec.trace.CP_len", length); + types = new byte[length]; + cpool = new Object[length]; + cpe_pos = new int[length]; + for (int i = 1; i < length; i++) { + byte btag; + int v1; + long lv; + cpe_pos[i] = arrayInputStream.getPos(); + btag = in.readByte(); + environment.traceln("jdec.trace.CP_entry", i, btag); + types[i] = btag; + ConstType tg = getByTag(btag); + switch (tg) { + case CONSTANT_UTF8, CONSTANT_ASCIZ -> cpool[i] = in.readUTF(); + case CONSTANT_INTEGER, CONSTANT_INT, + CONSTANT_BYTE, CONSTANT_C_BYTE, + CONSTANT_CHAR, CONSTANT_C_CHAR, + CONSTANT_SHORT, CONSTANT_C_SHORT, + CONSTANT_C_BOOLEAN, CONSTANT_BOOLEAN -> { + v1 = in.readInt(); + cpool[i] = v1; + } + case CONSTANT_FLOAT, CONSTANT_C_FLOAT -> { + v1 = Float.floatToIntBits(in.readFloat()); + cpool[i] = v1; + } + case CONSTANT_LONG, CONSTANT_C_LONG -> { + lv = in.readLong(); + cpool[i] = lv; + i++; + } + case CONSTANT_DOUBLE, CONSTANT_C_DOUBLE -> { + lv = Double.doubleToLongBits(in.readDouble()); + cpool[i] = lv; + i++; + } + case CONSTANT_CLASS, CONSTANT_C_CLASS, + CONSTANT_STRING, CONSTANT_L_STRING, + CONSTANT_MODULE, CONSTANT_PACKAGE -> { + v1 = in.readUnsignedShort(); + cpool[i] = v1; + } + case CONSTANT_INTERFACEMETHODREF, CONSTANT_INTERFACEMETHOD, + CONSTANT_FIELDREF, CONSTANT_FIELD, + CONSTANT_METHODREF, CONSTANT_METHOD, + CONSTANT_NAMEANDTYPE -> cpool[i] = "#" + in.readUnsignedShort() + " #" + in.readUnsignedShort(); + case CONSTANT_DYNAMIC, CONSTANT_INVOKEDYNAMIC -> + cpool[i] = in.readUnsignedShort() + "s #" + in.readUnsignedShort(); + case CONSTANT_METHODHANDLE -> cpool[i] = in.readUnsignedByte() + "b #" + in.readUnsignedShort(); + case CONSTANT_METHODTYPE -> cpool[i] = "#" + in.readUnsignedShort(); + default -> { + cpool[i] = in.readUnsignedShort(); + CPlen = ++i; + // the output can be not ready if file output is used. + if (!environment.getToolOutput().isReady()) { + environment.setToolOutput(new StdoutOutput()); + } + out_println("class {"); + printBytes(alreadyRead); + indent++; + printCP(); // exception will be thrown here. + } + } + } + } + + private void printCP() { + int length = CPlen; + startArrayCmt(length, "Constant Pool"); + out_println("; // first element is empty"); + try { + int size; + for (int i = 1; i < length; i = i + size) { + size = 1; + byte btag = types[i]; + ConstType tg = getByTag(btag); + int pos = cpe_pos[i]; + String tagstr; + String valstr; + int v1; + long lv; + if (tg != null) { + tagstr = tg.parseKey(); + } else { + throw new Error("Can't get a tg representing the type of Constant in the Constant Pool at: " + i); + } + switch (tg) { + case CONSTANT_UTF8, CONSTANT_ASCIZ -> { + tagstr = CONSTANT_UTF8.parseKey(); + valstr = StringUtils.Utf8ToString(getStringByIndex(i), "\""); + } + case CONSTANT_INTEGER, CONSTANT_INT, + CONSTANT_BYTE, CONSTANT_C_BYTE, + CONSTANT_CHAR, CONSTANT_C_CHAR, + CONSTANT_SHORT, CONSTANT_C_SHORT, + CONSTANT_C_BOOLEAN, CONSTANT_BOOLEAN, + CONSTANT_FLOAT, CONSTANT_C_FLOAT -> { + v1 = (Integer) cpool[i]; + valstr = toHex(v1, 4); + } + case CONSTANT_DOUBLE, CONSTANT_C_DOUBLE, CONSTANT_LONG, CONSTANT_C_LONG -> { + lv = (Long) cpool[i]; + valstr = toHex(lv, 8) + ";"; + size = 2; + } + case CONSTANT_MODULE, CONSTANT_PACKAGE, + CONSTANT_CLASS, CONSTANT_C_CLASS, + CONSTANT_STRING, CONSTANT_L_STRING -> { + v1 = (Integer) cpool[i]; + valstr = "#" + v1; + } + case CONSTANT_INTERFACEMETHODREF, CONSTANT_INTERFACEMETHOD, + CONSTANT_FIELDREF, CONSTANT_FIELD, + CONSTANT_METHODREF, CONSTANT_METHOD, + CONSTANT_NAMEANDTYPE, + CONSTANT_METHODHANDLE, CONSTANT_METHODTYPE, + CONSTANT_DYNAMIC, CONSTANT_INVOKEDYNAMIC -> valstr = getStringByIndex(i); + default -> { + out_println(toHex(btag, 1) + "; // invalid constant type: " + (int) btag + " for element " + i); + throw new ClassFormatError("Invalid constant type: " + (int) btag + " for element " + i); + } + } + out_print(tagstr + " " + valstr + "; // #" + i); + if (environment.printDetailsFlag) { + out_println(" at " + toHex(pos)); + } else { + environment.println(); + } + } + } finally { + out_end("}" + (environment.printDetailsFlag ? " // end of Constant Pool" : "")); + environment.println(); + } + } + + /** + * CONSTANT_Module_info { + * u1 tag; // == CONSTANT_MODULE(19) + * u2 name_index; + * } + * + * @return Constant Pool module name by name_index + */ + private String getModuleName() { + int idx = 0; + String name = ""; + for (int i = 1; i < types.length; i++) { + if (types[i] == CONSTANT_MODULE.getTag()) { + idx = i; + break; + } + } + if (idx != 0) { + try { + name = StringUtils.Utf8ToString(getNameByRefIndex(idx)); + } catch (Throwable ignored) { /* ignored*/ } + } + return name; + } + + private String getStringPos() { + return " at " + toHex(arrayInputStream.getPos()); + } + + private String getCommentPosCond() { + if (environment.printDetailsFlag) { + return " // " + getStringPos(); + } else { + return ""; + } + } + + private void decodeCPXAttr(DataInputStream in, int len, String attrname) throws IOException { + decodeCPXAttrM(in, len, attrname, 1); + } + + private void decodeCPXAttrM(DataInputStream in, int len, String attrName, int expectedIndices) throws IOException { + if (len != expectedIndices * 2) { + out_println("// == invalid length of " + attrName + " attr: " + len + " (should be " + (expectedIndices * 2) + ") =="); + printBytes(in, len, false, false); + } else { + StringBuilder outputString = new StringBuilder(); + for (int k = 1; k <= expectedIndices; k++) { + outputString.append("#").append(in.readUnsignedShort()).append("; "); + if (k % 16 == 0) { + out_println(outputString.toString().replaceAll("\\s+$", "")); + outputString = new StringBuilder(); + } + } + if (!outputString.isEmpty()) { + out_println(outputString.toString().replaceAll("\\s+$", "")); + } + } + } + + /** + * Reads from + * early_larval_frame { + * u1 frame_type = EARLY_LARVAL; // 246 + * u2 number_of_unset_fields; + * u2 unset_fields[number_of_unset_fields]; + * base_frame base; + * } + * the structure unset_fields[number_of_unset_fields] and returns its string presentation + * + * @param in input stream + * @return String presentation of the aggregation of [number_of_unset_fields] {unset_fields } + * @throws IOException if IO exception occurs + */ + private String getUnsetFields(DataInputStream in) throws IOException { + int num = in.readUnsignedShort(); + StringBuilder sb = new StringBuilder(20); + sb.append(startArray(num)).append('{'); + try { + for (int i = 0; i < num; i++) { + int cpIndex = in.readUnsignedShort(); // unset_field[i] + sb.append("#").append(cpIndex); + if (i < num - 1) { + sb.append("; "); + } + } + } finally { + sb.append('}'); + } + return sb.toString(); + } + + private String getStackMap(DataInputStream in, int elementsNum) throws IOException { + int num; + StringBuilder sb = new StringBuilder(20); + if (elementsNum > 0) { + num = elementsNum; + } else { + num = in.readUnsignedShort(); + } + sb.append(startArray(num)).append(elementsNum > 0 ? "z" : "").append('{'); + try { + for (int k = 0; k < num; k++) { + int maptype = in.readUnsignedByte(); + StackMap.VerificationType verificationType = StackMap.getVerificationType(maptype, + Optional.of((s, a) -> environment.printErrorLn(s, a))); + String maptypeImg; + if (environment.printDetailsFlag) { + maptypeImg = maptype + "b"; + } else { + try { + maptypeImg = verificationType.parseKey(); + } catch (ArrayIndexOutOfBoundsException e) { + maptypeImg = "/* BAD TYPE: */ " + maptype + "b"; + } + } + switch (verificationType) { + case ITEM_Object, ITEM_NewObject -> maptypeImg = maptypeImg + ",#" + in.readUnsignedShort(); + case ITEM_UNKNOWN -> maptypeImg = maptype + "b"; + default -> { + } + } + sb.append(maptypeImg); + if (k < num - 1) { + sb.append("; "); + } + } + } finally { + sb.append('}'); + } + return sb.toString(); + } + + /** + * Processes 4.7.20 The RuntimeVisibleTypeAnnotations Attribute, 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute + * type_annotation structure. + */ + private void decodeTargetTypeAndRefInfo(DataInputStream in) throws IOException { + int tt = in.readUnsignedByte(); // [4.7.20] annotations[], type_annotation { u1 target_type; ...} + ETargetType targetType = ETargetType.getTargetType(tt); + if (targetType == null) { + throw new Error("Type annotation: invalid target_type(u1) " + tt); + } + ETargetInfo targetInfo = targetType.targetInfo(); + out_println(toHex(tt, 1) + "; // target_type: " + targetType.parseKey()); + switch (targetInfo) { + case TYPEPARAM: //[3.3.1] meth_type_param, class_type_param: + out_println(toHex(in.readUnsignedByte(), 1) + "; // param_index"); + break; + case SUPERTYPE: //[3.3.2] class_exts_impls + out_println(toHex(in.readUnsignedShort(), 2) + "; // type_index"); + break; + case TYPEPARAM_BOUND: //[3.3.3] class_type_param_bnds, meth_type_param_bnds + out_println(toHex(in.readUnsignedByte(), 1) + "; // param_index"); + out_println(toHex(in.readUnsignedByte(), 1) + "; // bound_index"); + break; + case EMPTY: //[3.3.4] meth_receiver, meth_ret_type, field + // NOTE: reference_info is empty for this annotation's target + break; + case METHODPARAM: //[3.3.5] meth_formal_param: + out_println(toHex(in.readUnsignedByte(), 1) + "; // parameter_index"); + break; + case EXCEPTION: //[3.3.61] throws_type + //KTL: Updated index to UShort for JSR308 change + out_println(in.readUnsignedShort() + "; // type_index"); + break; + case LOCALVAR: //[3.3.7] local_var, resource_var + { + int lv_num = in.readUnsignedShort(); + startArrayCmt(lv_num, "local_variables"); + try { + for (int i = 0; i < lv_num; i++) { + out_println(in.readUnsignedShort() + " " + in.readUnsignedShort() + + " " + in.readUnsignedShort() + ";" + getCommentPosCond()); + } + } finally { + out_end("}"); + } + } + break; + case CATCH: //[3.3.8] exception_param + out_println(in.readUnsignedShort() + "; // exception_table_index"); + break; + case OFFSET: //[3.3.9] type_test (instanceof), obj_creat (new) + // constr_ref_receiver, meth_ref_receiver + out_println(in.readUnsignedShort() + "; // offset"); + break; + case TYPEARG: //[3.3.10] cast, constr_ref_typearg, meth_invoc_typearg + // constr_invoc_typearg, meth_ref_typearg + out_println(in.readUnsignedShort() + "; // offset"); + out_println(toHex(in.readUnsignedByte(), 1) + "; // type_index"); + break; + default: // should never happen + out_println(toHex(tt, 1) + "; // invalid target_info: " + tt); + throw new ClassFormatError(); + } + // [4.7.20.2] + int path_length = in.readUnsignedByte(); // type_path { u1 path_length; ...} + startArrayCmtB(path_length, "type_paths"); + try { + for (int i = 0; i < path_length; i++) { + // print the type_path elements + out_println("{ " + toHex(in.readUnsignedByte(), 1) // { u1 type_path_kind; + + "; " + toHex(in.readUnsignedByte(), 1) // u1 type_argument_index; } + + "; } // type_path[" + i + "]"); // path[i] + } + } finally { + out_end("}"); + } + } + + private void decodeElementValue(DataInputStream in, ToolOutput out) throws IOException { + out_begin("{ // element_value"); + try { + char tg = (char) in.readByte(); + AnnotationElementType tag = getAnnotationElementType(tg); + if (tag != AE_UNKNOWN) { + out_println("'" + tg + "';"); + } + switch (tag) { + case AE_BYTE, AE_CHAR, AE_DOUBLE, AE_FLOAT, + AE_INT, AE_LONG, AE_SHORT, AE_BOOLEAN, + AE_STRING -> decodeCPXAttr(in, 2, "const_value_index"); + case AE_ENUM -> { + out_begin("{ // enum_const_value"); + decodeCPXAttr(in, 2, "type_name_index"); + decodeCPXAttr(in, 2, "const_name_index"); + out_end("} // enum_const_value"); + } + case AE_CLASS -> decodeCPXAttr(in, 2, "class_info_index"); + case AE_ANNOTATION -> decodeAnnotation(in, out); + case AE_ARRAY -> { + int ev_num = in.readUnsignedShort(); + startArrayCmt(ev_num, "array_value"); + try { + for (int i = 0; i < ev_num; i++) { + decodeElementValue(in, out); + if (i < ev_num - 1) { + out_println(";"); + } + } + } finally { + out_end("} // array_value"); + } + } + case AE_UNKNOWN -> { + String msg = "invalid element_value" + + (StringUtils.isPrintableChar(tg) ? " tag type : " + tg : "??"); + out_println(toHex(tg, 1) + "; // " + msg); + throw new ClassFormatError(msg); + } + } + } finally { + out_end("} // element_value"); + } + } + + private void decodeAnnotation(DataInputStream in, ToolOutput out) throws IOException { + out_begin("{ // annotation"); + try { + decodeCPXAttr(in, 2, "field descriptor"); + int evp_num = in.readUnsignedShort(); + decodeElementValuePairs(evp_num, in, out); + } finally { + out_end("} // annotation"); + } + } + + private void decodeElementValuePairs(int count, DataInputStream in, ToolOutput out) throws IOException { + startArrayCmt(count, "element_value_pairs"); + try { + for (int i = 0; i < count; i++) { + out_begin("{ // element value pair"); + try { + decodeCPXAttr(in, 2, "name of the annotation type element"); + decodeElementValue(in, out); + } finally { + out_end("} // element value pair"); + if (i < count - 1) { + out_println(";"); + } + } + } + } finally { + out_end("} // element_value_pairs"); + } + } + + /** + * component_info { JEP 359 Record(Preview): class file 58.65535 + * u2 name_index; + * u2 descriptor_index; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + * } + *

+ * or + * field_info { + * u2 access_flags; + * u2 name_index; + * u2 descriptor_index; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + * } + * or + * method_info { + * u2 access_flags; + * u2 name_index; + * u2 descriptor_index; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + * } + */ + private void decodeInfo(DataInputStream in, ToolOutput out, String elementName, boolean hasAccessFlag) throws IOException { + out_begin("{ // " + elementName + (environment.printDetailsFlag ? getStringPos() : "")); + try { + if (hasAccessFlag) { + // u2 access_flags; + out_println(toHex(in.readShort(), 2) + "; // access"); + } + // u2 name_index + printUtf8InfoIndex(in.readUnsignedShort(), "name_index"); + // u2 descriptor_index + printUtf8InfoIndex(in.readUnsignedShort(), "descriptor_index"); + // u2 attributes_count; + // attribute_info attributes[attributes_count] + decodeAttrs(in, out); + } finally { + out_end("}"); + } + } + + private void decodeTypeAnnotation(DataInputStream in, ToolOutput out) throws IOException { + out_begin("{ // type_annotation"); + try { + decodeTargetTypeAndRefInfo(in); + decodeCPXAttr(in, 2, "field descriptor"); + int evp_num = in.readUnsignedShort(); + decodeElementValuePairs(evp_num, in, out); + } finally { + out_end("} // type_annotation"); + } + } + + private void decodeBootstrapMethod(DataInputStream in) throws IOException { + out_begin("{ // bootstrap_method"); + try { + out_println("#" + in.readUnsignedShort() + "; // bootstrap_method_ref"); + int bm_args_cnt = in.readUnsignedShort(); + startArrayCmt(bm_args_cnt, "bootstrap_arguments"); + try { + for (int i = 0; i < bm_args_cnt; i++) { + out_println("#" + in.readUnsignedShort() + ";" + getCommentPosCond()); + } + } finally { + out_end("} // bootstrap_arguments"); + } + } finally { + out_end("} // bootstrap_method"); + } + } + + private void decodeAttr(DataInputStream in, ToolOutput out) throws IOException { + // Read one attribute + String posComment = getStringPos(); + int name_cpx = 0, btag, len; + + String AttrName = ""; + try { + name_cpx = in.readUnsignedShort(); + btag = types[name_cpx]; + ConstType tag = getByTag(btag); + + if (tag == ConstType.CONSTANT_UTF8) { + AttrName = getStringByIndex(name_cpx); + } + } catch (ArrayIndexOutOfBoundsException ignored) { + environment.print(getOutString("")); + environment.println("// == %s ==", sharedI18n.getString("main.error.wrong.bytes")); + } + EAttribute tg = EAttribute.get(AttrName); + String endingComment = AttrName.isEmpty() ? "#" + name_cpx : AttrName; + len = in.readInt(); + arrayInputStream.enter(len); + try { + if (environment.printDetailsFlag) { + out_begin("Attr(#" + name_cpx + ", " + len + ") { // " + endingComment + posComment); + } else { + out_begin("Attr(#" + name_cpx + ") { // " + endingComment); + } + + switch (tg) { + case ATT_Code -> { + out_println(in.readUnsignedShort() + "; // max_stack"); + out_println(in.readUnsignedShort() + "; // max_locals"); + int code_len = in.readInt(); + out_begin("Bytes" + startArray(code_len) + "{"); + try { + printBytes(in, code_len, true, false); + } finally { + out_end("}"); + } + int trap_num = in.readUnsignedShort(); + /* + { u2 start_pc; + u2 end_pc; + u2 handler_pc; + u2 catch_type; + } exception_table[exception_table_length]; + */ + startArrayCmt(trap_num, "Traps"); + try { + for (int i = 0; i < trap_num; i++) { + out_println( + "%4d %4d %4d %3d;".formatted(in.readUnsignedShort(), + in.readUnsignedShort(), + in.readUnsignedShort(), + in.readUnsignedShort()) + getCommentPosCond()); + } + } finally { + out_end("} // end of Traps"); + } + // Read the attributes + decodeAttrs(in, out); + } + case ATT_Exceptions -> { + int count = in.readUnsignedShort(); + startArrayCmt(count, AttrName); + try { + for (int i = 0; i < count; i++) { + out_println("#" + in.readUnsignedShort() + ";" + + getCommentPosCond()); + } + } finally { + out_end("}"); + } + } + case ATT_LineNumberTable -> { + int ll_num = in.readUnsignedShort(); + startArrayCmt(ll_num, "line_number_table"); + try { + for (int i = 0; i < ll_num; i++) { + out_println( + "%4d %4d;".formatted(in.readUnsignedShort(), in.readUnsignedShort()) + + getCommentPosCond()); + } + } finally { + out_end("}"); + } + } + case ATT_LocalVariableTable, ATT_LocalVariableTypeTable -> { + int lvt_num = in.readUnsignedShort(); + startArrayCmt(lvt_num, AttrName); + try { + for (int i = 0; i < lvt_num; i++) { + out_println( + "%4d %4d %4d %4d %3d;".formatted(in.readUnsignedShort(), + in.readUnsignedShort(), in.readUnsignedShort(), + in.readUnsignedShort(), in.readUnsignedShort()) + + getCommentPosCond()); + } + } finally { + out_end("}"); + } + } + case ATT_InnerClasses -> { + int ic_num = in.readUnsignedShort(); + startArrayCmt(ic_num, "classes"); + try { + for (int i = 0; i < ic_num; i++) { + int inner_class_info_index = in.readUnsignedShort(); + int outer_class_info_index = in.readUnsignedShort(); + int inner_name_index = in.readUnsignedShort(); + int inner_class_access_flags = in.readUnsignedShort(); + out_println("%5s %5s %5s %3s;".formatted( + "#" + inner_class_info_index, + "#" + outer_class_info_index, + "#" + inner_name_index, + "" + inner_class_access_flags) + + getInnerClassComment(inner_class_access_flags)); + } + } finally { + out_end("}"); + } + } + case ATT_StackMap -> { + int e_num = in.readUnsignedShort(); + startArrayCmt(e_num, ""); + try { + for (int k = 0; k < e_num; k++) { + int start_pc = in.readUnsignedShort(); + environment.println(format("%d, %s, %s;", start_pc, + getStackMap(in, 0), getStackMap(in, 0))); + } + } finally { + out_end("}"); + } + } + case ATT_StackMapTable -> { + int wrappingLevel = 0; + int et_num = in.readUnsignedShort(); + startArrayCmt(et_num, ""); + try { + int idx = 0; // wrapper (early_larval_frame) is skipped. + while (idx < et_num) { + int frame_type = in.readUnsignedByte(); + StackMap.EntryType ftype = StackMap.stackMapEntryType(frame_type); + String indentString = (wrappingLevel > 0) ? INDENT_STRING.repeat(min(wrappingLevel, 4)) : ""; + + switch (ftype) { + case SAME_FRAME -> { + // entryType is same_frame; + out_println(indentString.concat(frame_type + "b; // same_frame")); + wrappingLevel = checkWrapping(wrappingLevel); + } + case SAME_LOCALS_1_STACK_ITEM_FRAME -> { + // entryType is same_locals_1_stack_item_frame + // read additional single stack element + out_println(indentString.concat(format("%db, %s; // same_locals_1_stack_item_frame", + frame_type, getStackMap(in, 1)))); + wrappingLevel = checkWrapping(wrappingLevel); + } + case EARLY_LARVAL -> { + // entryType is early_larval_frame + out_println(indentString.concat(format("%db, %s, { // early_larval_frame", + frame_type, getUnsetFields(in)))); + wrappingLevel++; + continue; // skip idx increasing + } + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED -> { + // entryType is same_locals_1_stack_item_frame_extended + // read additional single stack element + int noffset = in.readUnsignedShort(); + out_println(indentString.concat(format("%db, %d, %s; // same_locals_1_stack_item_frame_extended", + frame_type, noffset, getStackMap(in, 1)))); + wrappingLevel = checkWrapping(wrappingLevel); + } + case CHOP_1_FRAME, CHOP_2_FRAME, CHOP_3_FRAME -> { + // entryType is chop_frame + int coffset = in.readUnsignedShort(); + out_println(indentString.concat(format("%db, %d; // chop_frame %d", + frame_type, coffset, 251 - frame_type))); + wrappingLevel = checkWrapping(wrappingLevel); + } + case SAME_FRAME_EXTENDED -> { + // entryType is same_frame_extended; + int xoffset = in.readUnsignedShort(); + out_println(indentString.concat(format("%db, %d; // same_frame_extended", + frame_type, xoffset))); + wrappingLevel = checkWrapping(wrappingLevel); + } + case APPEND_FRAME -> { + // entryType is append_frame + // read additional locals + int aoffset = in.readUnsignedShort(); + out_println(indentString.concat(format("%db, %d, %s; // append_frame %d", + frame_type, aoffset, + getStackMap(in, frame_type - 251), frame_type - 251))); + wrappingLevel = checkWrapping(wrappingLevel); + } + case FULL_FRAME -> { + // entryType is full_frame + int foffset = in.readUnsignedShort(); + out_println(indentString.concat(format("%db, %d, %s, %s; // full_frame", frame_type, foffset, + getStackMap(in, 0), getStackMap(in, 0)))); + wrappingLevel = checkWrapping(wrappingLevel); + } + } + idx++; + } + } finally { + out_end("}"); + } + } + case ATT_EnclosingMethod -> decodeCPXAttrM(in, len, AttrName, 2); + case ATT_AnnotationDefault -> decodeElementValue(in, out); + case ATT_RuntimeInvisibleAnnotations, ATT_RuntimeVisibleAnnotations -> { + int an_num = in.readUnsignedShort(); + startArrayCmt(an_num, "annotations"); + try { + for (int i = 0; i < an_num; i++) { + decodeAnnotation(in, out); + if (i < an_num - 1) { + out_println(";"); + } + } + } finally { + out_end("}"); + } + } + // 4.7.20 The RuntimeVisibleTypeAnnotations Attribute + // 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute + case ATT_RuntimeInvisibleTypeAnnotations, ATT_RuntimeVisibleTypeAnnotations -> { + int ant_num = in.readUnsignedShort(); + startArrayCmt(ant_num, "annotations"); + try { + for (int i = 0; i < ant_num; i++) { + decodeTypeAnnotation(in, out); + if (i < ant_num - 1) { + out_println(";"); + } + } + } finally { + out_end("}"); + } + } + case ATT_RuntimeInvisibleParameterAnnotations, ATT_RuntimeVisibleParameterAnnotations -> { + int pm_num = in.readUnsignedByte(); + startArrayCmtB(pm_num, "parameters"); + try { + for (int k = 0; k < pm_num; k++) { + int anp_num = in.readUnsignedShort(); + startArrayCmt(anp_num, "annotations"); + try { + for (int i = 0; i < anp_num; i++) { + decodeAnnotation(in, out); + if (k < anp_num - 1) { + out_println(";"); + } + } + } finally { + out_end("}"); + } + if (k < pm_num - 1) { + out_println(";"); + } + } + } finally { + out_end("}"); + } + } + case ATT_BootstrapMethods -> { + int bm_num = in.readUnsignedShort(); + startArrayCmt(bm_num, "bootstrap_methods"); + try { + for (int i = 0; i < bm_num; i++) { + decodeBootstrapMethod(in); + if (i < bm_num - 1) { + out_println(";"); + } + } + } finally { + out_end("}"); + } + } + case ATT_Module -> decodeModule(in); + case ATT_TargetPlatform -> decodeCPXAttrM(in, len, AttrName, 3); + case ATT_ModulePackages -> { + int p_num = in.readUnsignedShort(); + startArrayCmt(p_num, null); + try { + decodeCPXAttrM(in, len - 2, AttrName, p_num); + } finally { + out_end("}"); + } + } + // MethodParameters_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u1 parameters_count; + // { u2 name_index; + // u2 access_flags; + // } parameters[parameters_count]; + // } + case ATT_MethodParameters -> { + int pcount = in.readUnsignedByte(); + startArrayCmtB(pcount, AttrName); + try { + for (int i = 0; i < pcount; i++) { + out_println("#" + in.readUnsignedShort() + " " + + toHex(in.readUnsignedShort(), 2) + ";" + + getCommentPosCond()); + } + } finally { + out_end("}"); + } + } + // JEP 359 Record(Preview): class file 58.65535 + // Record_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 components_count; + // component_info components[components_count]; + // } + case ATT_Record -> { + int ncomps = in.readUnsignedShort(); + startArrayCmt(ncomps, "components"); + try { + for (int i = 0; i < ncomps; i++) { + decodeInfo(in, out, "component", false); + if (i < ncomps - 1) { + out_println(";"); + } + } + } finally { + out_end("}"); + } + } + case ATT_ConstantValue, ATT_Signature, ATT_SourceFile -> decodeCPXAttr(in, len, AttrName); + + // JEP 181 (Nest-based Access Control): class file 55.0 + // NestHost_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 host_class_index; + // } + case ATT_NestHost -> decodeTypes(in, 1, "class"); + + // JEP 181 (Nest-based Access Control): class file 55.0 + // NestMembers_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 number_of_classes; + // u2 classes[number_of_classes]; + // } + // JEP 360 (Sealed types): class file 59.65535 + // PermittedSubclasses_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 number_of_classes; + // u2 classes[number_of_classes]; + // } + case ATT_NestMembers -> { + int nsubtypes = in.readUnsignedShort(); + startArrayCmt(nsubtypes, "classes"); + try { + decodeTypes(in, nsubtypes, "class"); + } finally { + out_end("}"); + } + } + case ATT_PermittedSubclasses -> { + int nsubtypes = in.readUnsignedShort(); + startArrayCmt(nsubtypes, "subclasses"); + try { + decodeTypes(in, nsubtypes, "subclass"); + } finally { + out_end("}"); + } + } + // Valhalla: + // + // LoadableDescriptors_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 number_of_descriptors; + // u2 descriptors[number_of_descriptors]; + // } + case ATT_LoadableDescriptors -> { + int nsubtypes = in.readUnsignedShort(); + startArrayCmt(nsubtypes, "Utf8"); + try { + decodeTypes(in, nsubtypes, "descriptor"); + } finally { + out_end("}"); + } + } + // SourceDebugExtension_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u1 debug_extension[attribute_length]; + // } + case ATT_SourceDebugExtension -> { + printUtf8String(in, len); + endingComment = "Attr(#" + name_cpx + ")"; + } + default -> { + printBytes(in, len, true, false); + endingComment = "Attr(#" + name_cpx + ")"; + } + } + } catch (EOFException e) { + environment.println(getOutString("") + "// == The unexpected end of attribute array while parsing. =="); + } finally { + int rest = arrayInputStream.available(); + if (rest > 0) { + environment.println(getOutString("") + + "// == The attribute array started at" + posComment + " has " + rest + " bytes more than expected. =="); + printBytes(in, rest, true, true); + } + out_end("} // end of " + endingComment); + arrayInputStream.leave(); + } + } + + private void decodeModuleStatement(String statementName, DataInputStream in) throws IOException { + int index, nFlags; + String sComment; + // u2 {exports|opens}_count + int count = in.readUnsignedShort(); + startArrayCmt(count, statementName); + try { + for (int i = 0; i < count; i++) { + // u2 {exports|opens}_index; u2 {exports|opens}_flags + index = in.readUnsignedShort(); + nFlags = in.readUnsignedShort(); + sComment = environment.printDetailsFlag ? format(" // [ %s ]", EModifier.asNames(nFlags, MODULE_DIRECTIVES)) : ""; + out_println(format("#%d %s%s", index, toHex(nFlags, 2), sComment)); + int exports_to_count = in.readUnsignedShort(); + startArrayCmt(exports_to_count, null); + try { + for (int j = 0; j < exports_to_count; j++) { + out_println("#" + in.readUnsignedShort() + ";"); + } + } finally { + out_end("};"); + } + } + } finally { + out_end("} // of " + statementName); + environment.println(); + } + } + + private void decodeModule(DataInputStream in) throws IOException { + int nFlags; + String sComment; + //u2 module_name_index + int index = in.readUnsignedShort(); + out_print("#" + index + "; // "); + if (environment.printDetailsFlag) { + environment.println(format("%-16s", "name_index")); + } else { + environment.println("name_index"); + } + + // u2 module_flags + int moduleFlags = in.readUnsignedShort(); + out_println(format("%s; //flags%s", + toHex(moduleFlags, 2), environment.printDetailsFlag ? EModifier.asNames(moduleFlags, MODULE_DIRECTIVES) + " " : "")); + environment.println(); + + //u2 module_version + int versionIndex = in.readUnsignedShort(); + out_println("#" + versionIndex + "; // version"); + + // u2 requires_count + int count = in.readUnsignedShort(); + startArrayCmt(count, "requires"); + try { + for (int i = 0; i < count; i++) { + // u2 requires_index; u2 requires_flags; u2 requires_version_index + index = in.readUnsignedShort(); + nFlags = in.readUnsignedShort(); + versionIndex = in.readUnsignedShort(); + sComment = environment.printDetailsFlag ? format(" // %s", EModifier.asNames(nFlags, MODULE_DIRECTIVES)) : ""; + out_println(format("#%d %s #%d;%s", index, toHex(nFlags, 2), versionIndex, sComment)); + } + } finally { + out_end("} // end of requires"); + environment.println(); + } + + decodeModuleStatement("exports", in); + + decodeModuleStatement("opens", in); + // u2 uses_count + count = in.readUnsignedShort(); + startArrayCmt(count, "uses"); + try { + for (int i = 0; i < count; i++) { + // u2 uses_index + out_println("#" + in.readUnsignedShort() + ";"); + } + } finally { + out_end("} // end of uses"); + environment.println(); + } + count = in.readUnsignedShort(); // u2 provides_count + startArrayCmt(count, "provides"); + try { + for (int i = 0; i < count; i++) { + // u2 provides_index + out_println("#" + in.readUnsignedShort()); + int provides_with_count = in.readUnsignedShort(); + // u2 provides_with_count + startArrayCmt(provides_with_count, null); + try { + for (int j = 0; j < provides_with_count; j++) { + // u2 provides_with_index; + out_println("#" + in.readUnsignedShort() + ";"); + } + } finally { + out_end("};"); + } + } + } finally { + out_end("} // end of provides"); + environment.println(); + } + } + + private void decodeAttrs(DataInputStream in, ToolOutput out) throws IOException { + // Read the attributes + int attr_num = in.readUnsignedShort(); + startArrayCmt(attr_num, "Attributes"); + try { + for (int i = 0; i < attr_num; i++) { + decodeAttr(in, out); + if (i + 1 < attr_num) { + out_println(";"); + } + } + } finally { + out_end("} // end of Attributes"); + } + } + + private void decodeMembers(DataInputStream in, ToolOutput out, String groupName, String elementName) throws IOException { + int count = in.readUnsignedShort(); + environment.traceln(groupName + "=" + count); + startArrayCmt(count, groupName); + try { + for (int i = 0; i < count; i++) { + decodeInfo(in, out, elementName, true); + if (i + 1 < count) { + out_println(";"); + } + } + } finally { + out_end("} // end of " + groupName); + environment.println(); + } + } + + String getInnerClassComment(int inner_class_access_flags) { + StringBuilder sb = new StringBuilder(); + if (environment.printDetailsFlag) { + sb.append("// access [ ").append(EModifier.asNames(inner_class_access_flags, ClassFileContext.INNER_CLASS)).append(" ]"); + } + return sb.toString(); + } + + void decodeClass() throws IOException { + boolean printingStarted = false; + // Read the header + try { + int magic = inputStream.readInt(); + int min_version = inputStream.readUnsignedShort(); + int version = inputStream.readUnsignedShort(); + ByteBuffer byteBuffer = ByteBuffer.allocate(8).putInt(magic). + putShort((short) min_version). + putShort((short) version); + + // Read the constant pool + readCP(byteBuffer.array(), inputStream); + short access = inputStream.readShort(); // don't care about sign + int this_cpx = inputStream.readUnsignedShort(); + + try { + entityName = (String) cpool[(Integer) cpool[this_cpx]]; + if (entityName.equals("module-info")) { + entityType = "module"; + entityName = getModuleName(); + } else { + entityType = "class"; + } + environment.getToolOutput().startClass(entityName, Optional.of(".jcod"), environment); + if (!entityName.isEmpty() && (JcodTokens.keyword_token_ident(entityName) != IDENT || + JcodTokens.getConstTagByParseString(entityName) != -1)) { + // JCod can't parse a entityName matching a keyword or a constant value, + // then use the filename instead: + out_begin(format("file \"%s.class\" {", entityName)); + } else { + if (entityName.startsWith(ERROR_PREFIX)) + out_begin(format("%s { %s", entityType, entityName)); + else + out_begin(format("%s %s {", entityType, entityName)); + } + printingStarted = true; + } catch (Exception e) { + entityName = environment.getToolInput().getName(); + environment.println("// " + e.getMessage() + " while accessing entityName"); + out_begin(format("%s %s { // source file name", entityType, entityName)); + printingStarted = true; + } + + if (magic != JAVA_MAGIC) { + out_println(toHex(magic, 4) + "; // wrong magic: " + toHex(JAVA_MAGIC, 4) + " expected"); + } else { + out_println(toHex(magic, 4) + ";"); + + } + out_println(min_version + "; // minor version"); + out_println(version + "; // version"); + + if (CFVersion.isValueObjectContext(version, min_version)) { + EModifier.setGlobalContext(VALUE_OBJECTS); + } + + // Print the constant pool + printCP(); + out_println(toHex(access, 2) + "; // access" + + (environment.printDetailsFlag ? " [ " + EModifier.asNames(access, ClassFileContext.CLASS) + " ]" : "")); + out_println("#" + this_cpx + "; // this_cpx"); + int super_cpx = inputStream.readUnsignedShort(); + out_println("#" + super_cpx + "; // super_cpx"); + environment.traceln("jdec.trace.access_thisCpx_superCpx", access, this_cpx, super_cpx); + environment.println(); + + // Read the interfaces + int numinterfaces = inputStream.readUnsignedShort(); + environment.traceln("jdec.trace.numinterfaces", numinterfaces); + startArrayCmt(numinterfaces, "Interfaces"); + try { + decodeTypes(inputStream, numinterfaces, "interface"); + } finally { + out_end("} // end of Interfaces"); + environment.println(); + } + // Read the fields + decodeMembers(inputStream, environment.getToolOutput(), "Fields", "field"); + + // Read the methods + decodeMembers(inputStream, environment.getToolOutput(), "Methods", "method"); + + // Read the attributes + decodeAttrs(inputStream, environment.getToolOutput()); + } catch (EOFException ignored) { + } catch (ClassFormatError err) { + String msg = err.getMessage(); + environment.println(INDENT_STRING + "// ClassFormatError" + (msg == null || msg.isEmpty() ? "" : ": " + msg)); + printRestOfBytes(); + printingStarted = true; + throw err; + } finally { + if (printingStarted) { + if (environment.printDetailsFlag && (!entityName.isBlank() || !entityType.isBlank())) { + out_end(format("} // end of %s %s", entityType, entityName)); + } else { + out_end("}"); + } + } + environment.getToolOutput().finishClass(entityName); + } + } // end decodeClass() + + private int checkWrapping(int wrappingLevel) { + if (wrappingLevel > 0) { + for (int i = wrappingLevel - 1; i >= 0; i--) { + out_println(INDENT_STRING.repeat(i).concat("};")); + } + } + return 0; + } + + private void decodeTypes(DataInputStream in, int count, String typeName) throws IOException { + for (int i = 0; i < count; i++) { + int type_cpx = in.readUnsignedShort(); + environment.traceln("jdec.trace.type", i, type_cpx); + String s = "#" + type_cpx + ";"; + if (environment.printDetailsFlag) { + Object cpObj = cpool[type_cpx]; + String name; + if (cpObj instanceof Integer index) { + name = "%s: %s".formatted(typeName, getStringByIndex(index)); + } else { + name = "%s: %s".formatted(typeName, cpObj); + } + out_println(s + " // " + name + getStringPos()); + } else { + out_println(s); + } + } + } + + private String getStringByIndex(int idx) { + Object obj = cpool[idx]; + if (obj instanceof String str) { + return str; + } else { + return "%s #%d refers to a ConstantPool Object: %s". + formatted(ERROR_PREFIX, idx, String.valueOf(obj)); + } + } + + private String getNameByRefIndex(int idx) { + Object obj = cpool[idx]; + if (obj instanceof Integer ref) { + return getStringByIndex(ref); + } else { + return "%s #%d refers to a ConstantPool Object: %s". + formatted(ERROR_PREFIX, idx, String.valueOf(obj)); + } + + } + + private String formatComments(String str, int shift) { + String[] pair = str.split("//"); + int len = pair.length; + if (len < 2) { + return str; + } + String s = pair[0]; + for (int i = 1; i <= len - 2; i++) { + s = s.concat("//").concat(pair[i]); + } + return s + repeat(" ", COMMENT_OFFSET - s.length() - shift * INDENT_LENGTH) + " // " + pair[len - 1].trim(); + } +}// end class ClassData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecEnvironment.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecEnvironment.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecEnvironment.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecEnvironment.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdec; + +import org.openjdk.asmtools.common.DecompilerLogger; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import static java.lang.String.format; + +public class JdecEnvironment extends Environment { + + protected boolean printDetailsFlag; + + // Output stream or files or custom Strings + private final ToolOutput toolOutput; + + /** + * @param builder the jdec environment builder + */ + private JdecEnvironment(Builder builder) { + super(builder); + this.toolOutput = builder.toolOutput; + } + + @Override + public void printErrorLn(String format, Object... args) { + getLogger().printErrorLn(format, args); + } + + public Environment setPrintDetailsFlag(boolean value) { + this.printDetailsFlag = value; + return this; + } + + @Override + public void println(String format, Object... args) { + getToolOutput().printlns((args == null || args.length == 0) ? format : format(format, args)); + } + + @Override + public void println() { + getToolOutput().printlns(""); + } + + @Override + public void print(String format, Object... args) { + getToolOutput().prints((args == null || args.length == 0) ? format : format(format, args)); + } + + @Override + public void print(char ch) { + getToolOutput().prints(ch); + } + + static class JDecBuilder extends Builder { + + public JDecBuilder(ToolOutput toolOutput, DualStreamToolOutput log) { + super(toolOutput, new DecompilerLogger("jdec", JdecEnvironment.class, log)); + } + + @Override + public JdecEnvironment build() { + return new JdecEnvironment(this); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecTool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecTool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecTool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/JdecTool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdec; + +import org.openjdk.asmtools.common.Decoder; +import org.openjdk.asmtools.common.outputs.EscapedPrintStreamOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; + +import java.io.PrintStream; + +public abstract class JdecTool extends Decoder { + + protected JdecTool(ToolOutput toolOutput, DualStreamToolOutput log) { + super(toolOutput, log); + } + + protected JdecTool(ToolOutput toolOutput) { + super(toolOutput, new StderrLog()); + } + + protected JdecTool(PrintStream toolOutput) { + this(new EscapedPrintStreamOutput(toolOutput)); + } + + @Override + public JdecEnvironment getEnvironment(ToolOutput toolOutput, DualStreamToolOutput log) { + JdecEnvironment.JDecBuilder builder = new JdecEnvironment.JDecBuilder(toolOutput, log); + return builder.build(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/Main.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/Main.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/Main.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/Main.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdec; + +import org.openjdk.asmtools.common.inputs.FileInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.EscapedPrintStreamOutput; +import org.openjdk.asmtools.common.outputs.StdoutOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualOutputStreamOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import static org.openjdk.asmtools.Main.*; +import static org.openjdk.asmtools.common.Environment.FAILED; +import static org.openjdk.asmtools.common.Environment.OK; +import static org.openjdk.asmtools.common.outputs.FSOutput.FSDestination.DIR; +import static org.openjdk.asmtools.util.ProductInfo.FULL_VERSION; + +/** + * jdec is a disassembler that accepts a .class file, and prints the plain-text translation of jcod source file + * to the standard output. + *

+ * Main program of the Java DECoder :: class to jcod + */ +public class Main extends JdecTool { + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput... toolInputs) { + super(toolOutput, log); + Collections.addAll(fileList, toolInputs); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput, String... argv) { + super(toolOutput, log); + if (toolInput != null) { + fileList.add(toolInput); + } + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, String... argv) { + this(toolOutput, log, null, argv); + } + + public Main(EscapedPrintStreamOutput toolOutput, String[] argv) { + this(toolOutput, new StderrLog(), argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput) { + super(toolOutput, log); + fileList.add(toolInput); + } + + // jdec entry point + public static void main(String... argv) { + Main decoder = new Main(new StdoutOutput(), argv); + System.exit(decoder.decode()); + } + + @Override + public void usage() { + environment.usage(List.of( + "info.usage", + "info.opt.d", + "info.opt.w", + "info.opt.g", + "info.opt.v", + "info.opt.version")); + } + + @Override + protected void parseArgs(String... argv) { + // Parse arguments + for (int i = 0; i < argv.length; i++) { + String arg = argv[i]; + switch (arg) { + case "-g": + setPrintDetails(true); + break; + case "-v": + environment.setVerboseFlag(true); + break; + case "-t": + environment.setVerboseFlag(true); + environment.setTraceFlag(true); + break; + case WRITE_SWITCH: // -w + environment.setIgnorePackage(true); + setFSDestination(DIR, ++i, argv); + break; + case DIR_SWITCH: + setFSDestination(DIR, ++i, argv); + break; + case DUAL_LOG_SWITCH: + this.environment.setOutputs(new DualOutputStreamOutput()); + break; + case VERSION_SWITCH: + environment.println(FULL_VERSION); + System.exit(OK); + case "-h", "-help": + usage(); + System.exit(OK); + case STDIN_SWITCH: + addStdIn(); + break; + default: + if (arg.startsWith("-")) { + environment.error("err.invalid_option", arg); + usage(); + System.exit(FAILED); + } else { + fileList.add(new FileInput(arg)); + } + } + } + if (fileList.isEmpty()) { + usage(); + System.exit(FAILED); + } + } + + public void setPrintDetails(boolean value) { + environment.setPrintDetailsFlag(value); + } + + /** + * Runs the decoder + */ + @Override + public synchronized int decode() { + int rc = OK; + for (ToolInput toolInput : fileList) { + try { + environment.setToolInput(toolInput); + ClassData classData = new ClassData(environment); + classData.decodeClass(); + environment.getOutputs().flush(); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + environment.getLogger().flush(); + continue; + } catch (FileNotFoundException fnf) { + environment.printException(fnf); + environment.error("err.not_found", toolInput); + rc = FAILED; + } catch (IOException | ClassFormatError ioe) { + environment.error(ioe); + environment.printException(ioe); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + } catch (Error error) { + environment.error(error); + environment.printException(error); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + } catch (Exception ex) { + environment.error(ex); + environment.printException(ex); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + } + environment.getLogger().flush(); + break; + } + return rc; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/NestedByteArrayInputStream.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/NestedByteArrayInputStream.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/NestedByteArrayInputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/NestedByteArrayInputStream.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdec; + +import java.io.ByteArrayInputStream; +import java.util.Stack; + +/** + * this class provides functionality needed to read class files: + *

+ */ +public class NestedByteArrayInputStream extends ByteArrayInputStream { + + NestedByteArrayInputStream(byte buf[]) { + super(buf); + } + + NestedByteArrayInputStream(byte buf[], int offset, int length) { + super(buf, offset, length); + } + + public int getPos() { + return pos; + } + Stack savedStates = new Stack(); + + public void enter(int range) { + savedStates.push(count); + if (pos + range < count) { + count = pos + range; + } + } + + public void leave() { + pos = count; + count = ((Integer) savedStates.pop()).intValue(); + } +} // end class NestedByteArrayInputStream + diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/i18n.properties jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/i18n.properties --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/i18n.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdec/i18n.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +info.usage=\ +Usage: java -jar asmtools.jar jdec [options] |- decompile into jcod file(s)\n\ +\ if - is provided, is used\n\ +where possible options include: +# see also shared section in asmtools/i18 +info.opt.g=\ +\ -g Generate a detailed output format + +err.invalid_option=Invalid option: {0} +err.not_found=No such file: {0} +err.count.issues={0}{1}in the file: {2} +err.file.empty=The file is empty: {0} +jdec.trace.CP_len=CP len= {0} +jdec.trace.CP_entry=CP entry # {0} tag= {1} +jdec.trace.access_thisCpx_superCpx=access={0} this_cpx={1} super_cpx={2} +jdec.trace.numinterfaces=numinterfaces={0} +jdec.trace.type=type_cpx[{0}]={1} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.stream.Collectors; + +import static org.openjdk.asmtools.jdis.MemberData.AnnotationElementState.*; + +public class AnnotationData extends MemberData { + protected String visibleAnnotationToken = "@+"; + protected String invisibleAnnotationToken = "@-"; + protected String dataName = "AnnotationData"; + private final ArrayList annotationElements = new ArrayList<>(); + + private int type_cpx = 0; //an index into the constant pool indicating the annotation type for this annotation. + private final boolean invisible; + + public AnnotationData(T data, boolean invisible) { + super(data); + this.invisible = invisible; + } + + public void read(DataInputStream in) throws IOException { + type_cpx = in.readShort(); + int elemValueLength = in.readShort(); + for (int i = 0; i < elemValueLength; i++) { + AnnotationElement elem = new AnnotationElement(data); + elem.read(in, invisible); + annotationElements.add(elem); + } + } + + @Override + public void print() throws IOException { + printHeader(); + printBody(); + } + + // Prints the annotation header. + protected void printHeader() { + //Print annotation Header, which consists of the + // Annotation Token ('@'), visibility ('+', '-'), + // and the annotation name (type index, CPX). + // Mark whether it is invisible or not. + String annotationName = pool.getString(type_cpx, index -> null); + if (printCPIndex) { + annotationName = "#" + type_cpx + (annotationName != null && (!skipComments) ? " /* %s */".formatted(annotationName) : ""); + } else { + if (annotationName == null) { + annotationName = "#" + type_cpx; + } else { + annotationName = "\"" + annotationName + "\""; + } + } + switch (getAnnotationElementState()) { + case HAS_DEFAULT_VALUE -> { + println(" " + DEFAULT_VALUE_PREFIX); + printIndent(invisible ? invisibleAnnotationToken : visibleAnnotationToken).print(annotationName); + setCommentOffset(getCommentOffset()); + } + case PARAMETER_ANNOTATION, INLINED_ELEMENT -> print(invisible ? invisibleAnnotationToken : visibleAnnotationToken).print(annotationName); + default -> printIndent(invisible ? invisibleAnnotationToken : visibleAnnotationToken).print(annotationName); + } + } + + protected void printBody() throws IOException { + // For a standard annotation, print out brackets, + // and list the name/value pairs. + if (isEmpty()) { + // Marker annotation + print(" { }"); + } else { + switch (getAnnotationElementState()) { + case HAS_DEFAULT_VALUE -> { + println(" {"); + printBodyOfDefaultData(); + println(); + decIndent(); + printIndent("}"); + } + case INLINED_ELEMENT -> { + incIndent().printIndentLn("{"); + printBodyOfData(); + printIndent("}").decIndent(); + } + default -> { + println(" {"); + printBodyOfData(); + printIndent("}"); + } + } + } + } + + // Prints the annotation value that is the default. + protected void printBodyOfDefaultData() throws IOException { + int prefixLength = getCommentOffset(); + for (AnnotationElement annotationElement : annotationElements) { + print(enlargedIndent(prefixLength)); + annotationElement.setElementState(RIGHT_OPERAND); + annotationElement.print(); + } + } + + // Prints the annotation value that is the default. + protected void printBodyOfData() throws IOException { + int i = 0; + for (AnnotationElement annotationElement : annotationElements) { + annotationElement.setCommentOffset(getCommentOffset()).setTheSame(this).incIndent(); + annotationElement.print(); + println((i++ < annotationElements.size() - 1) ? "," : ""); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + String annotationName = pool.getString(type_cpx, index -> "#" + index); + sb.append(invisible ? invisibleAnnotationToken : visibleAnnotationToken); + sb.append(annotationName).append("{"); + sb.append(annotationElements.stream().map(AnnotationElement::toString).collect(Collectors.joining(","))); + return sb.append("}").toString(); + } + + /** + * @return true if annotation has no elements + */ + public boolean isEmpty() { + return annotationElements.isEmpty(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationElement.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationElement.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationElement.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AnnotationElement.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,420 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.FormatError; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.openjdk.asmtools.asmutils.StringUtils.Utf8ToString; +import static org.openjdk.asmtools.asmutils.StringUtils.isPrintableChar; +import static org.openjdk.asmtools.jasm.ClassFileConst.AnnotationElementType; +import static org.openjdk.asmtools.jasm.ClassFileConst.getAnnotationElementType; +import static org.openjdk.asmtools.jdis.MemberData.AnnotationElementState.*; + +/** + * Base class of all AnnotationElement entries + */ +public class AnnotationElement> extends MemberData { + + //constant pool index for the name of the Annotation Element + public int name_cpx; + public AnnotationValue value = null; + + public AnnotationElement(T data) { + super(data); + } + + /* + * Static factory - creates Annotation Elements. + */ + public static

> AnnotationValue

readValue(DataInputStream in, P data, boolean invisible) throws IOException { + AnnotationValue

val; + char tg = (char) in.readByte(); + AnnotationElementType tag = getAnnotationElementType(tg); + switch (tag) { + // String, Byte, Char, Int (no need to add keyword), Short, Boolean, Float, Double, Long, Class + case AE_STRING, AE_BYTE, AE_CHAR, AE_INT, AE_SHORT, AE_BOOLEAN, AE_FLOAT, AE_DOUBLE, AE_LONG, AE_CLASS -> { + // CPX based Annotation + int cpx = in.readShort(); + val = new CPX_AnnotationValue<>(tag, data, cpx); + } + // Enum + case AE_ENUM -> { + // CPX2 based Annotation + int cpx1 = in.readShort(); + int cpx2 = in.readShort(); + val = new CPX2_AnnotationValue<>(tag, data, cpx1, cpx2); + } + // Annotation + case AE_ANNOTATION -> { + AnnotationData

annotationData = new AnnotationData<>(data, invisible); + annotationData.read(in); + val = new Annotation_AnnotationValue<>(tag, data, annotationData); + } + // Array + case AE_ARRAY -> { + Array_AnnotationValue

arrayAnnotationValue = new Array_AnnotationValue<>(tag, data); + val = arrayAnnotationValue; + int cnt = in.readShort(); + for (int i = 0; i < cnt; i++) { + arrayAnnotationValue.add(readValue(in, data, invisible)); + } + } + default -> { + if (data.bestEffort) { + data.environment.error("err.unknown.tag", isPrintableChar(tg) ? tg : '?', Integer.toHexString(tg)); + val = new Annotation_AnnotationValue<>(tag, data, null); + } else { + throw new FormatError(data.environment.getLogger(), + "err.unknown.tag", isPrintableChar(tg) ? tg : '?', Integer.toHexString(tg)); + } + } + } + return val; + } + + /** + * Read and resolve the method data called from ClassData. precondition: NumFields has + * already been read from the stream. + */ + public void read(DataInputStream in, boolean invisible) throws IOException { + name_cpx = in.readShort(); + value = readValue(in, data, invisible); + environment.traceln("AnnotationElement: cpIndex#%d=%s value=%s", name_cpx, + pool.getString(name_cpx, index -> "????"), value.toString()); + } + + public String stringVal() { + String name = pool.getName(name_cpx); + if (printCPIndex) { + return (skipComments) ? format("#%d", name_cpx) : format("#%d /* %s */", name_cpx, name); + } + return name; + } + + @Override + public void print() throws IOException { + printIndent(stringVal() + " = "); + value.setTheSame(this).incIndent(); + if (value.elementType == AnnotationElementType.AE_ARRAY) { + if (((Array_AnnotationValue) value).annotationValues.size() == 0) { + print("{ }"); + } else { + println().print(getIndentString()); + value.print(); + printIndent("}"); + } + } else { + value.setElementState(this.getAnnotationElementState()); + value.print(); + } + } + + @Override + public String toString() { + return ""; + } + + /** + * Base class for an annotation value. + */ + public static class AnnotationValue> extends MemberData { + + // tag the descriptor for the constant + public AnnotationElementType elementType; + + public AnnotationValue(AnnotationElementType elementType, T data) { + super(data); + this.elementType = elementType; + memberType = "AnnotationValue"; + } + + @Override + public String toString() { + return format("<%s %s %s>", memberType, elementType.printValue(), stringVal()); + } + + protected String stringVal() { + return ""; + } + + @Override + public void print() throws IOException { + print(PadLeft(elementType.value(), 4)); + } + } + + /** + * Annotation value which is described by a single CPX entries (i.e. String, byte, char, + * int, short, boolean, float, long, double, class reference). + */ + public static class CPX_AnnotationValue> extends AnnotationValue { + + public int cpx; + + public CPX_AnnotationValue(AnnotationElementType elementType, T data, int cpx) { + super(elementType, data); + this.cpx = cpx; + memberType = "CPX_AnnotationValue"; + } + + @Override + public String stringVal() { + StringBuilder sb = new StringBuilder(); + switch (elementType) { + // String + case AE_STRING -> sb.append(valueAsString("", + () -> Utf8ToString(pool.getString(cpx, index -> "#" + cpx), "\""))); + // Byte, Char, Short + case AE_BYTE, AE_CHAR, AE_SHORT -> sb.append(valueAsString(elementType.printValue(), + () -> pool.getConst(cpx).stringVal())); + // Int (no need to add keyword), Long, Float, Double + case AE_INT, AE_FLOAT, AE_DOUBLE, AE_LONG -> sb.append(valueAsString("", + () -> pool.getConst(cpx).stringVal())); + // Boolean + case AE_BOOLEAN -> sb.append(valueAsString(elementType.printValue(), + () -> ((ConstantPool.CP_Int) pool.getConst(cpx)).value == 0 ? "false" : "true")); + // Class + case AE_CLASS -> sb.append(valueAsString(elementType.printValue(), () -> pool.getName(cpx))); + default -> { + } + } + return sb.toString(); + } + + private String valueAsString(String prefix, Supplier supplier) { + String str = prefix.isEmpty() ? "" : prefix + " "; + if (printCPIndex) { + if (skipComments) { + str += format("#%d", cpx); + } else { + str += format("#%d /* %s */", cpx, supplier.get()); + } + } else { + str += supplier.get(); + } + return str; + } + + @Override + public void print() { + AnnotationElementState state = getAnnotationElementState(); + if (state == HAS_DEFAULT_VALUE) { + print(getDefaultValuePrefix() + "%s }", stringVal()); + } else if (state == RIGHT_OPERAND) { + print(" %s }", stringVal()); + } else { + print(stringVal()); + } + } + } + + /** + * AnnotationValue that contain 2 cpx indices (i.e. enums). + */ + public static class CPX2_AnnotationValue> extends AnnotationValue { + + public int cpx1; + public int cpx2; + + public CPX2_AnnotationValue(AnnotationElementType elementType, T data, int cpx1, int cpx2) { + super(elementType, data); + this.cpx1 = cpx1; + this.cpx2 = cpx2; + memberType = "CPX2_AnnotationValue"; + } + + @Override + public String stringVal() { + StringBuilder sb = new StringBuilder(); + // Enum + if (elementType == AnnotationElementType.AE_ENUM) { + // print the enum type and constant name + String className = pool.getName(cpx1); + String name = pool.getName(cpx2); + sb.append(elementType.printValue()).append(' '); + if (printCPIndex) { + sb.append(format("#%d.#%d", cpx1, cpx2)); + if (!skipComments) { + sb.append(format(" /* %s.%s */", className, name)); + } + } else { + sb.append(className).append(".").append(name); + } + } + return sb.toString(); + } + + @Override + public String toString() { + return format("<%s %s>", memberType, stringVal()); + } + + @Override + public void print() { + if (getAnnotationElementState() == HAS_DEFAULT_VALUE) { + print(getDefaultValuePrefix() + "%s }", stringVal()); + } else { + print(stringVal()); + } + } + } + + /** + * Annotation value that is an array of annotation elements. + */ + public static class Array_AnnotationValue> extends AnnotationValue { + + public ArrayList> annotationValues = new ArrayList<>(); + + public Array_AnnotationValue(AnnotationElementType elementType, T data) { + super(elementType, data); + memberType = "Array_AnnotationValue"; + } + + @Override + public String stringVal() { + return super.stringVal() + "={" + + annotationValues.stream().map(AnnotationValue::toString).collect(Collectors.joining(",")) + + '}'; + } + + public void add(AnnotationValue annotationValue) { + annotationValues.add(annotationValue); + } + + @Override + public void print() throws IOException { + int count = annotationValues.size(); + if (annotationValues.size() > 0) { + AnnotationElementState state = getAnnotationElementState(); + if (state == HAS_DEFAULT_VALUE || state == INLINED_ELEMENT) { + printDefaultAnnotationElement(count); + } else { + printAnnotationElement(count); + } + } else { + // Empty default array value. + print(getDefaultValuePrefix() + "{ } }"); + } + } + + private

> int getIndent(P value) { + if (value instanceof Annotation_AnnotationValue || value instanceof CPX_AnnotationValue) { + return getCommentOffset() + DEFAULT_VALUE_PREFIX.length() + getIndentSize(); + } + return 1; + } + + private int getItemsPerLine(int count, AnnotationElementType type) { + return switch (type) { + case AE_CLASS, AE_ANNOTATION, AE_ENUM, AE_ARRAY -> 1; + default -> (count > 10) ? (count % 2 == 0 ? 4 : 6) : (count % 2 == 0 ? 2 : 3); + }; + } + + public void printDefaultAnnotationElement(int count) throws IOException { + int i = 0, lineIndent = getIndent(annotationValues.get(0)); + int ItemsPerLine = getAnnotationElementState() == INLINED_ELEMENT ? 1 : + getItemsPerLine(count, annotationValues.get(0).elementType); + + println(getDefaultValuePrefix() + "{ "); + printPadLeft(INDENT_STRING, INDENT_OFFSET * 2); + for (AnnotationValue annotationValue : annotationValues) { + annotationValue.setElementState(INLINED_ELEMENT); + annotationValue.setCommentOffset(lineIndent); + if (annotationValue instanceof Annotation_AnnotationValue || + annotationValue instanceof CPX_AnnotationValue || + annotationValue instanceof CPX2_AnnotationValue) { + if (i % ItemsPerLine == 0 && i != 0) + printPadLeft(INDENT_STRING, INDENT_OFFSET * 2); + } + annotationValue.print(); // entry + if (i < count - 1) + print("," + (i % ItemsPerLine == (ItemsPerLine - 1) ? System.lineSeparator() : " ")); + i++; + } + println(" }").print(" }"); + } + + public void printAnnotationElement(int count) throws IOException { + int i = 0; + println("{"); + for (AnnotationValue annotationValue : annotationValues) { + annotationValue.setTheSame(this); + if (annotationValue instanceof CPX_AnnotationValue || annotationValue instanceof CPX2_AnnotationValue) { + print(annotationValue.getIndentString()); + } + annotationValue.print(); // entry + if (i < count - 1) + println(","); + i++; + } + println(); + } + } + + /** + * Annotation value that is a reference to an annotation. + */ + public static class Annotation_AnnotationValue> extends AnnotationValue { + + AnnotationData annotationData; + + public Annotation_AnnotationValue(AnnotationElementType annotationElementType, + T data, + AnnotationData annotationData) { + super(annotationElementType, data); + this.annotationData = annotationData; + memberType = "Annotation_AnnotationValue"; + } + + @Override + public String stringVal() { + return annotationData.toString(); + } + + @Override + public Annotation_AnnotationValue setElementState(AnnotationElementState state) { + super.setElementState(state); + annotationData.setElementState(state); + return this; + } + + @Override + public void print() throws IOException { + if (this.annotationData != null) { // data might be null if -best-effort is set + // sets the same offset, Indent etc. + annotationData.setCommentOffset(this.getCommentOffset()); + annotationData.setTheSame(this); + annotationData.print(); // check off + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttrData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttrData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttrData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttrData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.HexUtils; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static java.lang.Math.min; +import static org.openjdk.asmtools.asmutils.HexUtils.toHex; + +public class AttrData { + + private final int MAX_DATA_PRINT_SIZE = 10; + + private EAttribute attributeInfo; + // + private int name_cpx; + + private int length; + private byte[] data; + final Environment environment; + + public AttrData(Environment environment, EAttribute attributeInfo) { + this.environment = environment; + this.attributeInfo = attributeInfo; + } + + public void read(int name_cpx, int attrLength, DataInputStream in) throws IOException { + this.name_cpx = name_cpx; + this.length = attrLength; + try { + data = new byte[attrLength]; + in.readFully(data); + environment.traceln("AttrData:#%d length=%d", name_cpx, attrLength); + } catch (NegativeArraySizeException | ArrayIndexOutOfBoundsException ex) { + throw new FormatError(environment.getLogger(), + "err.invalid.attribute.length", attributeInfo.printValue(), attrLength); + } + } + + public String dataAsString() { + if (data != null && data.length > 0) { + int maxLength = min( MAX_DATA_PRINT_SIZE, data.length ); + String res = IntStream.range(0, maxLength).mapToObj(i -> HexUtils.toHex(i)).collect(Collectors.joining(", ")); + if (data.length > MAX_DATA_PRINT_SIZE) { + res += ", ..."; + } + return res; + } + return ""; + } + + /** + * ATTRIBUTE_NAME_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * ... + * } + * + * @param name_cpx set the ConstantPool index of the attribute name + * @return the current instance + */ + public AttrData setNameCpx(int name_cpx) { + this.name_cpx = name_cpx; + return this; + } + + public AttrData setLength(int length) { + this.length = length; + return this; + } + + /** + * ATTRIBUTE_NAME_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * ... + * } + * + * @return attribute_name_index + */ + public int getNameCpx() { + return name_cpx; + } + + public int getLength() { + return length; + } + + public EAttribute getAttributeInfo() { + return attributeInfo; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttributeData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttributeData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttributeData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/AttributeData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.ToolLogger; +import org.openjdk.asmtools.jasm.TableFormatModel; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.function.Supplier; + +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.ENCLOSING_METHOD; + +/** + * Base class for attributes: SourceFile, NestHost, EnclosingMethod with format: + *

+ * attribute { + * u2 attribute_name_index; + * u4 attribute_length; SourceFile, NestHost: 2 EnclosingMethod: 4 + * u2 constant_pool_index; sourcefile_index, host_class_index, class_index + * **** + * u2 method_index; Only if EnclosingMethod + */ +public abstract class AttributeData> extends Indenter { + protected ConstantPool pool; + protected ToolLogger logger; + + protected int attribute_length = 0; + // Constant pool: SourceFile, NestHost class, Inner class. + protected String name = null; + // sourcefile_index, host_class_index, class_index + protected int cpx; + // only applicable to EnclosingMethod + // EnclosingMethod: If the current class is not immediately enclosed by a method or constructor, + // then the value of the method_index (that is equal to CONSTANT_NameAndType_info_index;) item must be zero. + protected int methodCpx = 0; + + // Utility functions + Supplier idxStringSupplier; + private Printable indexPrinter = () -> println(idxStringSupplier.get()); + private Printable namePrinter; + private Printable indexAndNamePrinter = () -> print(PadRight(idxStringSupplier.get(), getPrintAttributeCommentPadding())). + println((name != null) ? " // %s".formatted(name) : ""); + + protected AttributeData(ClassData classData, TableFormatModel.Token token) { + super(classData.toolOutput); + pool = classData.pool; + logger = classData.data.environment.getLogger(); + tableToken = token; + switch (tableToken) { + case SOURCE_FILE -> { + attribute_length = 2; + idxStringSupplier = () -> "#%d;".formatted(cpx); + namePrinter = () -> println("\"%s\";".formatted(name != null ? name : "???")); + } + case NEST_HOST -> { + attribute_length = 2; + idxStringSupplier = () -> "#%d;".formatted(cpx); + namePrinter = () -> println("%s;".formatted(name != null ? name : "\"???\"")); + } + case ENCLOSING_METHOD -> { + attribute_length = 4; + idxStringSupplier = () -> "#%d:#%d;".formatted(cpx, methodCpx); + namePrinter = () -> println("%s;".formatted(name)); + } + default -> throw new RuntimeException( + "Implementation of \"%s\" is not supported".formatted(tableToken.parseKey())); + } + } + + public A read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + if (attribute_length != this.attribute_length) { + if (bestEffort) { + logger.error("err.invalid.attribute.length", + tableToken.getAttribute().printValue(), attribute_length); + } else { + throw new FormatError(logger, + "err.invalid.attribute.length", + tableToken.getAttribute().printValue(), attribute_length); + } + } + this.cpx = in.readUnsignedShort(); + if (tableToken == ENCLOSING_METHOD) { + this.methodCpx = in.readUnsignedShort(); + } + return (A) this; + } + + @Override + protected void jasmPrint() { + calculateName(); + printIndent(PadRight(tableToken.getJasmToken().parseKey(), getPrintAttributeKeyPadding())); + if (printCPIndex) { + if (skipComments) { + indexPrinter.print(); + } else { + indexAndNamePrinter.print(); + } + } else { + namePrinter.print(); + } + } + + /** + * There are no differences between the simple (jasm) and extended (table) presentations of NestHost, + * SourceFile, EnclosingMethod attribute, and NestMembers attribute. + */ + @Override + protected void tablePrint() { + this.jasmPrint(); + } + + protected abstract String calculateName(); + + @FunctionalInterface + public interface Printable { + void print(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/BootstrapMethodData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/BootstrapMethodData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/BootstrapMethodData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/BootstrapMethodData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; + +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.BOOTSTRAPMETHOD; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.BOOTSTRAP_METHOD; + +/** + * BootstrapMethods_attribute { + * ... + * { u2 bootstrap_method_ref; + * u2 num_bootstrap_arguments; + * u2 bootstrap_arguments[num_bootstrap_arguments]; + * } + * } + */ +public class BootstrapMethodData extends Element { + int bsmRef; // u2 bootstrap_method_ref; + ArrayList bsmArguments; // u2 bootstrap_arguments[num_bootstrap_arguments]; + int numBsmArgs; // num_bootstrap_arguments + int indexOffset; + + public BootstrapMethodData(ClassData classData, Container container) { + super(classData, container); + tableToken = BOOTSTRAP_METHOD; + indexOffset = classData.printProgramCounter ? + PROGRAM_COUNTER_PLACEHOLDER_LENGTH : + INSTR_PREFIX_LENGTH - getIndentStep(); + } + + @Override + public boolean isPrintable() { + return bsmArguments != null && !bsmArguments.isEmpty(); + } + + /** + * Read and resolve the bootstrap method data called from ClassData. + */ + public void read(DataInputStream in) throws IOException { + // read the Methods CP indexes + bsmRef = in.readUnsignedShort(); + numBsmArgs = in.readUnsignedShort(); + bsmArguments = new ArrayList<>(numBsmArgs); + for (int i = 0; i < numBsmArgs; i++) { + bsmArguments.add(in.readUnsignedShort()); + } + } + + @Override + protected void jasmPrint(int index, int size) throws IOException { + int commentOffset = getCommentOffset() - TABLE_PADDING; + final BsmInfo bsmInfo = getBsmInfo(); + + printIndent(PadRight(BOOTSTRAPMETHOD.parseKey(), TABLE_PADDING)); + if (printCPIndex) { + if (skipComments) { + println("#%d;".formatted(bsmRef)); + } else { + printPadRight("#%d;".formatted(bsmRef), commentOffset). + println(" // %s".formatted(formatOperandLine(bsmInfo.strBsm(), + getCommentOffset() + getIndentSize(), + " // ", InvokeDynamicBreakPositions))); + } + } else { + println(formatOperandLine( + "%s".formatted(bsmInfo.strBsm()), TABLE_PADDING + getIndentStep(), "", + BootstrapMethodBreakPositions) + ); + } + printIndent(PadRight(" ", TABLE_PADDING)).print("{ "); + if (numBsmArgs > 0) { + println(); + incIndent(2); + if (printCPIndex) { + for (int i = 0; i < numBsmArgs; i++) { + int argRef = bsmArguments.get(i); + String delim = (i != numBsmArgs - 1) ? "," : ""; + boolean notLastIdx = i != numBsmArgs - 1; + printIndent(PadRight(" ", TABLE_PADDING)); + if (skipComments) { + println("#%d%s".formatted(argRef, delim)); + } else { + String strArg = bsmInfo.cpx2Const().bsmArgWithoutDelimitersAsString(argRef, notLastIdx); + strArg = formatOperandLine(strArg, getCommentOffset() + getIndentStep(), + " // ", + InvokeDynamicBreakPositions); + printPadRight("#%d%s".formatted(argRef, delim), commentOffset - getIndentStep() * 2). + println(" // %s".formatted(strArg)); + } + } + } else { + String strArgs = bsmInfo.cpx2Const().bsmArgsAsString(this); + printIndent(PadRight(" ", TABLE_PADDING - getIndentStep())). + println(formatOperandLine(strArgs, TABLE_PADDING + getIndentStep() * 2, "", + BootstrapArgumentsBreakPositions)); + } + decIndent(2); + printIndent(PadRight(" ", TABLE_PADDING)); + } + println("}"); + if (index < size - 1) + println(); + } + + @Override + protected void tablePrint(int index, int size) throws IOException { + final int commentOffset = getCommentOffset() - indexOffset - getIndentSize(); + final BsmInfo bsmInfo = getBsmInfo(); + + if (index == 0) { + printIndentLn("%s {".formatted(BOOTSTRAPMETHOD.alias())); + } + incIndent(); + printIndent(PadRight(format("%2d:", index), indexOffset)); + if (printCPIndex) { + if (skipComments) { + println("#%d;".formatted(bsmRef)); + } else { + printPadRight("#%d;".formatted(bsmRef), commentOffset). + println(" // %s".formatted(formatOperandLine( + "%s".formatted(bsmInfo.strBsm()), + getCommentOffset() + getIndentStep(), + " // ", + BootstrapMethodBreakPositions))); + } + } else { + println(formatOperandLine("%s".formatted(bsmInfo.strBsm()), indexOffset + getIndentStep() * 2, "", + BootstrapMethodBreakPositions) + ); + } + + if (numBsmArgs > 0) { + printIndentLn(" Arguments:"); + if (printCPIndex) { + int argOffs = commentOffset + indexOffset + getIndentStep() * 2; + for (int i = 0; i < numBsmArgs; i++) { + int argRef = bsmArguments.get(i); + boolean notLastIdx = i != numBsmArgs - 1; + String delim = (i != numBsmArgs - 1) ? "," : ";"; + printIndent(PadRight("", indexOffset)); + if (printCPIndex) { + if (skipComments) { + println("#%d%s".formatted(argRef, delim)); + } else { + String strArg = bsmInfo.cpx2Const().bsmArgWithoutDelimitersAsString(argRef, notLastIdx); + strArg = formatOperandLine(strArg, argOffs, " // ", InvokeDynamicBreakPositions); + printPadRight("#%d%s".formatted(argRef, delim), commentOffset).println(" // %s".formatted(strArg)); + } + } + } + } else { + String strArgs = bsmInfo.cpx2Const().bsmArgsAsString(this); + printIndent(PadRight(" ", indexOffset)); + println(formatOperandLine(strArgs, indexOffset + getIndentStep() * 2, "", + BootstrapArgumentsBreakPositions) + ";"); + } + } + if (index < size - 1) + println(); + else { + decIndent(); + printIndentLn("}"); + } + } + + private BsmInfo getBsmInfo() { + String strBsm; + ConstantPool.Constant cnt = owner.pool.getConst(bsmRef); + ConstantPool.CPX2 cpx2Const = owner.pool.getCPX2(ConstantPool.TAG.CONSTANT_NULL); + if (cnt instanceof ConstantPool.CPX2 cpx) { + cpx2Const = cpx; + strBsm = cpx.stringVal() + ";"; + } else { + strBsm = owner.environment.getInfo("info.corrupted_bootstrap_method_ref"); + if (!printCPIndex) { + strBsm = PadRight("#%d".formatted(bsmRef), CIRCULAR_COMMENT_OFFSET).concat(" // ").concat(strBsm); + } + } + BsmInfo bsmInfo = new BsmInfo(strBsm, cpx2Const); + return bsmInfo; + } + + private record BsmInfo(String strBsm, ConstantPool.CPX2 cpx2Const) { + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassArrayData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassArrayData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassArrayData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassArrayData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Base class of the "classes[]" data of attributes: + *

+ * Exceptions_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_exceptions; + * u2 exception_index_table[number_of_exceptions]; + * } + * The exception_index_table[i] is an index of a CONSTANT_Class_info structure representing a class type + * that this method is declared to throw. + *

+ * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + *

+ * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubclasses_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + *

+ */ +public class ClassArrayData extends MemberData { + JasmTokens.Token token; + int[] indexes; + + protected > ClassArrayData(M classData, JasmTokens.Token token) { + super(classData); + this.token = token; + } + + public ClassArrayData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + int number_of_entities = in.readUnsignedShort(); + if (attribute_length != 2 + number_of_entities * 2) { + throw new ClassFormatError("%s_attribute: Invalid attribute length".formatted(token.parseKey())); + } + indexes = new int[number_of_entities]; + for (int i = 0; i < number_of_entities; i++) { + indexes[i] = in.readUnsignedShort(); + } + return this; + } + + @Override + public void jasmPrint() { + if (indexes.length > 2) { + jasmPrintLong(); + } else { + jasmPrintShort(); + } + } + + public void jasmPrintShort() { + StringBuilder indexes = new StringBuilder(); + StringBuilder names = new StringBuilder(); + int lastIndex = this.indexes.length - 1; + String eoNames = (printCPIndex) ? "" : ";"; + for (int i = 0; i <= lastIndex; i++) { + if (printCPIndex) { + indexes.append("#").append(this.indexes[i]).append(i == lastIndex ? ";" : ", "); + } + names.append(pool.StringValue(this.indexes[i])).append(i == lastIndex ? eoNames : ", "); + } + printIndent(PadRight(token.parseKey(), getPrintAttributeKeyPadding())); + if (printCPIndex) { + if (skipComments) { + println(indexes.toString()); + } else { + print(PadRight(indexes.toString(), getPrintAttributeCommentPadding())).println(" // " + names); + } + } else { + println(names.toString()); + } + } + + public void jasmPrintLong() { + String name = token.parseKey(); + String locIndent = " ".repeat(name.length()); + int lastIndex = indexes.length - 1; + for (int i = 0; i <= lastIndex; i++) { + if (printCPIndex) { + if (skipComments) { + printIndent(PadRight((i == 0) ? name : locIndent, getPrintAttributeKeyPadding())). + print("#%d".formatted(indexes[i])).println(i == lastIndex ? ";" : ","); + } else { + printIndent(PadRight((i == 0) ? name : locIndent, getPrintAttributeKeyPadding())). + print(PadRight("#%d%s".formatted(indexes[i], (i == lastIndex) ? ";" : ","), getPrintAttributeCommentPadding())). + println(" // %s".formatted(pool.StringValue(indexes[i]))); + } + } else { + printIndent(PadRight((i == 0) ? name : locIndent, getPrintAttributeKeyPadding())). + print(pool.StringValue(indexes[i])).println(i == lastIndex ? ";" : ","); + } + } + } + + @Override + protected void tablePrint() { + jasmPrint(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ClassData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,775 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.HexUtils; +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.DecompilerLogger; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.SyntaxError; +import org.openjdk.asmtools.common.inputs.FileInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.structure.CFVersion; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.EModifier; +import org.openjdk.asmtools.jdis.notations.Type; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.text.DateFormat; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.openjdk.asmtools.common.structure.ClassFileContext.*; +import static org.openjdk.asmtools.common.structure.EModifier.ACC_ABSTRACT; +import static org.openjdk.asmtools.common.structure.EModifier.ACC_SUPER; +import static org.openjdk.asmtools.jasm.ClassFileConst.JAVA_MAGIC; +import static org.openjdk.asmtools.jdis.ClassData.COMPILATION_UNIT.MODULE_INFO; + +/** + * Central class data for of the Java Disassembler + */ +public class ClassData extends MemberData { + + // internal status of the class data + private boolean alreadyPrinted = false; + private boolean canBePrinted = false; // Sufficient class info has been read and is now ready to be printed + + // Version info + protected CFVersion cfVersion = new CFVersion(); + + // Constant Pool index to this class + protected int this_cpx; + // Constant Pool index to this classes parent (super) + protected int super_cpx; + + // Pre-initialized Constant Pool names calculated by this_cpx + protected String className = ""; + protected String packageName = ""; + protected String classShortName = ""; + + // The interfaces this class implements + protected int[] interfaces; + + // The fields of this class + protected Container fields; + + // The methods of this class + protected Container methods; + + /** + * Attributes: + * SourceFile 45.3 + * InnerClasses 45.3 + * EnclosingMethod 49.0 + * SourceDebugExtension 49.0 + * BootstrapMethods 51.0 + * Module, ModulePackages, ModuleMainClass 53.0 + * NestHost, NestMembers 55.0 + * Record 60.0 + * PermittedSubclasses 61.0 + * ------------------------------------------------- + * Synthetic 45.3 + * Deprecated 45.3 + * Signature 49.0 + * RuntimeVisibleAnnotations 49.0 + * RuntimeInvisibleAnnotations 49.0 + * RuntimeVisibleTypeAnnotations 52.0 + * RuntimeInvisibleTypeAnnotations 52.0 + */ + + private int totalAttributes = 0; + + // The SourceFile Attribute (since 45.3) + protected SourceFileData sourceFileData; + + // The inner-classes of this class (since 45.3) + protected Container innerClasses; + + // The EnclosingMethod Attribute (since 49.0) + protected EnclosingMethodData enclosingMethodData; + + // The record attribute of this class (since class file 58.65535) + protected RecordData recordData; + + // The bootstrap methods this class implements + protected Container bootstrapMethods; + + //The module this class file presents + protected ModuleData moduleData; + + // The NestHost of this class (since class file: 55.0) + protected NestHostData nestHost; + + // The NestMembers of this class (since class file: 55.0) + protected NestMembersData nestMembers; + + // The PermittedSubclasses of this class (JEP 360 (Sealed types): class file 59.65535) + protected PermittedSubclassesData permittedSubclassesData; + + protected SourceDebugExtensionData sourceDebugExtensionData; + + // Valhalla + protected LoadableDescriptorsData loadableDescriptorsData; + + // source file data + private TextLines sourceLines = null; + private Path classFile = null; + + public > ClassData(E environment) { + super(environment); + memberType = "ClassData"; + super.environment = environment; + environment.traceln("printOptions=" + Options.asShortString()); + super.pool = new ConstantPool(this); + super.init(this); + } + + public boolean isDetailedOutput() { + return detailedOutput || extraDetailedOutput; + } + + /** + * Read and resolve the field data + */ + protected void readFields(DataInputStream in) throws IOException { + int nFields = in.readUnsignedShort(); + environment.traceln("fields=#" + nFields); + fields = new Container<>(this, FieldData.class, nFields); + for (int k = 0; k < nFields; k++) { + FieldData field = new FieldData(this); + environment.traceln(" FieldData: #" + k); + field.read(in); + fields.add(field); + } + } + + /** + * Read and resolve the method data + */ + protected void readMethods(DataInputStream in) throws IOException { + int nMethods = in.readUnsignedShort(); + environment.traceln("methods=#" + nMethods); + methods = new Container<>(this, MethodData.class, nMethods); + for (int k = 0; k < nMethods; k++) { + MethodData method = new MethodData(this); + environment.traceln("MethodData: #" + k); + method.read(in); + methods.add(method); + } + } + + /** + * Read and resolve the interface data + */ + protected void readInterfaces(DataInputStream in) throws IOException { + // Read the interface names + int nInterfaces = in.readUnsignedShort(); + environment.traceln("interfaces=#" + nInterfaces); + interfaces = new int[nInterfaces]; + for (int i = 0; i < nInterfaces; i++) { + int interfaceCpx = in.readShort(); + environment.traceln(" InterfaceCpx[" + i + "]=" + interfaceCpx); + interfaces[i] = interfaceCpx; + } + } + + /** + * Read and resolve the attribute data + */ + @Override + protected boolean handleAttributes(DataInputStream in, EAttribute attributeTag, int attributeLength) throws IOException { + // Read the Attributes + boolean handled = true; + totalAttributes++; + switch (attributeTag) { + case ATT_Signature -> { + if (signature != null) { + environment.warning("warn.one.attribute.required", "Signature", "ClassFile"); + } + signature = new SignatureData(this).read(in, attributeLength); + } + case ATT_SourceFile -> { + // Read SourceFile attribute + if (sourceFileData != null) { + environment.warning("warn.one.attribute.required", "SourceFile", "ClassFile"); + } + sourceFileData = new SourceFileData(this).read(in, attributeLength); + } + case ATT_EnclosingMethod -> { + // Read EnclosingMethod attribute + if (enclosingMethodData != null) { + environment.warning("warn.one.attribute.required", "EnclosingMethod", "ClassFile"); + } + enclosingMethodData = new EnclosingMethodData(this).read(in, attributeLength); + } + case ATT_SourceDebugExtension -> + sourceDebugExtensionData = new SourceDebugExtensionData(this).read(in, attributeLength); + case ATT_InnerClasses -> { + // Read InnerClasses Attr + int count = in.readUnsignedShort(); + if (2 + count * 8 != attributeLength) { + if (bestEffort) { + environment.getLogger().error( + "err.invalid.attribute.length", "InnerClasses_attribute", attributeLength); + } else { + throw new FormatError(environment.getLogger(), + "err.invalid.attribute.length", "InnerClasses_attribute", attributeLength); + } + } + innerClasses = new Container<>(this, InnerClassData.class, count). + setHasSize(!isTableOutput() && !skipComments && !tableFormat); + innerClasses.setCommentOffset(this.getCommentOffset()); + for (int j = 0; j < count; j++) { + InnerClassData innerClass = new InnerClassData(this, innerClasses); + innerClass.read(in); + innerClasses.add(innerClass); + } + } + case ATT_BootstrapMethods -> { + // Read BootstrapMethods Attr + int count = in.readUnsignedShort(); + bootstrapMethods = new Container<>(this, BootstrapMethodData.class, count); + bootstrapMethods.setCommentOffset(this.getCommentOffset()); + for (int j = 0; j < count; j++) { + BootstrapMethodData bsmData = new BootstrapMethodData(this, bootstrapMethods); + bsmData.read(in); + bootstrapMethods.add(bsmData); + } + } + case ATT_Module -> { + // Read Module Attribute + moduleData = new ModuleData(this); + moduleData.read(in); + } + case ATT_NestHost -> + // Read NestHost Attribute (since class file: 55.0) + nestHost = new NestHostData(this).read(in, attributeLength); + case ATT_NestMembers -> + // Read NestMembers Attribute (since class file: 55.0) + nestMembers = new NestMembersData(this).read(in, attributeLength); + case ATT_Record -> recordData = new RecordData(this).read(in); + case ATT_PermittedSubclasses -> + // Read PermittedSubclasses Attribute (JEP 360 (Sealed types): class file 59.65535) + permittedSubclassesData = new PermittedSubclassesData(this).read(in, attributeLength); + case ATT_LoadableDescriptors -> + // Valhalla + loadableDescriptorsData = new LoadableDescriptorsData(this).read(in, attributeLength); + default -> handled = false; + } + return handled; + } + + /** + * Read and resolve the class data + */ + public void read(final DataInputStream in, final Path src) throws IOException { + classFile = src; + // Read the header + try { + int magic = in.readInt(); + if (magic != JAVA_MAGIC) { + environment.warning("warn.wrong.magic", HexUtils.toHex(JAVA_MAGIC), HexUtils.toHex(magic)); + } + cfVersion.setMinorVersion(in.readUnsignedShort()); + cfVersion.setMajorVersion(in.readUnsignedShort()); + + // Read the constant pool + pool.read(in).InitializePrintData(); + + access = in.readUnsignedShort(); + this_cpx = in.readUnsignedShort(); + super_cpx = in.readUnsignedShort(); + + environment.traceln("0x%04X [ %s] this_cpx=%d super_cpx=%d", access, + EModifier.asNames(access, EModifier.isModule(access) ? CLASS : MODULE), + this_cpx, super_cpx); + + // Read the interfaces + readInterfaces(in); + + // Read the fields + readFields(in); + + // Read the methods + readMethods(in); + + // Read the attributes + readAttributes(in); + + //Pre-initialize names,indexes needed for printing. + initClassNames(this_cpx); + // + environment.traceln("\n<< Reading is done >>"); + // Final initialization based on just read class data. + if (cfVersion.isValueObjectContext()) { + EModifier.setGlobalContext(VALUE_OBJECTS); + } + + } catch (EOFException eofException) { + environment.error("err.eof"); + } + } + + /** + * Initializes class, package names needed for printing asm file + * + * @param this_cpx The constant_pool entry at that index is a CONSTANT_Class_info structure (§4.4.1) + * representing the class or interface defined by this class file or + * this_class is module-info in the case of a module. + */ + private void initClassNames(int this_cpx) { + this.className = pool.getClassName(this_cpx); + final int idx = className.lastIndexOf('/'); + if (idx != -1) { + this.packageName = className.substring(0, idx); + this.classShortName = className.substring(idx + 1); + } else { + this.classShortName = className; + } + if (sourceFileData != null) { + sourceFileData.getName(); + } + } + + /** + * Determines if this Class has a package + * + * @return true if the package exists for this class + */ + public boolean hasPackage() { + return !this.packageName.isEmpty(); + } + + public String getClassName() { + return className; + } + + /** + * Read and resolve the attribute data + */ + public String getSrcLine(int lineNum) { + if (sourceLines == null) { + return null; // impossible call + } + String line; + try { + line = sourceLines.getLine(lineNum); + } catch (ArrayIndexOutOfBoundsException e) { + line = format("Line number %d is out of bounds", lineNum); + } + return line; + } + + @Override + protected void printAnnotations(List... annotationLists) throws IOException { + for (List list : annotationLists) { + if (list != null) { + for (T annotation : list) { + annotation.initIndent(0); + annotation.print(); + println(); + } + } + } + } + + /** + * Prints the JASM file as much as it was read if exceptions occur during reading. + */ + public void postPrint() { + if (!alreadyPrinted && canBePrinted) { + try { + this.print(); + } catch (Exception ignored) { + } + } + try { + environment.getToolOutput().finishClass(className); + } catch (IOException ignored) { + } + environment.getOutputs().flush(); + } + + /** + * Print jasm file in simple/table format. + */ + @Override + public void print() throws IOException { + if (COMPILATION_UNIT.get(className, access) == MODULE_INFO) { // module-info compilation unit + // Print the Annotations + printAnnotations(visibleAnnotations, invisibleAnnotations); + // Print Module Header + if (moduleData == null) { + // exception: 4.7.25. The Module Attribute is empty. + moduleData = new ModuleData(this); + } + print(moduleData.getModuleHeader(format("version %s", cfVersion.asString()))); + println(); + println("{"); + // Print the constant pool + if (printConstantPool) { + pool.print(); + } + canBePrinted = true; + // Print module attributes + moduleData.print(); + // + print(format("} // end of module %s", moduleData.getModuleName())); + if (moduleData.getModuleVersion() != null) + print("@" + moduleData.getModuleVersion()); + println(); + + // Print the Annotations + printAnnotations(visibleAnnotations, invisibleAnnotations); + printAnnotations(visibleTypeAnnotations, invisibleTypeAnnotations); + if (hasPackage()) { + println(String.format("package %s version %s;", packageName, cfVersion.asString())); + } + } else { // class/interface compilation unit + // Print either extended(table) or Jasm-formatted Annotations, Header, and ConstantPool. + printClassIntroduction(); + canBePrinted = true; + // Load source file info. + if (printSourceLines && (sourceFileData != null)) { + String sourceName = sourceFileData.calculateName(); + if (sourceName != null) { + sourceLines = new TextLines(classFile.getParent(), sourceName); + } + } + + // get the list of attributes that would be printed. it might be empty. + final List printableAttributes = getListOfPrintableAttributes( + signature, + sourceFileData, + enclosingMethodData, + sourceDebugExtensionData, + recordData, // Print the Record (since class file 58.65535 JEP 359) + nestHost, // Print the NestHost (since class file: 55.0) + innerClasses, + nestMembers, // Print the NestMembers (since class file: 55.0) + permittedSubclassesData, // Print PermittedSubclasses Attribute (JEP 360 (Sealed types): class file 59.65535) + loadableDescriptorsData, + bootstrapMethods + ); + + int commentOffset = getCommentOffset(); + + // Print the fields + if (printMemberDataList(fields, commentOffset) && isPrintable(methods) && !printableAttributes.isEmpty()) { + println(); + } + + setCommentOffset(commentOffset -= getIndentSize()); + + // Print the methods + if (printMemberDataList(methods, commentOffset) && !printableAttributes.isEmpty()) { + println(); + } + + // Print the attributes + printAttributes(printableAttributes, commentOffset); + + if (skipComments) { + println("}"); + } else { + println(format("} // end Class %s%s", + className, + sourceFileData != null ? " compiled from \"" + sourceFileData.calculateName() + "\"" : "")); + } + alreadyPrinted = true; + } + + List issues = pool.getIssues(); + if (!issues.isEmpty()) { + for (IOException ioe : issues) { + environment.error(ioe); + } + throw new SyntaxError(); + } + } + + protected void printClassIntroduction() throws IOException { + printSysInfo(); + if (hasPackage()) { + println(format("package %s;%n", packageName)); + } + // Print class annotations + printAnnotations(visibleAnnotations, invisibleAnnotations); + printAnnotations(visibleTypeAnnotations, invisibleTypeAnnotations); + // Print ClassDeclaration + printJasmClassDeclaration(); + println("{"); + int thisCommentOffset = pool.getCommentOffset(); + // Print the constant pool + if (printConstantPool) { + pool.print(); + setCommentOffset(thisCommentOffset); + } + // Print (this|super)_class + if (extraDetailedOutput && !dropClasses) { + if (printCPIndex) { + if (skipComments) { + printIndentLn("this_class: #%d;".formatted(this_cpx), thisCommentOffset); + printIndentLn("super_class: #%d;".formatted(super_cpx), thisCommentOffset); + } else { + thisCommentOffset -= getIndentSize(); + printIndent(PadRight("this_class: #%d;".formatted(this_cpx), thisCommentOffset)). + println(" // " + pool.getClassName(this_cpx, cpx -> "invalid index into the constant_pool table")); + printIndent(PadRight("super_class: #%d;".formatted(super_cpx), thisCommentOffset)). + println(" // " + pool.getClassName(super_cpx, cpx -> "invalid index into the constant_pool table")); + } + } else { + printIndentLn("this_class: %s;". + formatted(pool.getClassName(this_cpx, cpx -> "invalid index into the constant_pool table"))); + printIndentLn("super_class: %s;". + formatted(pool.getClassName(super_cpx, cpx -> "invalid index into the constant_pool table"))); + } + println(); + } + } + + @Override + protected void printSysInfo() { + if (sysInfo) { + ToolInput toolInput = environment.getToolInput(); + String thisClassName = pool.getJavaClassName(this_cpx, ""); + boolean isClass = !EModifier.isInterface(access); + Date lm; + String prefix = " * "; + println("/**"); + if (toolInput instanceof FileInput) { + println(prefix + "Classfile " + classFile.toAbsolutePath()); + lm = new Date(classFile.toFile().lastModified()); + } else { + String name = classFile.toString(); + println(prefix + "Classfile " + name.substring(name.lastIndexOf('/') + 1)); + lm = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + } + DateFormat df = DateFormat.getDateInstance(); + int length = toolInput.getSize(); + if (length > 0) { + println(prefix + INDENT_STRING + "Last modified %s; size %d bytes", df.format(lm), length); + } else { + println(prefix + INDENT_STRING + "Last modified %s", df.format(lm)); + } + MessageDigest msd = toolInput.getMessageDigest(); + if (msd != null) { + byte[] digest = msd.digest(); + if (digest != null) { + StringBuilder sb = new StringBuilder(); + for (byte b : digest) + sb.append(String.format("%02x", b)); + println(prefix + INDENT_STRING + msd.getAlgorithm() + " checksum " + sb); + } + } + if (sourceFileData != null) { + println(prefix + INDENT_STRING + "Compiled from \"%s\"".formatted(sourceFileData.calculateName())); + } + // Print java descriptor of a class/interface + if (isClass) { + print(prefix + EModifier.asKeywords(access & ~ACC_SUPER.getFlag(), CLASS) + + "class " + thisClassName); + } else { + print(prefix + EModifier.asKeywords(access & ~ACC_ABSTRACT.getFlag() & ~ACC_SUPER.getFlag(), CLASS) + + "interface " + thisClassName); + } + if (signature == null) { + // use info from class file header + if (isClass && super_cpx != 0) { + String superClassName = pool.getJavaClassName(this_cpx, ""); + if (!superClassName.equals("java.lang.Object")) { + print(" extends " + superClassName); + } + } + for (int i = 0; i < interfaces.length; i++) { + print(i == 0 ? (isClass ? " implements " : " extends ") : ","); + print(pool.getJavaClassName(interfaces[i], "")); + } + println(); + } else { + Type signType = signature.getSignatureType(); + String sign = signature.getJavaSignature(); + if (signType instanceof Type.ClassSigType) + print(sign); + else if (!signType.isObject()) { + print(" extends " + sign); + } + println(); + } + println(prefix + INDENT_STRING + "minor version: " + cfVersion.minor_version()); + println(prefix + INDENT_STRING + "major version: " + cfVersion.major_version()); + println(prefix + INDENT_STRING + "flags: (0x%04x) %s".formatted(access, EModifier.asNames(access, CLASS))); + println(prefix + INDENT_STRING + "this_class: %s".formatted(pool.getClassName(this_cpx, cpx -> "invalid index into the constant_pool table"))); + println(prefix + INDENT_STRING + "super_class: %s".formatted(pool.getClassName(super_cpx, cpx -> "invalid index into the constant_pool table"))); + + println(prefix + INDENT_STRING + "interfaces: %d, fields: %d, methods: %d, attributes: %d", + interfaces.length, fields.size(), methods.size(), totalAttributes); + println(" */"); + } + } + + protected void printJasmClassDeclaration() { + { + String shortClassName = pool.inRange(this_cpx) ? pool.getShortClassName(this_cpx, this.packageName) : "?? invalid index"; + // In Java SE 8, the ACC_SUPER semantics became mandatory, regardless of the setting of ACC_SUPER or + // the class file version number, and the flag no longer had any effect. + // however, to not print it where it was, would cause hotswap of such class to + // throw java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the class modifiers + Pair signInfo = (signature != null) ? + signature.getJasmPrintInfo((i) -> pool.inRange(i)) : + new Pair<>("", ""); + // An interface is distinguished by the ACC_INTERFACE flag being set. + if (EModifier.isInterface(access)) { // interface compilation unit + print(EModifier.asKeywords(access & ~ACC_ABSTRACT.getFlag(), CLASS)); + print(printCPIndex ? + (skipComments ? + format("interface #%d%s", this_cpx, signInfo.first) : + format("interface #%d%s /* %s%s */", this_cpx, signInfo.first, shortClassName, signInfo.second) + ) : + format("interface %s", shortClassName, signInfo.second) + ); + } else { // class compilation unit + // add synthetic, deprecated if necessary + print(EModifier.asKeywords(access, CLASS) + getPseudoFlagsAsString()); + print(printCPIndex ? + (skipComments ? + format("class #%d%s", this_cpx, signInfo.first) : + format("class #%d%s /* %s%s */", this_cpx, signInfo.first, shortClassName, signInfo.second) + ) : + format("class %s%s", shortClassName, signInfo.second) + ); + // if base class is not j.l.Object prints the "extends" statement + if (this_cpx < pool.size() && this_cpx > 0) { + if (!pool.getClassName(super_cpx).equals("java/lang/Object")) { + print(printCPIndex ? + (skipComments ? + format(" extends #%d", super_cpx) : + format(" extends #%d /* %s */", super_cpx, pool.getShortClassName(super_cpx, this.packageName)) + ) : + format(" extends %s", pool.getShortClassName(super_cpx, this.packageName)) + ); + } + } else { + print(printCPIndex ? + (skipComments ? + format(" extends #%d", super_cpx) : + format(" extends #%d /* ?? invalid index */", super_cpx) + ) : " extends ??"); + } + } + // print the "implements" statement + int numInterfaces = interfaces.length; + if (numInterfaces > 0) { + String statement; + String sNames = Arrays.stream(interfaces). + mapToObj(cpx -> pool.getShortClassName(cpx, this.packageName)). + collect(Collectors.joining(", ")); + if (printCPIndex) { + String sIndexes = Arrays.stream(interfaces). + mapToObj(cpx -> format("#%d", cpx)). + collect(Collectors.joining(", ")); + if (skipComments) { + statement = format("%simplements %s", (numInterfaces > 1) ? "\n" + getIndentString() : " ", sIndexes); + } else { + statement = format("%simplements %s /* %s */", (numInterfaces > 1) ? "\n" + getIndentString() : " ", sIndexes, sNames); + } + } else { + statement = format("%simplements %s", (numInterfaces > 1) ? "\n" + getIndentString() : " ", sNames); + } + print(statement); + } + println("%sversion %s", (numInterfaces > 1) ? "\n" + getIndentString() : " ", cfVersion.asString()); + } + } + + private

List

getListOfPrintableAttributes(P... attributes) { + return Arrays.stream(attributes).filter(a -> isPrintable(a)).toList(); + } + + // Utility methods to check whether cottages of data would be printed + private

boolean isPrintable(P... attributes) { + return Arrays.stream(attributes). + anyMatch(attribute -> attribute != null && attribute.isPrintable()); + } + + private

void printAttributes(List

attributeList, int commentOffset) throws + IOException { + int len = attributeList.size(); + boolean printed = false; + for (int i = 0; i < len; i++) { + P attribute = attributeList.get(i); + if (isPrintable(attribute)) { + if (Indenter.class.isAssignableFrom(attribute.getClass())) { + ((Indenter) attribute).setCommentOffset(commentOffset); + } + attribute.print(); + printed = true; + } + if (printed && (i + 1 < len)) { + println(); + printed = false; + } + } + // TODO: Prints corrupted attributes if any. + } + + private boolean printMemberDataList(Container, ClassData> list, + int commentOffset) throws IOException { + if (list != null && list.size() > 0) { + list.setCommentOffset(commentOffset).print(); + return true; + } + return false; + } + + public enum COMPILATION_UNIT { + MODULE_INFO, + PACKAGE_INFO, + CLASS_UNIT; + + /** + * @param className Pre-initialized Constant Pool name calculated by this_cpx + * @param access access flags (modifiers) + * @return compilation unit + */ + public static COMPILATION_UNIT get(String className, int access) { + if (className.endsWith("module-info") || EModifier.isModule(access)) { // module-info compilation unit + return MODULE_INFO; + } else if (className.endsWith("package-info") && EModifier.isInterface(access)) { // package-info compilation unit + return PACKAGE_INFO; + } else { + return CLASS_UNIT; + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/CodeData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/CodeData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/CodeData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/CodeData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,959 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.HexUtils; +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.StackMap; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.*; + +import static java.lang.String.format; +import static org.openjdk.asmtools.asmutils.HexUtils.toHex; +import static org.openjdk.asmtools.common.structure.EAttribute.ATT_RuntimeInvisibleTypeAnnotations; +import static org.openjdk.asmtools.common.structure.EAttribute.get; +import static org.openjdk.asmtools.jasm.ClassFileConst.BasicType; +import static org.openjdk.asmtools.jasm.ClassFileConst.getBasicType; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.LOCAL; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.STACK; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode.opc_bytecode; +import static org.openjdk.asmtools.jasm.OpcodeTables.opcode; + +/** + * Code data for a code attribute in method members in a class of the Java Disassembler + */ +public class CodeData extends MemberData { + + /** + * reversed bytecode index hash, associates labels with ByteCode indexes + */ + private final HashMap instructionAttrs = new HashMap<>(); + // Raw byte array for the byte codes + protected byte[] code; + // Limit for the stack size + protected int max_stack; + // Limit for the number of local vars + protected int max_locals; + // The remaining attributes of this class + protected ArrayList attrs = new ArrayList<>(0); // AttrData + // Trap table, describes exceptions caught + private ArrayList trap_table = new ArrayList<>(0); // TrapData + + // Line Number table, describes source lines associated with ByteCode indexes + private Container lineNumberTable; + // Local Variable table, describes variable scopes associated with ByteCode indexes + private Container localVariableTable; + + // Local Variable Type table, describes variable types associated with variables + private Container localVariableTypeTable; + + // stack map table, describes compiler hints for stack rep, associated with ByteCode indexes + private StackMapTable stackMapTable; + // The boolean firstStackEntry is calculated based on the index of the StackMap entry in the table. + // Is firstStackEntry the entries[0] in the stack_map_entry structure? + // In other words, does StackMapData[i] describe the second stack map entry of the method ignoring leading modifiers? + private boolean firstStackEntry = true; + + //The visible type annotations for this method + private ArrayList> visibleTypeAnnotations; + + // The invisible type annotations for this method + private ArrayList> invisibleTypeAnnotations; + + private int instructionOffset, attributeOffset; + + public CodeData(MethodData data) { + super(data); + if (data.printProgramCounter) { + instructionOffset = PROGRAM_COUNTER_PLACEHOLDER_LENGTH; + attributeOffset = instructionOffset; + } else { + instructionOffset = INSTR_PREFIX_LENGTH; + attributeOffset = instructionOffset - getIndentStep(); + } + } + + private static int align(int n) { + return (n + 3) & ~3; + } + + private int getByte(int pc) throws IndexOutOfBoundsException { + if (pc < 0 || pc >= code.length) { + throw new IndexOutOfBoundsException(environment.getInfo("err.out.of.range", pc)); + + } + return code[pc]; + } + + private int getUByte(int pc) throws IndexOutOfBoundsException { + if (pc < 0 || pc >= code.length) { + throw new IndexOutOfBoundsException(environment.getInfo("err.out.of.range", pc)); + + } + return code[pc] & 0xFF; + } + + private int getShort(int pc) throws IndexOutOfBoundsException { + if (pc < 0 || pc + 1 >= code.length) { + throw new IndexOutOfBoundsException(environment.getInfo("err.out.of.range", pc)); + } + return (code[pc] << 8) | (code[pc + 1] & 0xFF); + } + + private int getUShort(int pc) throws IndexOutOfBoundsException { + if (pc < 0 || pc + 1 >= code.length) { + throw new IndexOutOfBoundsException(environment.getInfo("err.out.of.range", pc)); + } + return ((code[pc] << 8) | (code[pc + 1] & 0xFF)) & 0xFFFF; + } + + private int getInt(int pc) throws IndexOutOfBoundsException { + return (getShort(pc) << 16) | (getShort(pc + 2) & 0xFFFF); + } + + protected InstructionAttr getInstructionAttribute(int pc) { + Integer PC = pc; + InstructionAttr res = instructionAttrs.get(PC); + if (res == null) { + res = new InstructionAttr(this.data); + res.setTheSame(this).incIndent(); + instructionAttrs.put(PC, res); + } + return res; + } + + protected InstructionAttr getLastInstruction() { + return instructionAttrs.get(Collections.max(instructionAttrs.keySet())); + } + + protected InstructionAttr getFirstInstruction() { + return instructionAttrs.get(Collections.min(instructionAttrs.keySet())); + } + + /* Read Methods */ + private Container readLineNumberTable(DataInputStream in, boolean ignoreMemorization) throws IOException { + int len = in.readInt(); // attr_length + int nLines = in.readUnsignedShort(); + Container table = ignoreMemorization ? null : new Container<>(this, LineNumberData.class, nLines); + environment.traceln("CodeAttr: LineNumberTable[%d] length=%d", nLines, len); + for (int l = 0; l < nLines; l++) { + LineNumberData data = new LineNumberData(in, this.data); + if (!ignoreMemorization) { + table.add(data); + } + } + return table; + } + + private Container readLocalVariableTable(DataInputStream in, boolean ignoreMemorization) throws IOException { + int len = in.readInt(); // attr_length + int nLines = in.readUnsignedShort(); + Container table = ignoreMemorization ? null : new Container<>(this, LocalVariableData.class, nLines); + environment.traceln("CodeAttr: LocalVariableTable[%d] length=%d", nLines, len); + for (int l = 0; l < nLines; l++) { + LocalVariableData data = new LocalVariableData(owner, in, this.data); + if (!ignoreMemorization) { + table.add(data); + } + } + return table; + } + + private Container readLocalVariableTypeTable(DataInputStream in, boolean ignoreMemorization) throws IOException { + int len = in.readInt(); // attr_length + int nLines = in.readUnsignedShort(); + Container table = ignoreMemorization ? null : new Container<>(this, LocalVariableTypeData.class, nLines); + environment.traceln("CodeAttr: LocalVariableTypeTable[%d] length=%d", nLines, len); + for (int l = 0; l < nLines; l++) { + LocalVariableTypeData data = new LocalVariableTypeData(owner, in, this.data); + if (!ignoreMemorization) { + table.add(data); + } + } + return table; + } + + private void readTrapTable(DataInputStream in) throws IOException { + int trap_table_len = in.readUnsignedShort(); + environment.traceln("CodeAttr: TrapTable[%d]", trap_table_len); + trap_table = new ArrayList<>(trap_table_len); + for (int l = 0; l < trap_table_len; l++) { + trap_table.add(new TrapData(in, l)); + } + } + + private void readStackMapEntity(EAttribute attribute, DataInputStream in) throws IOException { + int len = in.readInt(); // attr_length + int stackMapLength = in.readUnsignedShort(); + stackMapTable = new StackMapTable(attribute, this, stackMapLength); + firstStackEntry = true; + environment.traceln(() -> "CodeAttr: %s: attrLength=%d num=%d".formatted(attribute.name(), len, stackMapLength)); + int prevFrame_pc = 0; + int idx = 0; + boolean nextIsWrapped = false; + int wrapLevel = 0; + while (idx < stackMapLength) { + StackMapData stackMapData = switch (attribute) { + case ATT_StackMap -> new StackMapData(this, in); + case ATT_StackMapTable -> new StackMapData(calculateFirstPosition(idx), prevFrame_pc, this, in); + default -> throw new IllegalStateException("Unexpected value: " + attribute); + }; + prevFrame_pc = stackMapData.getFramePC(); + if (stackMapData.getStackEntryType() == StackMap.EntryType.EARLY_LARVAL) { + stackMapData.isWrapped = nextIsWrapped; // Negative test case:EARLY_LARVAL belongs to EARLY_LARVAL + stackMapData.wrapLevel = wrapLevel; + stackMapTable.add(stackMapData, true); + nextIsWrapped = true; + wrapLevel++; + } else { + stackMapData.isWrapped = nextIsWrapped; + stackMapData.wrapLevel = wrapLevel; + stackMapTable.add(stackMapData, false); + nextIsWrapped = false; + wrapLevel = 0; + idx++; + } + } + } + + /** + * Calculates whether a StackMapTable[index] entry is the first in the table, ignoring wrappers + * + * @param index index of the entry in the StackMapTable + * @return true if index refers to the first entry that isn't wrapper. + */ + private boolean calculateFirstPosition(int index) { + if (firstStackEntry) { + if (index == 0 || stackMapTable.wrappers.get(index - 1)) { + return true; + } + firstStackEntry = false; + } + return false; + } + + + private void readTypeAnnotations(DataInputStream in, boolean isInvisible) throws IOException { + int attrLength = in.readInt(); + // Read Type Annotations Attr + int count = in.readShort(); + ArrayList> tannots = new ArrayList<>(count); + environment.traceln("CodeAttr: Runtime%sisibleTypeAnnotation: attrLength=%d num= %d", + (isInvisible ? "Inv" : "V"), attrLength, count); + for (int index = 0; index < count; index++) { + TypeAnnotationData tannot = new TypeAnnotationData<>(this.data, isInvisible); + tannot.read(in); + tannots.add(tannot); + } + if (isInvisible) { + invisibleTypeAnnotations = tannots; + } else { + visibleTypeAnnotations = tannots; + } + } + + /** + * Read and resolve the code attribute data called from MethodData. precondition: + * NumFields has already been read from the stream. + */ + public void read(DataInputStream in, int codeAttrLength) throws IOException { + // Read the code in the Code Attribute + max_stack = in.readUnsignedShort(); + max_locals = in.readUnsignedShort(); + int codelen = in.readInt(); + environment.traceln("CodeAttr: CodeLength=%d FullLength=%d max_stack=%d max_locals=%d", + codelen, codeAttrLength, max_stack, max_locals); + + // read the raw code bytes + code = new byte[codelen]; + in.read(code, 0, codelen); + + //read the trap table + readTrapTable(in); + + // Read any attributes of the Code Attribute + int nattr = in.readUnsignedShort(); + environment.traceln("CodeAttr: add.attr: %d", nattr); + for (int k = 0; k < nattr; k++) { + int name_cpx = in.readUnsignedShort(); + // verify the Attrs name + ConstantPool.Constant name_const = pool.getConst(name_cpx); + if (name_const != null && name_const.tag == ConstantPool.TAG.CONSTANT_UTF8) { + String attrName = pool.getString(name_cpx, index -> "#" + index); + environment.traceln("CodeAttr: attr: " + attrName); + // process the attr + EAttribute attrTag = get(attrName); + switch (attrTag) { + case ATT_LineNumberTable -> lineNumberTable = readLineNumberTable(in, !printLineNumber); + case ATT_LocalVariableTable -> + localVariableTable = readLocalVariableTable(in, !printLocalVariables); + case ATT_LocalVariableTypeTable -> + localVariableTypeTable = readLocalVariableTypeTable(in, !printLocalVariableTypes); + case ATT_StackMap, ATT_StackMapTable -> readStackMapEntity(attrTag, in); + case ATT_RuntimeVisibleTypeAnnotations, ATT_RuntimeInvisibleTypeAnnotations -> + readTypeAnnotations(in, attrTag == ATT_RuntimeInvisibleTypeAnnotations); + default -> { + AttrData attr = new AttrData(environment, attrTag); + int attrLen = in.readInt(); // attr_length + attr.read(name_cpx, attrLen, in); + attrs.add(attr); + } + } + } + } + } + + /* Code Resolution Methods */ + private int checkForLabelRef(int pc) { + int opc = getUByte(pc); + Opcode opcode = opcode(opc); + try { + if (opcode == null) { + // nonexistent opcode - but we have to print something + getInstructionAttribute(pc).referred = true; + return 1; + } + switch (opcode) { + case opc_tableswitch -> { + try { + int tb = align(pc + 1); + int default_skip = getInt(tb); /* default skip pamount */ + + int low = getInt(tb + 4); + int high = getInt(tb + 8); + int count = high - low; + for (int i = 0; i <= count; i++) { + getInstructionAttribute(pc + getInt(tb + 12 + 4 * i)).referred = true; + } + getInstructionAttribute(default_skip + pc).referred = true; + return tb - pc + 16 + count * 4; + } catch (IndexOutOfBoundsException e) { + environment.error(e); + getInstructionAttribute(pc).referred = true; + return 1; + } + } + case opc_lookupswitch -> { + try { + int tb = align(pc + 1); + int default_skip = getInt(tb); /* default skip pamount */ + + int npairs = getInt(tb + 4); + for (int i = 1; i <= npairs; i++) { + getInstructionAttribute(pc + getInt(tb + 4 + i * 8)).referred = true; + } + getInstructionAttribute(default_skip + pc).referred = true; + return tb - pc + (npairs + 1) * 8; + } catch (IndexOutOfBoundsException e) { + environment.error(e); + getInstructionAttribute(pc).referred = true; + return 1; + } + } + case opc_jsr, opc_goto, opc_ifeq, opc_ifge, opc_ifgt, opc_ifle, opc_iflt, opc_ifne, opc_if_icmpeq, + opc_if_icmpne, opc_if_icmpge, opc_if_icmpgt, opc_if_icmple, opc_if_icmplt, opc_if_acmpeq, + opc_if_acmpne, opc_ifnull, opc_ifnonnull -> { + try { + getInstructionAttribute(pc + getShort(pc + 1)).referred = true; + return 3; + } catch (IndexOutOfBoundsException e) { + environment.error(e); + getInstructionAttribute(pc).referred = true; + return 1; + } + } + case opc_jsr_w, opc_goto_w -> { + getInstructionAttribute(pc + getInt(pc + 1)).referred = true; + return 5; + } + case opc_wide, opc_nonpriv, opc_priv -> { + int opc2 = (opcode.value() << 8) + getUByte(pc + 1); + opcode = opcode(opc2); + } + } + if (opcode != null) { + int opclen = opcode.length(); + return opclen == 0 ? 1 : opclen; // bugfix for 4614404 + } else { + return 1; + } + } catch (ArrayIndexOutOfBoundsException e) { + return 1; + } + } // end checkForLabelRef + + private void loadLabelTable() { + for (int pc = 0; pc < code.length; ) { + pc = pc + checkForLabelRef(pc); + } + } + + private void loadLineNumTable() { + for (LineNumberData entry : lineNumberTable) { + getInstructionAttribute(entry.start_pc).lineNum = entry.line_number; + } + } + + private void loadStackMap() { + ArrayList wrappers = null; + boolean firstWrapper = true; + for (int i = 0; i < stackMapTable.size(); i++) { + StackMapData entry = stackMapTable.get(i); + if (stackMapTable.wrappers.get(i)) { + if (wrappers == null) { + wrappers = new ArrayList<>(); + } + wrappers.add(entry); + } else { + firstWrapper = false; + InstructionAttr instr = getInstructionAttribute(entry.frame_pc); + instr.stackMapEntry = entry; + instr.stackMapWrappers = wrappers; + wrappers = null; + } + } + if (wrappers != null) { + // get either first or last instruction and assign modifiers to it. + InstructionAttr instr = (firstWrapper) ? getFirstInstruction() : getLastInstruction(); + instr.stackMapWrappers = wrappers; + } + } + + private void loadLocalVariableTable() { + for (LocalVariableData entry : localVariableTable) { + getInstructionAttribute(entry.start_pc).addVar(entry); + getInstructionAttribute(entry.start_pc + entry.length).addEndVar(entry); + } + } + + private void loadLocalVariableTypeTable() { + for (LocalVariableTypeData entry : localVariableTypeTable) { + getInstructionAttribute(entry.start_pc).addType(entry); + getInstructionAttribute(entry.start_pc + entry.length).addEndType(entry); + } + } + + private void loadTrapTable() { + for (TrapData entry : trap_table) { + getInstructionAttribute(entry.start_pc).addTrap(entry); + getInstructionAttribute(entry.end_pc).addEndTrap(entry); + getInstructionAttribute(entry.handler_pc).add_handler(entry); + } + } + + /* Print Methods */ + private int printInstrLn(int pc, int shift) { + int opc = getUByte(pc), opc2; + Opcode opcode = opcode(opc), opcode2; + String mnem; + if (opcode == null) { + // nonexistent opcode - but we have to print something + print(PadRight("bytecode", OPERAND_PLACEHOLDER_LENGTH + 1)). + println((printHEX ? toHex(opc) : opc) + ";"); + return 1; + } + switch (opcode) { + case opc_nonpriv, opc_priv -> { + int count = 1; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) { + opc2 = getUByte(pc + 1); + int finalopc = (opc << 8) + opc2; + opcode2 = opcode(finalopc); + + if (opcode2 == null) { + // assume all (even nonexistent) priv and nonpriv instructions + // are 2 bytes long + print(PadRight(opcode.parseKey(), OPERAND_PLACEHOLDER_LENGTH + 1)). + println((printHEX ? toHex(opc2) : opc2) + ";"); + } else { + println(opcode2.parseKey() + ";"); + } + } else + printBytes(opcode.byteValue(), validBytes, shift); + return 2; + } + case opc_wide -> { + int count = 1; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() != count) { + printBytes(opcode.byteValue(), validBytes, shift); + return 1; + } + opc2 = getUByte(pc + 1); + int finalopcwide = (opc << 8) + opc2; + opcode2 = opcode(finalopcwide); + if (opcode2 == null) { + // nonexistent opcode - but we have to print something + print(PadRight(opc_bytecode.parseKey(), OPERAND_PLACEHOLDER_LENGTH + 1)). + println(opcode.getPrintName() + ";"); + return 1; + } else { + mnem = opcode2.parseKey(); + } + if (opcode2 == Opcode.opc_iinc_w) { + count = 5; + validBytes = checkCodeBounds(pc, 5); + if (validBytes.size() == count) { + print(PadRight(mnem, OPERAND_PLACEHOLDER_LENGTH + 1)); + println("%d, %d;", getUShort(pc + 2), getUShort(pc + 4)); + } else + printBytes(opcode.byteValue(), validBytes, shift); + return 6; + } else { + count = 3; + validBytes = checkCodeBounds(pc, 3); + if (validBytes.size() == count) { + print(PadRight(mnem, OPERAND_PLACEHOLDER_LENGTH + 1)).println("%d;", getUShort(pc + 2)); + } else + printBytes(opcode.byteValue(), validBytes, shift); + return 4; + } + } + } + mnem = opcode.parseKey(); + if (mnem == null) { + // nonexistent opcode - but we have to print something + print(PadRight("bytecode", OPERAND_PLACEHOLDER_LENGTH + 1)).println(opcode + ";"); + return 1; + } + if (!opcode.isReservedOpcode()) { // == opcode.value() >= Opcode.opc_bytecode.value(); + // pseudo opcodes should be printed as bytecodes + print(PadRight("bytecode", OPERAND_PLACEHOLDER_LENGTH + 1)).println(opcode + ";"); + return 1; + } + String operand = opcode.parseKey(); + switch (opcode) { + case opc_aload, opc_astore, opc_fload, opc_fstore, opc_iload, opc_istore, opc_lload, opc_lstore, opc_dload, + opc_dstore, opc_ret -> { + int count = 1; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)).println(getUByte(pc + 1) + ";"); + else + printBytes(opcode.byteValue(), validBytes, shift); + return 2; + } + case opc_iinc -> { + int count = 2; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)). + println("%d, %d;", getUByte(pc + 1), getByte(pc + 2)); + else + printBytes(opcode.byteValue(), validBytes, shift); + return 3; + } + case opc_tableswitch -> { + boolean notPrinted = true; + try { + int tb = align(pc + 1); + int default_skip = getInt(tb); /* default skip pamount */ + + int low = getInt(tb + 4); + int high = getInt(tb + 8); + int count = high - low; + printPadRight(format("%s { ", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH)), getCommentOffset()); + println(printCPIndex && !skipComments ? " // " + low + " to " + high : ""); + notPrinted = false; + for (int i = 0; i <= count; i++) { + // 9 == "default: ".length() + print(enlargedIndent(PadRight(format("%2d: ", i + low), 9), shift)). + println(data.getLabelPrefix() + (pc + getInt(tb + 12 + 4 * i)) + ";"); + } + print(enlargedIndent( + PadRight("default: " + data.getLabelPrefix() + (default_skip + pc), + OPERAND_PLACEHOLDER_LENGTH - getIndentStep() - 2), shift) + ).println(" };"); + return tb - pc + 16 + count * 4; + } catch (IndexOutOfBoundsException e) { + if (notPrinted) { + println("%s { ".formatted(operand)); + printIndentLn(enlargedIndent("BOGUS;", shift)); + println(enlargedIndent(" };", shift)); + } else { + println("BOGUS;").println(enlargedIndent(" };", shift)); + } + environment.error(e); + return 1; + } + } + case opc_lookupswitch -> { + boolean notPrinted = true; + try { + int tb = align(pc + 1); + + int default_skip = getInt(tb); + int nPairs = getInt(tb + 4); + printPadRight(format("%s { ", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH)), getCommentOffset()); + println(printCPIndex && !skipComments ? " // " + nPairs : ""); + notPrinted = false; + Pair[] lookupswitchPairs = getLookupswitchPairs(tb, nPairs); + // 9 == "default: ".length() + int caseLength = Math.max(9, Arrays.stream(lookupswitchPairs). + mapToInt(p -> String.valueOf(p.first).length()).max().orElse(0) + 2); + for (int i = 0; i < nPairs; i++) { + print(enlargedIndent(PadRight(format("%2d:", lookupswitchPairs[i].first), caseLength), shift)). + println(data.getLabelPrefix() + (pc + lookupswitchPairs[i].second) + ";"); + } + print(enlargedIndent( + PadRight(PadRight("default: ", caseLength) + data.getLabelPrefix() + (default_skip + pc), + OPERAND_PLACEHOLDER_LENGTH - getIndentStep() - 2), shift)).println(" };"); + return tb - pc + (nPairs + 1) * 8; + } catch (IndexOutOfBoundsException e) { + if (notPrinted) { + println("%s { ".formatted(operand)); + } + printIndentLn(enlargedIndent("BOGUS;", shift)); + println(enlargedIndent(" };", shift)); + environment.error(e); + return 1; + } + } + case opc_newarray -> { + int count = 1; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) { + int tp = getUByte(pc + 1); + BasicType basicType = getBasicType(tp); + if (basicType == null) { + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)). + println("BOGUS TYPE: " + toHex(tp, 8) + ";"); + } else { + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)). + println(basicType.printValue() + ";"); + } + } else + printBytes(opcode.byteValue(), validBytes, shift); + return 2; + } + case opc_ldc, opc_ldc_w, opc_ldc2_w, opc_invokedynamic -> { + try { + int index, opLength; + Map> breakPositions = new HashMap<>(); + if (opcode == Opcode.opc_ldc) { + opLength = 2; + breakPositions = LdwBreakPositions; + index = getUByte(pc + 1); + } else if (opcode == Opcode.opc_invokedynamic) { + opLength = 5; + breakPositions = InvokeDynamicBreakPositions; + index = getUShort(pc + 1); // getUbyte(pc + 3); // getUbyte(pc + 4); // reserved bytes + } else { // opc_ldc*_w + opLength = 3; + breakPositions = LdwBreakPositions; + index = getUShort(pc + 1); + } + pool.setPrintTAG(true); + if (printCPIndex) { + if (skipComments) { + println(format("%s #%d;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH), index)); + } else { + printPadRight( + format("%s #%d;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH), index), getCommentOffset()). + print(" // "); + println( + formatOperandLine(pool.ConstantStrValue(index), getCommentOffset() + shift, + " // ", breakPositions)); + } + } else { + // TODO: Check Offset calculation + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)); + println(formatOperandLine(pool.ConstantStrValue(index), OPERAND_PLACEHOLDER_LENGTH + shift + 1, + "", breakPositions) + ";"); + } + pool.setPrintTAG(false); + return opLength; + } catch (IndexOutOfBoundsException e) { + if (printCPIndex) { + if (skipComments) { + println(format("%s BOGUS;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH))); + } else { + printPadRight(format("%s BOGUS;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH)), + getCommentOffset()).println(" // " + e.getMessage()); + } + } else { + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)).println("BOGUS;"); + } + environment.error(e); + return 1; + } + } + case opc_anewarray, opc_instanceof, opc_checkcast, opc_new, opc_putstatic, opc_getstatic, opc_putfield, + opc_getfield, opc_invokevirtual, opc_invokespecial, opc_invokestatic -> { + int count = 2; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) { + int index = getUShort(pc + 1); + if (printCPIndex) { + if (skipComments) { + println(format("%s #%d;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH), index)); + } else { + printPadRight(format("%s #%d;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH), index), + getCommentOffset()).println(" // " + pool.ConstantStrValue(index)); + } + } else { + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)); + println(pool.ConstantStrValue(index) + ";"); + } + } else + printBytes(opcode.byteValue(), validBytes, shift); + return 3; + } + case opc_multianewarray, opc_invokeinterface -> { + int count = opcode == Opcode.opc_multianewarray ? 3 : 4; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) { + int index = getUShort(pc + 1); + int dimensions = getUByte(pc + 3); // nargs in case of opc_invokeinterface + if (printCPIndex) { + if (skipComments) { + println(format("%s #%d, %d;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH), index, dimensions)); + } else { + printPadRight(format("%s #%d, %d;", PadRight(operand, OPERAND_PLACEHOLDER_LENGTH), index, dimensions), + getCommentOffset()).println(" // " + pool.ConstantStrValue(index)); + } + } else { + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)); + println("%s, %d;", pool.ConstantStrValue(index), dimensions); + } + } else { + printBytes(opcode.byteValue(), validBytes, shift); + } + return count + 1; + } + case opc_sipush -> { + int count = 2; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)).println(getShort(pc + 1) + ";"); + else + printBytes(opcode.byteValue(), validBytes, shift); + return 3; + } + case opc_bipush -> { + int count = 1; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)).println(getByte(pc + 1) + ";"); + else + printBytes(opcode.byteValue(), validBytes, shift); + return 2; + } + case opc_jsr, opc_goto, opc_ifeq, opc_ifge, opc_ifgt, opc_ifle, opc_iflt, opc_ifne, opc_if_icmpeq, + opc_if_icmpne, opc_if_icmpge, opc_if_icmpgt, opc_if_icmple, opc_if_icmplt, opc_if_acmpeq, + opc_if_acmpne, opc_ifnull, opc_ifnonnull -> { + int count = 2; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)). + println(data.getLabelPrefix() + (pc + getShort(pc + 1)) + ";"); + else + printBytes(opcode.byteValue(), validBytes, shift); + return 3; + } + case opc_jsr_w, opc_goto_w -> { + int count = 4; + List validBytes = checkCodeBounds(pc, count); + if (validBytes.size() == count) + print(PadRight(operand, OPERAND_PLACEHOLDER_LENGTH + 1)). + println(data.getLabelPrefix() + (pc + getInt(pc + 1)) + ";"); + else + printBytes(opcode.byteValue(), validBytes, shift); + return 5; + } + default -> { + println(operand + ";"); + return 1; + } + } + } // end printInstr + + /** + * @param opcode byte encoding of an instruction + * @param bytes bytes corresponding to the instruction's parameters + * @param shift printing indentation for output bytes + */ + private void printBytes(byte opcode, List bytes, int shift) { + print(PadRight(opc_bytecode.parseKey(), OPERAND_PLACEHOLDER_LENGTH + 1)). + println(HexUtils.toHex(opcode) + ";"); + for (byte b : bytes) { + printPadLeft(" ", shift). + print(PadRight(opc_bytecode.parseKey(), OPERAND_PLACEHOLDER_LENGTH + 1)). + println(HexUtils.toHex(b) + ";"); + } + } + + /** + * Checks whether the bytes corresponding to the instruction's parameters belong to the code attribute. + * + * @param ind code index of the instruction + * @param count number of bytes corresponding to the instruction's parameters + * @return The list of bytes corresponds to the instruction's parameters that belong to the code attribute. + * If the count does not match the list size, it indicates that the instruction is truncated. + */ + private List checkCodeBounds(int ind, int count) { + List list = new ArrayList<>(); + int codeLength = code.length; + for (int i = 1; i <= count; i++) { + if (ind + i < codeLength) + list.add(code[i]); + else + return list; + } + return list; + } + + private Pair[] getLookupswitchPairs(int pad, int count) { + try { + Pair[] pairs = new Pair[count]; + for (int i = 1; i <= count; i++) { + pairs[i - 1] = new Pair<>(getInt(pad + i * 8), getInt(pad + 4 + i * 8)); + } + return pairs; + } catch (NegativeArraySizeException e) { + throw new IndexOutOfBoundsException(environment.getInfo("err.out.of.range", count)); + } + } + + /** + * Prints the code data to the current output stream if code exists (method isn't abstract) + */ + public void print() throws IOException { + + if (lineNumberTable != null) { + loadLineNumTable(); + } + + // Preparing the inlined StackMapTable to have early_larval_frame tied to other frame types for which it is a wrapper. + if (stackMapTable != null && !tableFormat) { + loadStackMap(); + } + if (!data.printProgramCounter) { + loadLabelTable(); + } + loadTrapTable(); + if (localVariableTable != null) { + loadLocalVariableTable(); + } + if (localVariableTypeTable != null) { + loadLocalVariableTypeTable(); + } + // stack 3 locals 1 + incIndent().printIndentLn("%s %d %s %d", STACK.parseKey(), max_stack, LOCAL.parseKey(), max_locals).decIndent(); + + // Print ParamAnnotations if found. + data.printMethodParameters(); + + // Print Code Attribute + printIndentLn("{"); + + InstructionAttr insAttr = instructionAttrs.get(0); + + setCommentOffset(getCommentOffset() - instructionOffset - getIndentSize()); + + for (int pc = 0; pc < code.length; ) { + + if (insAttr != null) { + incIndent(); + insAttr.setCommentOffset(this.getCommentOffset()); + insAttr.printBegins(attributeOffset); + decIndent(); + } + + if (data.printProgramCounter) { + incIndent(); + printIndent(PadRight(format("%2d:", pc), instructionOffset)); + } else { + printIndent(PadRight(((insAttr != null) && insAttr.referred) ? data.getLabelPrefix() + pc + ":" : " ", + instructionOffset)); + incIndent(); + } + + if (insAttr != null) { + if (insAttr.printStackMap_Table(attributeOffset)) { + print(enlargedIndent(attributeOffset)); + } + } + + pc = pc + printInstrLn(pc, attributeOffset + getIndentSize()); + insAttr = instructionAttrs.get(pc); + if (insAttr != null) { + insAttr.printEnds(attributeOffset); + decIndent(); + } + decIndent(); + } + + // the right brace can be labelled: + if (insAttr != null && insAttr.stackMapEntry != null && insAttr.referred) { + if (data.printProgramCounter) { + incIndent(); + printIndent(PadRight("%2d:".formatted(code.length), 0)); + decIndent(); + } else { + printIndent(PadRight("%s%d:".formatted(data.getLabelPrefix(), code.length), code.length), 0); + } + } + // Print code's type annotations + printAnnotations(visibleTypeAnnotations, invisibleTypeAnnotations); + + // Print + printAttributes(lineNumberTable, localVariableTable, localVariableTypeTable, stackMapTable); + printIndentLn("}"); + } + + @Override + public MemberData setSignature(SignatureData signatureData) { + throw new RuntimeException("The Code Attribute does not have a signature attribute"); + } + + public Environment getEnvironment() { + return environment; + } + + /** + * Prints ClassData annotations + * + * @throws IOException signals that an exception of some sort has occurred + */ + @Override + protected void printAnnotations(List... annotationLists) throws IOException { + boolean firstTime = true; + for (List list : annotationLists) { + if (list != null) { + println(firstTime); + for (T annotation : list) { + firstTime = false; + annotation.print(); + println(); + } + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ConstantPool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ConstantPool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ConstantPool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ConstantPool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,1167 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.HexUtils; +import org.openjdk.asmtools.asmutils.Range; +import org.openjdk.asmtools.asmutils.StringUtils; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.outputs.ToolOutput; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.*; +import java.util.function.Function; + +import static java.lang.Math.max; +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.CONSTANT_POOL; + +/** + * Class representing the Constant Pool + */ +public class ConstantPool extends Indenter { + + public static final Function funcInvalidCPIndex = + index -> "??? Invalid constant_pool reference #%d".formatted(index); + + private static final Hashtable tagHash = new Hashtable<>(); + private static final Hashtable subTagHash = new Hashtable<>(); + + // Class initializer Code + static { + // Make sure all the tags get initialized before being used. + tagHash.put(TAG.CONSTANT_UTF8.value(), TAG.CONSTANT_UTF8); + // Obsolete: tagHash.put(TAG.CONSTANT_UNICODE.value(), TAG.CONSTANT_UNICODE); + tagHash.put(TAG.CONSTANT_INTEGER.value(), TAG.CONSTANT_INTEGER); + tagHash.put(TAG.CONSTANT_FLOAT.value(), TAG.CONSTANT_FLOAT); + tagHash.put(TAG.CONSTANT_LONG.value(), TAG.CONSTANT_LONG); + tagHash.put(TAG.CONSTANT_DOUBLE.value(), TAG.CONSTANT_DOUBLE); + tagHash.put(TAG.CONSTANT_CLASS.value(), TAG.CONSTANT_CLASS); + tagHash.put(TAG.CONSTANT_STRING.value(), TAG.CONSTANT_STRING); + tagHash.put(TAG.CONSTANT_FIELD.value(), TAG.CONSTANT_FIELD); + tagHash.put(TAG.CONSTANT_METHOD.value(), TAG.CONSTANT_METHOD); + tagHash.put(TAG.CONSTANT_INTERFACEMETHOD.value(), TAG.CONSTANT_INTERFACEMETHOD); + tagHash.put(TAG.CONSTANT_NAMEANDTYPE.value(), TAG.CONSTANT_NAMEANDTYPE); + tagHash.put(TAG.CONSTANT_METHODHANDLE.value(), TAG.CONSTANT_METHODHANDLE); + tagHash.put(TAG.CONSTANT_METHODTYPE.value(), TAG.CONSTANT_METHODTYPE); + tagHash.put(TAG.CONSTANT_DYNAMIC.value(), TAG.CONSTANT_DYNAMIC); + tagHash.put(TAG.CONSTANT_INVOKEDYNAMIC.value(), TAG.CONSTANT_INVOKEDYNAMIC); + tagHash.put(TAG.CONSTANT_MODULE.value(), TAG.CONSTANT_MODULE); + tagHash.put(TAG.CONSTANT_PACKAGE.value(), TAG.CONSTANT_PACKAGE); + + subTagHash.put(SUBTAG.REF_GETFIELD.value(), SUBTAG.REF_GETFIELD); + subTagHash.put(SUBTAG.REF_GETSTATIC.value(), SUBTAG.REF_GETSTATIC); + subTagHash.put(SUBTAG.REF_PUTFIELD.value(), SUBTAG.REF_PUTFIELD); + subTagHash.put(SUBTAG.REF_PUTSTATIC.value(), SUBTAG.REF_PUTSTATIC); + subTagHash.put(SUBTAG.REF_INVOKEVIRTUAL.value(), SUBTAG.REF_INVOKEVIRTUAL); + subTagHash.put(SUBTAG.REF_INVOKESTATIC.value(), SUBTAG.REF_INVOKESTATIC); + subTagHash.put(SUBTAG.REF_INVOKESPECIAL.value(), SUBTAG.REF_INVOKESPECIAL); + subTagHash.put(SUBTAG.REF_NEWINVOKESPECIAL.value(), SUBTAG.REF_NEWINVOKESPECIAL); + subTagHash.put(SUBTAG.REF_INVOKEINTERFACE.value(), SUBTAG.REF_INVOKEINTERFACE); + } + + /** + * Reference to the class data + */ + private final ClassData classData; + private Environment environment; + + /** + * The actual pool of Constants + */ + private ArrayList pool; + private Range range; + + private boolean printTAG = false; + + /* ConstantPool Constructors */ + public ConstantPool(ClassData cd) { + this(cd, 10); + } + + public ConstantPool(ClassData classData, int size) { + super(classData.toolOutput); + this.classData = classData; + this.environment = classData.environment; + tableToken = CONSTANT_POOL; + pool = new ArrayList<>(size); + } + + public void setPrintTAG(boolean value) { + this.printTAG = value; + } + + public String getPrintedTAG(TAG tag) { + return (this.printTAG) ? tag.tagName + " " : ""; + } + + public int size() { + return pool.size(); + } + + public boolean inRange(int value) { + if (range == null) { + range = new Range<>(1, pool.size() - 1); + } + return range.in(value); + } + + /** + * decodes a ConstantPool and it's constants from a data stream. + */ + ConstantPool read(DataInputStream in) throws IOException { + // constant_pool_count + //The value of the constant_pool_count item is equal to the number of entries in the constant_pool table plus one. + int constant_pool_count = in.readUnsignedShort(); + int tagSize; + pool = new ArrayList<>(constant_pool_count); + pool.add(0, null); + environment.traceln("constant_pool_count = " + constant_pool_count); + for (int i = 1; i < constant_pool_count; i += tagSize) { + byte tagByte = in.readByte(); + TAG tag = tagHash.get(tagByte); + if (tag == null) { + throw new ClassFormatError( + format("Error while reading constant pool for %s: unexpected tag at #%d: %d", + environment.getToolInput(), i, tagByte)); + } + tagSize = tag.size(); + environment.traceln("\tCP entry #" + i + " tag[" + tagByte + "]\t=\t" + tag); + switch (tag) { + case CONSTANT_UTF8 -> pool.add(i, new CP_Str(tag, in.readUTF())); + case CONSTANT_INTEGER -> pool.add(i, new CP_Int(tag, in.readInt())); + case CONSTANT_LONG -> { + pool.add(i, new CP_Long(tag, in.readLong())); + // handle null entry to account for Longs taking up 2 CP slots + pool.add(null); + } + case CONSTANT_FLOAT -> pool.add(i, new CP_Float(tag, in.readFloat())); + case CONSTANT_DOUBLE -> { + pool.add(i, new CP_Double(tag, in.readDouble())); + // handle null entry to account for Doubles taking up 2 CP slots + pool.add(null); + } + case CONSTANT_CLASS, CONSTANT_STRING, CONSTANT_METHODTYPE, CONSTANT_PACKAGE, CONSTANT_MODULE -> + pool.add(i, new CPX(tag, in.readUnsignedShort())); + case CONSTANT_FIELD, CONSTANT_METHOD, CONSTANT_INTERFACEMETHOD, CONSTANT_NAMEANDTYPE, CONSTANT_DYNAMIC, + CONSTANT_INVOKEDYNAMIC -> + pool.add(i, new CPX2(tag, in.readUnsignedShort(), in.readUnsignedShort())); + case CONSTANT_METHODHANDLE -> pool.add(i, new CPX2(tag, in.readUnsignedByte(), in.readUnsignedShort())); + default -> throw new ClassFormatError("invalid constant type: " + (int) tagByte); + } + } + return this; + } + + /** + * Public getter - Safely gets a Constant from the CP at a given index. + */ + public Constant getConst(int cpx) { + if (inRange(cpx)) { + return pool.get(cpx); + } else { + return null; + } + } + + /** + * Safely gets the string representation of a ConstantUTF8 from the CP at a given index. + *

+ * Returns either the UTF8 string, or a default ConstantUTF8 built by CP index + * with the function funcGetDefaultString like: index-> "#" + index + */ + public String getString(int cpx, Function funcGetDefaultString) { + String str = funcGetDefaultString.apply(cpx); + if (inRange(cpx)) { + Constant cns = pool.get(cpx); + if (cns != null && cns.tag == TAG.CONSTANT_UTF8) { + CP_Str cns1 = (CP_Str) cns; + str = cns1.value; + } + } + return str; + } + + /** + * Safely gets the string representation of a ConstantModule from the CP at a given index. + *

+ * Returns either the Java Module name, or a default class name built by CP index + * with the function funcGetDefaultModuleName like: index-> "#" + index + */ + public String getModuleName(int cpx, Function funcGetDefaultModuleName) { + String str = funcGetDefaultModuleName.apply(cpx); + if (inRange(cpx)) { + Constant cns = pool.get(cpx); + if (cns != null && cns.tag == TAG.CONSTANT_MODULE) { + str = cns.stringVal(); + } + } + return str; + } + + public String getModuleName(int cpx) { + return getModuleName(cpx, index -> "#" + index); + } + + /** + * Public string val - Safely gets the string representation of a ConstantPackage from the CP at a given index. + *

+ * Returns either the Java Package name, or a default class name built by CP index + * with the function funcGetDefaultPackageName like: index-> "#" + index + */ + public String getPackageName(int cpx, Function funcGetDefaultPackageName) { + String str = funcGetDefaultPackageName.apply(cpx); + if (inRange(cpx)) { + Constant cns = pool.get(cpx); + if (cns != null && cns.tag == TAG.CONSTANT_PACKAGE) { + str = cns.stringVal(); + } + } + return str; + } + + public String getPackageName(int cpx) { + return getPackageName(cpx, index -> "#" + index); + } + + /** + * Safely gets a Java name from a ConstantUTF8 from the CP at a given index. + *

+ * Returns either null (if invalid), or the Java name value of the UTF8 + */ + public String getName(int cpx) { + String str = getString(cpx, index -> null); + if (str == null) { + return ""; + } + return Utils.javaName(str); + } + + /** + * Safely gets a Java class name from a ConstantClass from the CP at a given index. + *

+ * Returns either the Java class name, or a CP index reference string. + */ + public String getClassName(int cpx) { + return getClassName(cpx, index -> "#" + index); + } + + public String getMethodName(int cpx) { + Constant cns = pool.get(cpx); + if (cns != null && cns instanceof CPX2 cpx2) { + return cpx2.stringVal(); + } else { + return cns.stringVal(); + } + } + + /** + * Gets a string representation of the constant_pool entry at the specified index, + * pointing to a CONSTANT_NameAndType_info structure with a field descriptor. + * + * @param cpx the constant_pool index pointing to CONSTANT_NameAndType_info + * @return a string presentation of the CONSTANT_NameAndType_info structure + */ + public String getFieldNameTypeAsString(int cpx) { + Constant cns = pool.get(cpx); + if (cns == null || (cns.tag != TAG.CONSTANT_NAMEANDTYPE) || referredBy(cpx, TAG.CONSTANT_METHOD, + TAG.CONSTANT_INTERFACEMETHOD, TAG.CONSTANT_METHODHANDLE, TAG.CONSTANT_DYNAMIC, TAG.CONSTANT_INVOKEDYNAMIC)) { + String msg = environment.getLogger().getResourceString("warn.field.nametype.required", cpx); + return (printCPIndex) ? msg : "??? #%d %s".formatted(cpx, msg); + } + return cns.stringVal(); + } + + public boolean referredBy(int cpx, TAG... tags) { + Optional cns = pool.stream().filter(item -> item != null && + item.tag.belongsTo(tags)).filter(c -> ((CPX2) c).value2 == cpx).findFirst(); + return cns.isPresent(); + } + + /** + * Safely gets a Java class name from a ConstantClass from the CP at a given index. + *

+ * Returns either the Java class name, or a message string formatted by cpx: formatString.formatted(cpx) + */ + public String getJavaClassName(int cpx, String formatString) { + String str = getClassName(cpx, index -> null); + return (str == null) ? formatString.formatted(cpx) : str.replace('/', '.'); + } + + /** + * Safely gets a Java class name from a ConstantClass from the CP at a given index. + *

+ * Returns either the Java class name, or a default class name built by CP index + * with the function funcGetDefaultClassName like: index-> "#" + index + */ + public String getClassName(int cpx, Function funcGetDefaultClassName) { + Constant cns = getConstantOfClassName(cpx); + if (cns == null) { + return funcGetDefaultClassName.apply(cpx); + } + return getClassName((CPX) cns); + } + + public Constant getConstantOfClassName(int cpx) { + if (!inRange(cpx)) { + return null; + } + Constant cns = pool.get(cpx); + if (cns == null || cns.tag != TAG.CONSTANT_CLASS) { + return null; + } + return cns; + } + + /** + * Safely gets a Java class name from a ConstantClass from a CPX2 constant pool + * object. (eg. Method/Field/Interface Ref) + *

+ * Returns either the Java class name, or a CP index reference string. + */ + public String getClassName(CPX2 classConst) { + return _getClassName(classConst.value); + } + + /** + * Safely gets a Java class name from a ConstantClass from a CPX constant pool object. + * (eg. Class Ref) + *

+ * Returns either the Java class name, or a CP index reference string. + */ + public String getClassName(CPX classConst) { + return _getClassName(classConst.value); + } + + /** + * Helper for getting class name. It checks ConstantPool bounds, does name conversion. + */ + private String _getClassName(int nameIndex) { + String res = "#" + nameIndex; + if (!inRange(nameIndex)) { + return res; + } + Constant nameConst = pool.get(nameIndex); + if (nameConst == null || nameConst.tag != TAG.CONSTANT_UTF8) { + return res; + } + CP_Str name = (CP_Str) nameConst; + + String classname = name.value; + + if (Utils.isClassArrayDescriptor(classname)) { + classname = "\"%s\"".formatted(classname); + } + return classname; + } + + /** + * Shortens a class name (if the class is in the given package). + * Works with a string-encoded classname. + * + * @param className fully qualified name of the class + * @param packageName the package + */ + public String getShortClassName(String className, String packageName) { + final int idx = className.lastIndexOf('/'); + if (idx == packageName.length() && className.startsWith(packageName)) { + return className.substring(idx + 1); + } + return className; + } + + /** + * Shortens a class name (if the class is in the given package). + * Works with a CP index to a ConstantClass. + * + * @param cpx the Constant Pool index to a CONSTANT_Class_info + * @param packageName the package + */ + public String getShortClassName(int cpx, String packageName) { + String name = Utils.javaName(getClassName(cpx)); + return getShortClassName(name, packageName); + } + + /** + * Getter that safely gets the string descriptor of a subtag + */ + private String subtagToString(int subtag) { + SUBTAG st = subTagHash.get((byte) subtag); + if (st == null) { + return "BOGUS_SUBTAG:" + subtag; + } + return st.tagName; + } + + /** + * Safely gets the string value of any Constant at any CP index. + */ + public String StringValue(int cpx) { + if (!inRange(cpx)) { + return "".formatted(cpx); + } + Constant cnst = pool.get(cpx); + if (cnst == null) { + return ""; + } + return cnst.stringVal(); + } + + /** + * Safely gets the string value of any Constant at any CP index. This string is either + * a Constant's String value or a CP index reference string. The Constant string has + * a tag descriptor in the beginning. + */ + public String ConstantStrValue(int cpx) { + if (cpx == 0 || !inRange(cpx)) { + return "#" + cpx; + } + Constant cns = pool.get(cpx); + if (cns == null) { + return "#" + cpx; + } + if (cns instanceof CPX2 cns2) { + if (cns2.value == classData.this_cpx && cns2.refersClassMember()) { + cpx = cns2.value2; + } + } + return cns.tag.tagName + " " + StringValue(cpx); + } + + @Override + public boolean isTableOutput() { + return tableFormat; + } + + @Override + protected void jasmPrint() { + int size; + if (extraDetailedOutput && !skipComments) { + printIndentLn("// %s:".formatted(tableToken.printKey())); + } + for (int idx = 1; idx < pool.size(); idx += size) { + Constant cns = pool.get(idx); + printIndent(this.CPXPlaceHolder, idx); + if (cns == null) { + size = 0; + printIndentLn("null;"); + } else { + size = cns.size(); + cns.setCommentPadding(getCommentPadding()); + // simple printing + cns.jasmPrint(toolOutput, this.tagPadding); + + } + } + printIndentLn(); + } + + @Override + protected void tablePrint() { + int size; + if (extraDetailedOutput && !skipComments) { + printIndentLn("// %s:".formatted(tableToken.printKey())); + } + for (int idx = 1; idx < pool.size(); idx += size) { + Constant cns = pool.get(idx); + printIndent(this.CPXPlaceHolder, idx); + if (cns == null) { + size = 0; + printIndentLn("null;"); + } else { + size = cns.size(); + cns.setCommentPadding(getCommentPadding()); + // extended printing + cns.tablePrint(toolOutput, this.tagPadding); + } + } + printIndentLn(); + } + + private String CPXPlaceHolder = ""; + private int CPXPlaceHolderLength = 0; + private int CPXLength = 0; + private int tagPadding = 0; + + /** + * Initialize printing data once the pool was read. + * Prepare offsets, paddings, etc. needed for printing + */ + protected ConstantPool InitializePrintData() { + int maxTagNameLength = pool.stream().mapToInt(elem -> (elem == null) ? 4 : + elem.tag.getPrintWidth(tableFormat)).max().orElse(10); + this.CPXLength = pool.size() > 100 ? 4 : 3; + // similar to javap format like this: + // Constant pool: + // #1 = Methodref #2.#3 // java/lang/Object."":()V + // #2 = Class #4 // java/lang/Object + // if (javap-like format) :: + // int maxTagAliasLength = pool.stream().mapToInt(elem -> (elem == null) ? 4 : + // elem.tag.tagAlias().length()).max().orElse(10); + // this.tagPadding = maxTagAliasLength + 1; + // this.CPXPlaceHolder = "%" + CPXLength + "s = ".formatted("#%d"); + this.tagPadding = maxTagNameLength + 1; + this.CPXPlaceHolder = "const #%-" + CPXLength + "d = "; + this.CPXPlaceHolderLength = this.CPXPlaceHolder.formatted(pool.size()).length(); + // --const #XX = --TagPadding-|--commentPadding---// + // --const #25 = class--------|#34;---------------// TesterInfo$Priority + // --#XX = + // IIhhhhhhhhhhhhTTTTTTTTTTTTTCCCCCCCCCCCCCCCCCCCC + // 123456789012345678901234567890123 4567890123456789012 + // II + hhhhhhhhhhhhhhhhhhhhhhhh + TTTTTTTTTT + CCCCCCCCCCCCCCCCCCC + this.commentOffset = getIndentSize() + this.CPXPlaceHolderLength + tagPadding + this.getCommentPadding(); + return this; + } + + public int getCommentPadding() { + return max(COMMENT_PADDING, tagPadding); + } + + public List getIssues() { + return this.pool.stream().filter(Objects::nonNull). + flatMap(constant -> constant.getIssues().stream().filter(Objects::nonNull)). + toList(); + } + + public CPX2 getCPX2(TAG tag) { + return new CPX2(tag); + } + + public boolean CheckEntryType(int cpIndex, TAG... tags) { + Constant cell = getConst(cpIndex); + if (cell != null) { + return cell.tag.belongsTo(tags); + } + return false; + } + + public TAG getTag(int cpIndex) { + Constant cell = getConst(cpIndex); + if (cell != null) { + return cell.tag; + } + return null; + } + + + /** + * TAG - A Tag descriptor of constants in the constant pool + */ + public enum TAG { + CONSTANT_NULL((byte) 0, "null", "CONSTANT_NULL", 1), + CONSTANT_UTF8((byte) 1, "Utf8", "CONSTANT_UTF8", 1), + // Obsolete CONSTANT_UNICODE((byte) 2, "unicode", "CONSTANT_UNICODE", 1), + CONSTANT_INTEGER((byte) 3, "int", "Integer", "CONSTANT_INTEGER", 1), + CONSTANT_FLOAT((byte) 4, "float", "Float", "CONSTANT_FLOAT", 1), + CONSTANT_LONG((byte) 5, "long", "Long", "CONSTANT_LONG", 2), + CONSTANT_DOUBLE((byte) 6, "double", "Double", "CONSTANT_DOUBLE", 2), + CONSTANT_CLASS((byte) 7, "class", "Class", "CONSTANT_CLASS", 1), + CONSTANT_STRING((byte) 8, "String", "CONSTANT_STRING", 1), + CONSTANT_FIELD((byte) 9, "Field", "Fieldref", "CONSTANT_FIELD", 1), + CONSTANT_METHOD((byte) 10, "Method", "Methodref", "CONSTANT_METHOD", 1), + CONSTANT_INTERFACEMETHOD((byte) 11, "InterfaceMethod", "InterfaceMethodref", "CONSTANT_INTERFACEMETHOD", 1), + CONSTANT_NAMEANDTYPE((byte) 12, "NameAndType", "CONSTANT_NAMEANDTYPE", 1), + CONSTANT_METHODHANDLE((byte) 15, "MethodHandle", "CONSTANT_METHODHANDLE", 1), + CONSTANT_METHODTYPE((byte) 16, "MethodType", "CONSTANT_METHODTYPE", 1), + CONSTANT_DYNAMIC((byte) 17, "Dynamic", "CONSTANT_DYNAMIC", 1), + CONSTANT_INVOKEDYNAMIC((byte) 18, "InvokeDynamic", "CONSTANT_INVOKEDYNAMIC", 1), + CONSTANT_MODULE((byte) 19, "Module", "CONSTANT_MODULE", 1), + CONSTANT_PACKAGE((byte) 20, "Package", "CONSTANT_PACKAGE", 1); + + private final Byte value; + private final String tagName; + private final String tagAlias; + private final String printValue; + private final int size; + + TAG(byte value, String tagName, String printValue, int size) { + this.value = value; + this.tagName = tagName; + this.tagAlias = ""; + this.printValue = printValue; + this.size = size; + } + + TAG(byte value, String tagName, String tagAlias, String printValue, int size) { + this.value = value; + this.tagName = tagName; + this.tagAlias = tagAlias; + this.printValue = printValue; + this.size = size; + } + + public String printValue() { + String[] strings = this.name().split("_"); + return strings[0] + "_" + + strings[1].substring(0, 1).toUpperCase() + + strings[1].substring(1).toLowerCase(); + } + + public boolean belongsTo(TAG... tags) { + for (TAG tag : tags) { + if (this.value.equals(tag.value)) { + return true; + } + } + return false; + } + + public byte value() { + return value; + } + + public String tagName() { + return tagName; + } + + public int getPrintWidth(boolean tableFormat) { + String str = tableFormat ? this.tagAlias() : this.tagName; + return str.length(); + } + + public String tagAlias() { + return tagAlias.isEmpty() ? tagName : tagAlias; + } + + public int size() { + return size; + } + + @Override + public String toString() { + return "<" + tagName + "> "; + } + } + + /** + * SUBTAG - A Tag descriptor of form method-handle constants + */ + public enum SUBTAG { + REF_GETFIELD((byte) 1, "REF_getField", "REF_GETFIELD"), + REF_GETSTATIC((byte) 2, "REF_getStatic", "REF_GETSTATIC"), + REF_PUTFIELD((byte) 3, "REF_putField", "REF_PUTFIELD"), + REF_PUTSTATIC((byte) 4, "REF_putStatic", "REF_PUTSTATIC"), + REF_INVOKEVIRTUAL((byte) 5, "REF_invokeVirtual", "REF_INVOKEVIRTUAL"), + REF_INVOKESTATIC((byte) 6, "REF_invokeStatic", "REF_INVOKESTATIC"), + REF_INVOKESPECIAL((byte) 7, "REF_invokeSpecial", "REF_INVOKESPECIAL"), + REF_NEWINVOKESPECIAL((byte) 8, "REF_newInvokeSpecial", "REF_NEWINVOKESPECIAL"), + REF_INVOKEINTERFACE((byte) 9, "REF_invokeInterface", "REF_INVOKEINTERFACE"); + + private final Byte value; + private final String tagName; + private final String printValue; + + SUBTAG(byte val, String tagName, String printValue) { + value = val; + this.tagName = tagName; + this.printValue = printValue; + } + + public byte value() { + return value; + } + + public String description() { + return printValue; + } + + @Override + public String toString() { + return "<" + tagName + "> "; + } + } + + /** + * Constant - Base class of all constant entries + */ + public abstract class Constant { + // tag the descriptor for the constant + protected final TAG tag; + protected final T value; + private final List issues = new ArrayList<>(); + // comment shift is used by the print method + protected int commentPadding = Indenter.COMMENT_PADDING; + + public Constant(TAG tag, T value) { + this.tag = tag; + this.value = value; + } + + public void jasmPrint(ToolOutput out, int spacePadding) { + out.prints(PadRight(tag.tagName(), spacePadding)); + } + + public void tablePrint(ToolOutput out, int spacePadding) { + out.prints(PadRight(tag.tagAlias(), spacePadding)); + } + + public int size() { + return 1; + } + + public List getIssues() { + return issues; + } + + public void setIssue(IOException value) { + issues.add(value); + } + + public void setCommentPadding(int commentPadding) { + this.commentPadding = commentPadding; + } + + public String stringVal() { + return String.valueOf(value); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Constant)) return false; + Constant constant = (Constant) o; + if (tag != constant.tag) return false; + return value.equals(constant.value); + } + + @Override + public int hashCode() { + int result = tag.hashCode(); + result = 31 * result + value.hashCode(); + return result; + } + + @Override + public String toString() { + return "".formatted(tag, stringVal()); + } + } + + /** + * CP_Str - Constant entries that contain String data. usually is a CONSTANT_UTF8 + */ + class CP_Str extends Constant { + + CP_Str(TAG tag, String value) { + super(tag, value); + } + + public String stringVal() { + return StringUtils.Utf8ToString(value, "\""); + } + + + @Override + public void jasmPrint(ToolOutput out, int spacePadding) { + super.jasmPrint(out, spacePadding); + out.printlns(stringVal() + ";"); + } + + @Override + public void tablePrint(ToolOutput out, int spacePadding) { + super.tablePrint(out, spacePadding); + // out.printlns(StringUtils.Utf8ToString(value)); + out.printlns(stringVal() + ";"); + } + } + + /** + * CP_Int - Constant entries that contain Integer data. usually is a CONSTANT_INTEGER + */ + class CP_Int extends Constant { + + CP_Int(TAG tag, int value) { + super(tag, value); + } + + @Override + public String stringVal() { + return classData.printHEX ? HexUtils.toHex(value) : value.toString(); + } + + @Override + public void jasmPrint(ToolOutput out, int spacePadding) { + super.jasmPrint(out, spacePadding); + out.printlns(stringVal() + ";"); + } + + @Override + public void tablePrint(ToolOutput out, int spacePadding) { + super.tablePrint(out, spacePadding); + // out.printlns(stringVal()); + out.printlns(stringVal() + ";"); + } + } + + /** + * CP_Long - Constant entries that contain LongInteger data. usually is a CONSTANT_LONG + * These take up 2 slots in the constant pool. + */ + class CP_Long extends Constant { + + CP_Long(TAG tag, long value) { + super(tag, value); + } + + @Override + public String stringVal() { + return classData.printHEX ? HexUtils.toHex(value) + 'l' : value.toString() + 'l'; + } + + + @Override + public void jasmPrint(ToolOutput out, int spacePadding) { + super.jasmPrint(out, spacePadding); + out.printlns(stringVal() + ";"); + } + + @Override + public void tablePrint(ToolOutput out, int spacePadding) { + super.tablePrint(out, spacePadding); + // out.printlns(stringVal()); + out.printlns(stringVal() + ";"); + } + + @Override + public int size() { + return 2; + } + } + + /** + * CP_Float - Constant entries that contain Float data. usually is a CONSTANT_FLOAT + */ + class CP_Float extends Constant { + + CP_Float(TAG tag, float value) { + super(tag, value); + } + + @Override + public String stringVal() { + if (classData.printHEX) { + return "bits " + HexUtils.toHex(Float.floatToIntBits(value)); + } + String sf = (value).toString(); + if (value.isNaN() || value.isInfinite()) { + return sf; + } + return sf + "f"; + } + + @Override + public void jasmPrint(ToolOutput out, int spacePadding) { + super.jasmPrint(out, spacePadding); + out.printlns(stringVal() + ";"); + } + + @Override + public void tablePrint(ToolOutput out, int spacePadding) { + super.tablePrint(out, spacePadding); + // out.printlns(stringVal()); + out.printlns(stringVal() + ";"); + + } + } + + /** + * CP_Double - Constant entries that contain double-precision float data. usually is a CONSTANT_DOUBLE + * These take up 2 slots in the constant pool. + */ + class CP_Double extends Constant { + + CP_Double(TAG tag, double value) { + super(tag, value); + } + + @Override + public String stringVal() { + if (classData.printHEX) { + return "bits " + HexUtils.toHex(Double.doubleToLongBits(value)) + 'l'; + } + String sd = value.toString(); + if (value.isNaN() || value.isInfinite()) { + return sd; + } + return sd + "d"; + } + + @Override + public void jasmPrint(ToolOutput out, int spacePadding) { + super.jasmPrint(out, spacePadding); + out.printlns(stringVal() + ";"); + } + + @Override + public void tablePrint(ToolOutput out, int spacePadding) { + super.tablePrint(out, spacePadding); + // out.printlns(stringVal()); + out.printlns(stringVal() + ";"); + } + + @Override + public int size() { + return 2; + } + } + + /** + * CPX - Constant entries that contain a single constant-pool index. Usually, this includes: + * CONSTANT_CLASS CONSTANT_METHODTYPE CONSTANT_STRING CONSTANT_MODULE CONSTANT_PACKAGE + */ + class CPX extends Constant { + + // value is Constant Pool index + CPX(TAG tag, int cpx) { + super(tag, cpx); + } + + @Override + public String stringVal() { + String str = "UnknownTag"; + switch (tag) { + case CONSTANT_CLASS -> str = getShortClassName(getClassName(this), classData.packageName); + case CONSTANT_PACKAGE, CONSTANT_MODULE -> str = getString(value, index -> "#" + index); + case CONSTANT_METHODTYPE, CONSTANT_STRING -> str = StringValue(value); + default -> { + } + } + return str; + } + + @Override + public void jasmPrint(ToolOutput out, int spacePadding) { + super.jasmPrint(out, spacePadding); + print(); + } + + @Override + public void tablePrint(ToolOutput out, int spacePadding) { + super.tablePrint(out, spacePadding); + print(); + } + + // Identical printing part for both JASM (simple) and extended (table) formats. + private void print() { + switch (tag) { + case CONSTANT_CLASS, CONSTANT_STRING, CONSTANT_METHODTYPE, CONSTANT_PACKAGE, CONSTANT_MODULE -> { + if (skipComments) { + println("#" + value + ";"); + } else { + printPadRight("#" + value + ";", commentPadding).println(" // " + stringVal()); + } + } + default -> { + } + } + } + + } + + /** + * CPX2 - Constant entries that contain two constant-pool indices. Usually, this includes: + * CONSTANT_FIELD CONSTANT_METHOD CONSTANT_INTERFACEMETHOD CONSTANT_NAMEANDTYPE + * CONSTANT_METHODHANDLE CONSTANT_DYNAMIC CONSTANT_INVOKEDYNAMIC + */ + public class CPX2 extends Constant { + + protected final int value2; + + // stack to control circular references in bsm arguments. + final Stack stack = new Stack<>(); + + CPX2(TAG tag, int cpx1, int cpx2) { + super(tag, cpx1); + this.value2 = cpx2; + } + + CPX2(TAG tag) { + super(tag, 0); + this.value2 = 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CPX2)) return false; + if (!super.equals(o)) return false; + CPX2 cpx2 = (CPX2) o; + return value2 == cpx2.value2; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + value2; + return result; + } + + @Override + public String stringVal() { + String str = "UnknownTag"; + switch (tag) { + case CONSTANT_FIELD: + // CODETOOLS-7902660: the tag Field is not necessary while printing static parameters of a bsm + // Example: MethodHandle REF_getField:ClassName.FieldName:"I" + str = getShortClassName(getClassName(value), classData.packageName) + "." + StringValue(value2); + break; + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + // CODETOOLS-7902648: added printing of the tag: Method/Interface to clarify + // interpreting CONSTANT_MethodHandle_info:reference_kind + // Example: invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap + str = getPrintedTAG(tag) + getShortClassName(getClassName(value), classData.packageName) + "." + + StringValue(value2); + break; + case CONSTANT_NAMEANDTYPE: + str = getName(value) + ":" + StringValue(value2); + break; + case CONSTANT_METHODHANDLE: + str = subtagToString(value) + ":" + StringValue(value2); + break; + case CONSTANT_DYNAMIC: + case CONSTANT_INVOKEDYNAMIC: + int bsmAttributeIndex = value; + int nameTypeIndex = value2; + BootstrapMethodData bsmData; + try { + bsmData = classData.bootstrapMethods.get(bsmAttributeIndex); + } catch (NullPointerException npe) { + return ""; + } catch (IndexOutOfBoundsException ioobe) { + return ""; + } + int bsm_ref = bsmData.bsmRef; + str = "%s:%s%s".formatted(StringValue(bsm_ref), + StringValue(nameTypeIndex), + bsmArgsAsString(bsmData, "{", "}")); + default: + break; + } + return str; + } + + public String bsmArgsAsString(BootstrapMethodData bsmData) { + return bsmArgsAsString(bsmData, "", ""); + } + + public String bsmArgsAsString(BootstrapMethodData bsmData, String LeftBracket, String RightBracket) { + StringBuilder sb = new StringBuilder(); + int bsmArgsLen = bsmData.bsmArguments.size(); + sb.append(LeftBracket); + if (bsmArgsLen > 0) { + for (int i = 0; i < bsmArgsLen; i++) { + int bsmArgIdx = bsmData.bsmArguments.get(i); + boolean notLastIdx = i != bsmArgsLen - 1; + sb.append(bsmArgAsString(bsmArgIdx, notLastIdx)); + } + } + sb.append(RightBracket); + return sb.toString(); + } + + public String bsmArgAsString(int bsmArgIdx, boolean notLastIdx) { + return bsmArgAsString(bsmArgIdx, notLastIdx ? ARGUMENT_DELIMITER : "", notLastIdx ? LINE_SPLITTER : ""); + } + + public String bsmArgWithoutDelimitersAsString(int bsmArgIdx, boolean notLastIdx) { + return bsmArgAsString(bsmArgIdx, "", notLastIdx ? LINE_SPLITTER : ""); + } + + + public String bsmArgAsString(int bsmArgIdx, String argDelimiter, String lineSplitter) { + String str = ""; + if (inRange(bsmArgIdx)) { + Constant cnt = pool.get(bsmArgIdx); + if (stack.search(this) == -1) { + stack.push(this); + str = str.concat(ConstantStrValue(bsmArgIdx)).concat(argDelimiter); + stack.pop(); + } else { + String ref; + if (cnt instanceof CPX2) { + ref = format("%-8s %d:#%d; ", cnt.tag.tagName(), cnt.value, ((CPX2) cnt).value2); + } else { + ref = format("%-8s #%d; ", cnt.tag.tagName(), cnt.value); + } + String msg = "circular reference to " + cnt.tag.tagName() + " #" + bsmArgIdx; + if (printCPIndex) { + str = str.concat(PadRight(ref, CIRCULAR_COMMENT_OFFSET)).concat("<").concat(msg).concat(">").concat(argDelimiter); + } else { + str = str.concat(PadRight(ref, CIRCULAR_COMMENT_OFFSET)).concat(" // <").concat(msg).concat(">").concat(lineSplitter); + } + cnt.setIssue(new IOException(msg)); + } + } else { + str = environment.getInfo("info.corrupted_cp_entry"); + } + return str; + } + + @Override + public void jasmPrint(ToolOutput out, int spacePadding) { + super.jasmPrint(out, spacePadding); + print(); + } + + @Override + public void tablePrint(ToolOutput out, int spacePadding) { + super.tablePrint(out, spacePadding); + print(); + } + + // Identical printing part for both JASM (simple) and extended (table) formats. + private void print() { + if (skipComments) { + switch (tag) { + case CONSTANT_FIELD, CONSTANT_METHOD, CONSTANT_INTERFACEMETHOD -> + println("#%d.#%d;", value, value2); + case CONSTANT_METHODHANDLE, CONSTANT_DYNAMIC, CONSTANT_INVOKEDYNAMIC -> + println("%d:#%d;", value, value2); + case CONSTANT_NAMEANDTYPE -> println("#%d:#%d;", value, value2); + default -> + printPadRight(format("%d:#%d;", value, value2), commentPadding).println(" // unknown tag: " + tag.tagName); + } + } else { + switch (tag) { + case CONSTANT_FIELD, CONSTANT_METHOD, CONSTANT_INTERFACEMETHOD -> + printPadRight(format("#%d.#%d;", value, value2), commentPadding).println(" // " + stringVal()); + case CONSTANT_METHODHANDLE -> + printPadRight(format("%d:#%d;", value, value2), commentPadding).println(" // " + stringVal()); + case CONSTANT_NAMEANDTYPE -> + printPadRight(format("#%d:#%d;", value, value2), commentPadding).println(" // " + stringVal()); + case CONSTANT_DYNAMIC, CONSTANT_INVOKEDYNAMIC -> + printPadRight(format("%d:#%d;", value, value2), commentPadding).println(" // #%d:%s", value, StringValue(value2)); + default -> + printPadRight(format("%d:#%d;", value, value2), commentPadding).println(" // unknown tag: " + tag.tagName); + } + } + } + + + public boolean refersClassMember() { + return tag == TAG.CONSTANT_FIELD || tag == TAG.CONSTANT_METHOD || tag == TAG.CONSTANT_INTERFACEMETHOD; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Container.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Container.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Container.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Container.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.TableFormatModel; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Spliterator; +import java.util.function.Consumer; + +public class Container> extends Indenter implements Iterable, Measurable { + + protected final ArrayList elements; + protected M owner; + + public Container(M owner, Class elementClass, int initialCapacity) { + this.owner = owner; + this.elements = new ArrayList<>(initialCapacity); + this.tableToken = TableFormatModel.Token.getBy(elementClass); + } + + protected final boolean isCollectionMeasurable() { + return (!this.elements.isEmpty() && elements.get(0) instanceof Measurable); + } + + @Override + public void print() throws IOException { + int size = this.size(); + if (size > 0) { + boolean isExtendedPrintingSupported = tableToken.isExtendedPrintingSupported(); + setMaxPrintSize(getPrintSize()); + for (int i = 0; i < size; i++) { + T element = elements.get(i); + if (element instanceof Measurable measurable) { + measurable.setMaxPrintSize(this.getMaxPrintSize()); + } + element.setCommentOffset(this.getCommentOffset()); + if (isExtendedPrintingSupported && isTableOutput()) + element.tablePrint(i, size); + else + element.jasmPrint(i, size); + } + } + } + + public void add(T element) throws IOException { + if (element instanceof MemberData md) { + ((MemberData) md).setOwner(this.owner); + } + elements.add(element); + } + + public int size() { + return elements.size(); + } + + public T get(int index) { + return elements.get(index); + } + + @Override + public boolean isPrintable() { + return !elements.isEmpty() && + elements.stream().anyMatch(Printable::isPrintable); + } + + /** + * Calculates max print size of elements in a collection if they are measurable + * In the case of s collection the print size is equal to max print size + * + * @return maxSize or 0 + */ + @Override + public int getPrintSize() { + if (!maxSizeCalculated && isCollectionMeasurable()) { + this.maxSize = isCollectionMeasurable() ? + elements.stream().map(e -> (Measurable) e). + mapToInt(Measurable::getPrintSize).max().orElse(0) : 0; + maxSizeCalculated = true; + } + return this.maxSize; + } + + /** + * Sets max print size to all elements of the collection + */ + @Override + public void setMaxPrintSize(int maxSize) { + if (maxSize > 0 && isCollectionMeasurable()) { + elements.stream().map(e -> (Measurable) e).peek(e -> e.setMaxPrintSize(maxSize)); + } + } + + /** + * Calculates max print size of elements in a collection if they are measurable + * In the case of s collection the print size is equal to max print size + * + * @return maxSize or 0 + */ + @Override + public int getMaxPrintSize() { + return getPrintSize(); + } + + /** + * Set up print-ability of cartage + * + * @param value print-ability + * @return the instance + */ + public Container setPrintable(boolean value) { + printable = value; + return this; + } + + /** + * Set up measure-ability of cartage + * + * @param value can be measured + * @return the instance + */ + public Container setHasSize(boolean value) { + hasSize = true; + return this; + } + + @Override + public Iterator iterator() { + return elements.iterator(); + } + + @Override + public void forEach(Consumer action) { + elements.forEach(action); + } + + @Override + public Spliterator spliterator() { + return elements.spliterator(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Element.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Element.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Element.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Element.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +/** + * The element of the class Container that belongs to the owner M + */ +public class Element> extends Indenter { + protected M owner; + protected Container container; + + public Element(M owner, Container container) { + super(owner.toolOutput); + this.owner = owner; + this.container = container; + } + + @Override + public int getCommentOffset() { + return container.getCommentOffset(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/EnclosingMethodData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/EnclosingMethodData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/EnclosingMethodData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/EnclosingMethodData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.ENCLOSING_METHOD; + +/** + * The EnclosingMethod attribute since 45.3 + *

+ * EnclosingMethod_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 class_index; + * u2 method_index; that is equal to CONSTANT_NameAndType_info_index; + * } + */ +public class EnclosingMethodData extends AttributeData { + + public EnclosingMethodData(ClassData classData) { + super(classData, ENCLOSING_METHOD); + } + + public String calculateName() { + if (this.name == null) { + if (printCPIndex) { + this.name = (pool.getClassName(cpx, index -> logger.getResourceString("info.invalid_cp_entry"))); + } else { + this.name = "\"". + concat(pool.getClassName(cpx, index -> "%s #%d". + formatted(logger.getResourceString("info.invalid_cp_entry"), index))). + concat("\""); + } + if (this.methodCpx != 0) { + this.name += ":" + pool.getMethodName(this.methodCpx); + } + } + return this.name; + } + + public EnclosingMethodData getName() { + name = pool.getString(cpx, index -> "#%d".formatted(index)); + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ExceptionData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ExceptionData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ExceptionData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ExceptionData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; + +import static org.openjdk.asmtools.jasm.JasmTokens.Token.THROWS; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.EXCEPTIONS; + +/** + * Exceptions_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_exceptions; + * u2 exception_index_table[number_of_exceptions]; + * } + */ +public class ExceptionData extends ClassArrayData { + private int keywordPadding = -1; + + public ExceptionData(ClassData classData) { + super(classData, THROWS); + tableToken = EXCEPTIONS; + } + + public ExceptionData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + return (ExceptionData) super.read(in, attribute_length); + } + + public ExceptionData setKeywordPadding(int keywordPadding) { + this.keywordPadding = keywordPadding; + return this; + } + @Override + protected int getPrintAttributeKeyPadding() { + return keywordPadding == -1 ? super.getPrintAttributeKeyPadding() : keywordPadding; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/FieldData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/FieldData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/FieldData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/FieldData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,231 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.structure.ClassFileContext; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.ELocation; +import org.openjdk.asmtools.common.structure.EModifier; +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.List; + +import static java.lang.Math.max; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.SIGNATURE; +import static org.openjdk.asmtools.jdis.ConstantPool.TAG.*; + +/** + * Field data for field members in a class of the Java Disassembler + */ +public class FieldData extends MemberData implements Measurable { + + // CP index to the field name + protected int name_cpx; + // CP index to the field type + protected int type_cpx; + // CP index to the field value + protected int value_cpx = UNDEFINED; + + public FieldData(ClassData classData) { + super(classData); + memberType = "FieldData"; + } + + @Override + protected boolean handleAttributes(DataInputStream in, EAttribute attributeTag, int attributeLength) throws IOException { + // Read the Attributes + boolean handled = true; + switch (attributeTag) { + case ATT_Signature -> { + if (signature != null) { + environment.warning("warn.one.attribute.required", + EAttribute.ATT_Signature.printValue(), ELocation.field_info.toString()); + } + signature = new SignatureData(data).read(in, attributeLength); + } + case ATT_ConstantValue -> { + if (attributeLength != 2) { + if (bestEffort) { + environment.error("err.invalid.attribute.length", EAttribute.ATT_ConstantValue.printValue(), attributeLength); + } else { + throw new FormatError(environment.getLogger(), + "err.invalid.attribute.length", EAttribute.ATT_ConstantValue.printValue(), attributeLength); + } + } + if (getListOf(EAttribute.ATT_ConstantValue).size() > 1) { + environment.warning("warn.one.attribute.required", + EAttribute.ATT_ConstantValue.printValue(), ELocation.field_info.toString()); + } + value_cpx = in.readUnsignedShort(); + if (!pool.inRange(value_cpx)) { + environment.warning("warn.attribute.constantvalue.incorrect", value_cpx); + } else { + if (!pool.CheckEntryType(value_cpx, CONSTANT_INTEGER, CONSTANT_FLOAT, CONSTANT_DOUBLE, CONSTANT_LONG, CONSTANT_STRING)) { + ConstantPool.TAG tag = pool.getTag(value_cpx); + String tagName = tag == null ? "unknown" : tag.printValue(); + environment.warning("warn.attribute.type.incorrect", tagName); + } + } + } + default -> handled = false; + } + return handled; + } + + @Override + protected boolean handleUnrecognizedAttributes(DataInputStream in, int attributeNameCpx, int attributeLength) throws IOException { + if (!data.pool.inRange(attributeNameCpx)) { + environment.warning("warn.attribute.name.corrupted", attributeNameCpx); + } else { + environment.warning("warn.attribute.name.incorrect", attributeNameCpx); + } + return false; + } + + /** + * Read and resolve the field data called from ClassData. + * Precondition: NumFields has already been read from the stream. + */ + public void read(DataInputStream in) throws IOException { + // read the Fields CP indexes + access = in.readUnsignedShort(); + name_cpx = in.readUnsignedShort(); + type_cpx = in.readUnsignedShort(); + // Read the attributes + readAttributes(in); + // + environment.traceln(() -> + "FieldData: name[%d]=%s type[%d]=%s%s".formatted( + name_cpx, data.pool.getString(name_cpx, index -> "#%d?".formatted(index)), + type_cpx, data.pool.getString(type_cpx, index -> "#%d?".formatted(index)), + signature != null ? signature : "")); + } + + /** + * Prints the field data to the current output stream called from ClassData. + */ + @Override + protected void jasmPrint(int index, int size) throws IOException { + boolean printSignature = signature != null && signature.isPrintable() && tableFormat; + // Print annotations first + super.printAnnotations(visibleAnnotations, invisibleAnnotations); + super.printAnnotations(visibleTypeAnnotations, invisibleTypeAnnotations); + if (getListOf(EAttribute.ATT_Unrecognized).size() > 0) { + List list = getListOf(EAttribute.ATT_Unrecognized); + for (AttrData attr : list) { + printIndentLn("// Ignored unrecognized attribute: { u2 #%d; u4 %d; u1[ %s ]; }". + formatted(attr.getNameCpx(), attr.getLength(), attr.dataAsString())); + } + } + + if (!printCPIndex && value_cpx != UNDEFINED && !pool.CheckEntryType(value_cpx, CONSTANT_INTEGER, CONSTANT_FLOAT, + CONSTANT_DOUBLE, CONSTANT_LONG, CONSTANT_STRING)) { + ConstantPool.TAG tag = pool.getTag(value_cpx); + String tagName = tag == null ? "unknown" : tag.printValue(); + printIndentLn("// ".concat(environment.getInfo("warn.attribute.constantvalue.unrecognized",value_cpx, tagName))); + } + // print field + StringBuilder prefix = new StringBuilder(getIndentString()). + append(EModifier.asKeywords(access, ClassFileContext.FIELD)); + // add synthetic, deprecated if necessary + prefix.append(getPseudoFlagsAsString()); + // field + prefix.append(JasmTokens.Token.FIELDREF.parseKey()).append(' '); + int keywordPadding = max(prefix.length() - getIndentSize() * 2, SIGNATURE.parseKey().length() + getIndentSize()); + printVar(prefix, + (value_cpx != UNDEFINED) ? getConstantValue(" = ") : null, + printSignature ? ":" : ";", + name_cpx, type_cpx, value_cpx); + // print Signature if necessary + if (printSignature) { + signature.setKeywordPadding(keywordPadding). + incIndent(). + setCommentOffset(this.getCommentOffset() - getIndentStep() * 2); + signature.print(); + } + } + + private String getConstantValue(String prefix) { + if (!printCPIndex && + value_cpx != UNDEFINED && + !pool.CheckEntryType(value_cpx, CONSTANT_INTEGER, CONSTANT_FLOAT, CONSTANT_DOUBLE, CONSTANT_LONG, CONSTANT_STRING)) { + return ""; + } else { + return prefix.concat(data.pool.ConstantStrValue(value_cpx)); + } + } + + + /** + * Prints the field data to the current output stream called from ClassData. + */ + @Override + protected void tablePrint(int index, int size) throws IOException { + //There are no differences between the simple (jasm) and extended (table) presentations of field info. + this.jasmPrint(index, size); + } + + private String getFieldDefinitionString() { + if (printCPIndex && !skipComments) { + StringBuilder sb = new StringBuilder(EModifier.asKeywords(access, ClassFileContext.FIELD)); + // add synthetic, deprecated if necessary + sb.append(getPseudoFlagsAsString()); + // field + sb.append(JasmTokens.Token.FIELDREF.parseKey()).append(' '); + sb.append('#').append(name_cpx).append(":#").append(type_cpx); + if (signature != null && !signature.isPrintable()) { + sb.append(":#").append(signature.getCPIndex()); + } + if (value_cpx != UNDEFINED) { + sb.append(" = #").append(value_cpx); + } + sb.append(';'); + return sb.toString(); + } + return ""; + } + + @Override + public int getCommentOffset() { + return Math.max(super.getCommentOffset(), this.maxSize + getIndentSize()); + } + + @Override + public int getPrintSize() { + String line = getFieldDefinitionString(); + return line.length(); + } + + @Override + public void setMaxPrintSize(int size) { + this.maxSize = size; + } + + @Override + public int getMaxPrintSize() { + return this.maxSize; + } +} // end FieldData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Indenter.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Indenter.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Indenter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Indenter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.jasm.TableFormatModel; + +import java.io.IOException; +import java.util.*; + +import static java.lang.System.lineSeparator; +import static org.openjdk.asmtools.jdis.Options.PrintOption.*; + +public abstract class Indenter implements Printable { + public static final int UNDEFINED = -1; + + public static final int INDENT_STEP = 2; + public static final int INDENT_OFFSET = 2; + public static final String INDENT_CHAR = " "; + public static final String INDENT_STRING = INDENT_CHAR.repeat(INDENT_STEP); + + // Global formatting strings + public static final String ARGUMENT_DELIMITER = "^"; + public static final String LINE_SPLITTER = "⾀"; + public static final String NO_BSM_ARGUMENTS = "{}"; + public static final String NO_BSM_ARGUMENTS_REGEX = "\\{\\}"; + public static final String REPLACEMENT_NO_BSM_ARGUMENTS = ""; + + // Global numbers + public static final int PROGRAM_COUNTER_PLACEHOLDER_LENGTH = 7; + public static final int INSTR_PREFIX_LENGTH = 7; + public static final int STACKMAP_TYPE_PLACEHOLDER_LENGTH = 18; + public static final int OPERAND_PLACEHOLDER_LENGTH = 17; + public static int TABLE_PADDING = OPERAND_PLACEHOLDER_LENGTH + INSTR_PREFIX_LENGTH + 1; + public static final int COMMENT_PADDING = (Options.contains(TABLE)) ? 16 : 20; + public static final int INITIAL_COMMENT_OFFSET = 0; // Initial offset that will be dynamically updated + + public static final int CIRCULAR_COMMENT_OFFSET = 25; + + protected final boolean tableFormat = Options.contains(TABLE); + protected final boolean sysInfo = Options.contains(SYSINFO); + protected final boolean detailedOutput = Options.contains(DETAILED_Output); + protected final boolean extraDetailedOutput = Options.contains(EXTRA_DETAILED_Output); + protected final boolean bestEffort = Options.contains(BEST_EFFORT); + + // Discard printing attributes + protected final boolean dropSourceFile = Options.contains(DROP_Source); + protected final boolean dropClasses = Options.contains(DROP_Classes); + protected final boolean dropSignatures = Options.contains(DROP_Signatures); + protected final boolean dropCharacterRange = Options.contains(DROP_CharacterRange); + + // Extra printing instruction + protected final boolean printLocalVariables = Options.contains(LOCAL_VARIABLE_All, LOCAL_VARIABLE_Vars); + protected final boolean printLocalVariableTypes = Options.contains(LOCAL_VARIABLE_All, LOCAL_VARIABLE_Types); + protected final boolean printLineNumber = Options.contains(LINE_NUMBER_TABLE_Numbers, LINE_NUMBER_TABLE_Lines, LINE_NUMBER_TABLE_Table, TABLE); + + // internal references + protected final boolean printCPIndex = Options.contains(CP_INDEX); + protected final boolean skipComments = Options.contains(NO_COMMENTS); + protected final boolean printProgramCounter = Options.contains(PRINT_BCI); + protected final boolean printLabelAsIdentifiers = Options.contains(LABELS) && !printProgramCounter; + protected final boolean printConstantPool = Options.contains(CONSTANT_POOL); + protected final boolean printSourceLines = Options.contains(LINE_NUMBER_TABLE_Lines); + protected final boolean printLineTable = Options.contains(LINE_NUMBER_TABLE_Table); + protected final boolean printLineTableLines = Options.contains(LINE_NUMBER_TABLE_Lines); + protected final boolean printLineTableNumbers = Options.contains(LINE_NUMBER_TABLE_Numbers); + protected final boolean printHEX = Options.contains(HEX); + // + protected boolean printable = true; + // indicated that an entity has a size in a collection + protected boolean hasSize = false; + protected TableFormatModel.Token tableToken = TableFormatModel.Token.NOT_SUPPORTED; + // + // the maximum size of the same elements in the collection to calculate printing bounds + // applies only to entities that implement Measurable interface. + protected int maxSize = 0; + protected boolean maxSizeCalculated = false; + // + protected ToolOutput toolOutput; + // + private final String LabelPrefix = printLabelAsIdentifiers ? "L" : ""; + // + protected int commentOffset = INITIAL_COMMENT_OFFSET; + private int length, offset, step; + private String fillString; + + /** + * If a table format is supported and the tool option TABLE is set, prints an object as a table entry. + */ + public void print() throws IOException { + if (isTableOutput()) { + tablePrint(); + } else { + jasmPrint(); + } + } + + public boolean isTableOutput() { + return this.tableFormatSupported() && tableFormat; + } + + @Override + public boolean tableFormatSupported() { + return tableToken.isExtendedPrintingSupported(); + } + + protected String getTitle() { + throw new NotImplementedException(this.getClass().getName()); + } + + protected void tablePrint() throws IOException { + throw new NotImplementedException(this.getClass().getName()); + } + + protected void jasmPrint() throws IOException { + throw new NotImplementedException(this.getClass().getName()); + } + + protected void tablePrint(int index, int size) throws IOException { + throw new NotImplementedException(this.getClass().getName()); + } + + protected void jasmPrint(int index, int size) throws IOException { + throw new NotImplementedException(this.getClass().getName()); + } + + public void print(int index, int size) throws IOException { + if (isTableOutput()) { + tablePrint(index, size); + } else { + jasmPrint(index, size); + } + } + + + public Indenter(ToolOutput toolOutput) { + this(); + this.toolOutput = toolOutput; + } + + protected Indenter() { + this.length = 0; + this.step = INDENT_STEP; + this.offset = INDENT_OFFSET; + this.fillString = INDENT_CHAR; + } + + protected String getLabelPrefix() { + return LabelPrefix; + } + + public Indenter printIndentLn(String s) { + toolOutput.printlns(Indent(s)); + return this; + } + + public Indenter printIndentLn() { + toolOutput.printlns(""); + return this; + } + + public int getIndentStep() { + return this.step; + } + + public Indenter printIndentLn(String format, Object... args) { + toolOutput.printlns(Indent(new Formatter().format(format, args).toString())); + return this; + } + + public Indenter printIndent(String format, Object... args) { + toolOutput.prints(Indent(new Formatter().format(format, args).toString())); + return this; + } + + public Indenter printIndent(String s) { + String str = Indent(s); + toolOutput.prints(str); + return this; + } + + public Indenter printIndent() { + toolOutput.prints(getIndentString()); + return this; + } + + public Indenter printPadRight(String s, int totalWidth) { + toolOutput.prints(PadRight(s, totalWidth)); + return this; + } + + public Indenter printPadLeft(String s, int totalWidth) { + toolOutput.prints(PadLeft(s, totalWidth)); + return this; + } + + public Indenter printIndentPadRight(String str, int totalWidth) { + toolOutput.prints(IndentPadRight(str, totalWidth)); + return this; + } + + public Indenter printIndentPadLeft(String str, int totalWidth) { + toolOutput.prints(IndentPadLeft(str, totalWidth)); + return this; + } + + public Indenter print(String s) { + toolOutput.prints(s); + return this; + } + + public Indenter print(String format, Object... args) { + toolOutput.prints(new Formatter().format(format, args).toString()); + return this; + } + + public Indenter println(String s) { + toolOutput.printlns(s); + return this; + } + + public Indenter println() { + toolOutput.printlns(""); + return this; + } + + public Indenter println(boolean isPrint) { + if (isPrint) { + toolOutput.printlns(""); + } + return this; + } + + public Indenter println(String format, Object... args) { + toolOutput.printlns(new Formatter().format(format, args).toString()); + return this; + } + + public Indenter incIndent() { + return incIndent(1); + } + + public Indenter decIndent() { + return decIndent(1); + } + + public Indenter incIndent(int count) { + length += step * count; + return this; + } + + public Indenter decIndent(int count) { + length -= step * count; + if (length < 0) { + length = 0; + } + return this; + } + + public Indenter setTheSame(Indenter that) { + this.length = that.length; + this.offset = that.offset; + this.step = that.step; + this.commentOffset = that.commentOffset; + this.fillString = that.fillString; + return this; + } + + public Indenter initIndent(int initialOffset) { + this.length = 0; + this.step = INDENT_STEP; + this.offset = initialOffset; + this.fillString = INDENT_CHAR; + return this; + } + + public int getIndentSize() { + return this.offset + this.length; + } + + public String nCopies(int n) { + // create a string made up of n copies of string fillString + return String.join("", Collections.nCopies(n < 0 ? 0 : n, this.fillString)); + } + + /** + * Creates indent string based on current indent size. + */ + public String getIndentString() { + return this.nCopies(this.getIndentSize()); + } + + /** + * Formats input string by adding indent string and padding spaces from the left. + * "[indent][PaddingSpaces][string]" + * -----totalWidth------- + */ + public String IndentPadLeft(String str, int totalWidth) { + return this.getIndentString() + PadLeft(str, totalWidth); + } + + /** + * Formats input string by adding indent string and padding spaces from the left. + * "[indent][string][PaddingSpaces]" + * -----totalWidth------- + */ + public String IndentPadRight(String str, int totalWidth) { + return this.getIndentString() + PadRight(str, totalWidth); + } + + /** + * Formats input string by adding indent string and padding spaces from the left. + * "[PaddingSpaces][string]" + * -----totalWidth------- + */ + public String PadLeft(String str, int totalWidth) { + if (totalWidth > 0) { + int count = totalWidth - str.length(); + if (count > 0) { + str = nCopies(count) + str; + } + } + return str; + } + + public String PadRight(String str, int totalWidth) { + if (totalWidth > 0) { + int count = totalWidth - str.length(); + if (count > 0) { + str = str + nCopies(count); + } + } + return str; + } + + public String padRight(String value, int width, char pad) { + if (value.length() >= width) + return value; + char[] buf = new char[width]; + Arrays.fill(buf, value.length(), width, pad); + value.getChars(0, value.length(), buf, 0); + return new String(buf); + } + + public String padLeft(String value, int width, char pad) { + if (value.length() >= width) + return value; + char[] buf = new char[width]; + int padLen = width - value.length(); + Arrays.fill(buf, 0, padLen, pad); + value.getChars(0, value.length(), buf, padLen); + return new String(buf); + } + + public String Indent(String str) { + return this.getIndentString() + str; + } + + public String enlargedIndent(String str, int shift) { + this.offset += shift; + str = Indent(str); + this.offset -= shift; + return str; + } + + public String enlargedIndent(int shift) { + return enlargedIndent("", shift); + } + + /** + * @return the common offset of comments for printing methods + */ + public int getCommentOffset() { + return commentOffset; + } + + public Indenter setCommentOffset(int commentOffset) { + this.commentOffset = commentOffset; + return this; + } + + /** + * @return the common offset of the indent + */ + public int getOffset() { + return offset; + } + + public Indenter setOffset(int offset) { + this.offset = offset; + return this; + } + + /** + * Calculates offsets for Class's attributes: + *

+ * 12AAAAAAAAAAAAAAAAAAAAAAAAAAACCCCCCCCCCCCCCCCC + * SourceFile #126; // TestMethods0.java + * 12 - Indent + * AAA.A - getPrintAttributeKeyPadding() + * CCC.C - getPrintAttributeCommentPadding() + * + * @return + */ + protected int getPrintAttributeKeyPadding() { + int instructionOffset = (printProgramCounter) ? PROGRAM_COUNTER_PLACEHOLDER_LENGTH : INSTR_PREFIX_LENGTH; + int attributeOffset = (printProgramCounter) ? instructionOffset : (instructionOffset - getIndentStep()); + return instructionOffset + attributeOffset + OPERAND_PLACEHOLDER_LENGTH - getIndentSize() * 2; + } + + protected int getPrintAttributeCommentPadding() { + return getCommentOffset() - getPrintAttributeKeyPadding(); + } + + public Indenter setHasSize(boolean hasSize) { + this.hasSize = hasSize; + return this; + } + + protected final static Map> InvokeDynamicBreakPositions = Map.of( + 0, List.of(2, 3), + 1, List.of(3), + 2, List.of(3)); + protected final static Map> LdwBreakPositions = Map.of( + 0, List.of(3), + 1, List.of(3), + 2, List.of(3)); + protected final static Map> BootstrapMethodBreakPositions = Map.of(0, List.of(2, 3)); + protected final static Map> BootstrapArgumentsBreakPositions = Map.of(0, List.of(3)); + + /** + * Formats invokedynamic/ldc dynamic operand line and Bootstrap arguments + * + * @param str non-formatted operand line + * @param offset indent for new lines + * @param prefix prefix placed upfront new lines + * @param breakPositions numbers where after ":" a lineSeparator is added to wrap a very long operand lines + * @return formatted operand line + */ + protected String formatOperandLine(String str, int offset, String prefix, Map> breakPositions) { + boolean noArgs = str.contains(NO_BSM_ARGUMENTS); + if (noArgs) { + str = str.replaceAll(NO_BSM_ARGUMENTS_REGEX, REPLACEMENT_NO_BSM_ARGUMENTS); + } + StringTokenizer st = new StringTokenizer(str, ":\"{}\\" + ARGUMENT_DELIMITER + LINE_SPLITTER, true); + StringBuilder sb = new StringBuilder(80); + boolean processTokens = true; + String prevToken = ""; + int nItems = 0, nLevel = 0; + while (st.hasMoreTokens()) { + String token = st.nextToken(); + List breaks = breakPositions.getOrDefault(nLevel, Collections.emptyList()); + switch (token) { + case ":": + sb.append(token); + if (processTokens) { + nItems++; + if (breaks.contains(nItems)) { + sb.append(lineSeparator()).append(nCopies(offset)).append(prefix). + append(nCopies(getIndentStep() * nLevel)); + } + } + break; + case "}": + if (processTokens) { + nLevel = (nLevel == 0) ? nLevel : nLevel - 1; + nItems = 0; + sb.append(lineSeparator()).append(nCopies(offset)). + append(prefix).append(nCopies(getIndentStep() * nLevel)).append(token); + } else + sb.append(token); + break; + case "{": + if (processTokens) { + nLevel++; + nItems = 0; + sb.append(" {").append(lineSeparator()).append(nCopies(offset)). + append(prefix).append(nCopies(getIndentStep() * nLevel)); + } else { + sb.append(token); + } + break; + case "\"": + if (!prevToken.equals("\\")) + processTokens = !processTokens; + sb.append(token); + break; + case ARGUMENT_DELIMITER: + if (processTokens) { + sb.append(',').append(lineSeparator()).append(nCopies(offset)). + append(prefix).append(nCopies(getIndentStep() * nLevel)); + nItems = 0; + } else { + sb.append(ARGUMENT_DELIMITER); + } + break; + case LINE_SPLITTER: + if (processTokens) { + sb.append(lineSeparator()).append(nCopies(offset)). + append(prefix).append(nCopies(getIndentStep() * nLevel)); + } else { + sb.append(ARGUMENT_DELIMITER); + } + break; + default: + sb.append(token); + break; + } + prevToken = token; + } + str = sb.toString(); + if (noArgs) { + str = str.replaceAll(REPLACEMENT_NO_BSM_ARGUMENTS, NO_BSM_ARGUMENTS); + } + return str; + } + + public static class NotImplementedException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public NotImplementedException(String where) { + super("".formatted(where)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InnerClassData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InnerClassData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InnerClassData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InnerClassData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.structure.ClassFileContext; +import org.openjdk.asmtools.common.structure.EModifier; + +import java.io.DataInputStream; +import java.io.IOException; + +import static java.lang.Math.max; +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.INNERCLASS; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.INNER_CLASSES; + +/** + * 4.7.6. The InnerClasses Attribute + */ +public class InnerClassData extends Element implements Measurable { + int inner_class_info_index; + int outer_class_info_index; + int inner_name_index; + int access; + + private int calculatedCommentOffset = 0; + private String jasmPrefix = Indent(PadRight(INNERCLASS.parseKey(), TABLE_PADDING)); + + public InnerClassData(ClassData classData, Container container) { + super(classData, container); + this.tableToken = INNER_CLASSES; + } + + @Override + public int getCommentOffset() { + if (this.calculatedCommentOffset == 0) { + if (isTableOutput()) { + this.calculatedCommentOffset = container.getCommentOffset() - getIndentStep(); + this.calculatedCommentOffset = max(this.calculatedCommentOffset, getMaxPrintSize()); + } else { + this.calculatedCommentOffset = container.getCommentOffset() - getIndentStep(); + calculatedCommentOffset = max(this.calculatedCommentOffset, getMaxPrintSize() + jasmPrefix.length()); + } + } + return calculatedCommentOffset; + } + + public void read(DataInputStream in) throws IOException { + inner_class_info_index = in.readUnsignedShort(); + outer_class_info_index = in.readUnsignedShort(); + inner_name_index = in.readUnsignedShort(); + access = in.readUnsignedShort(); + } // end read + + @Override + public void jasmPrint(int index, int size) throws IOException { + String line = jasmPrefix.concat(EModifier.asKeywords(access, ClassFileContext.INNER_CLASS)); + if (printCPIndex) { + line = getClassDefinitionString(line); + if (skipComments) { + print(line); + } else { + print(PadRight(line, this.getCommentOffset())).print(" // "); + } + } else { + print(line); + } + if (!printCPIndex || (printCPIndex && !skipComments)) { + if (inner_name_index != 0) + print(owner.pool.getName(inner_name_index) + " = "); + if (inner_class_info_index != 0) + print(owner.pool.ConstantStrValue(inner_class_info_index)); + if (outer_class_info_index != 0) + print(format(" of %s", owner.pool.ConstantStrValue(outer_class_info_index))); + println(owner.printCPIndex && !skipComments ? "" : ";"); + } else { + println(); + } + } + + @Override + public void tablePrint(int index, int size) throws IOException { + if (index == 0) { + printIndentLn("%s {".formatted(INNERCLASS.alias())); + } + incIndent(); + String prefix = EModifier.asKeywords(access, ClassFileContext.INNER_CLASS); + if (printCPIndex) { + prefix = getClassDefinitionString(prefix); + if (skipComments) { + printIndent(prefix); + } else { + printIndentPadRight(prefix, this.getCommentOffset()).print(" // "); + } + } else { + printIndent(prefix); + } + + if (!printCPIndex || (printCPIndex && !skipComments)) { + if (inner_name_index != 0) + print("%s = ".formatted(owner.pool.getName(inner_name_index))); + if (inner_class_info_index != 0) + print(owner.pool.ConstantStrValue(inner_class_info_index)); + if (outer_class_info_index != 0) + print(format(" of %s", owner.pool.ConstantStrValue(outer_class_info_index))); + println(owner.printCPIndex && !skipComments ? "" : ";"); + } else { + println(); + } + decIndent(); + if (index == size - 1) { + printIndentLn("}"); + } + } + + private String getClassDefinitionString(String line) { + if (inner_name_index != 0) + line = line.concat("#%d = ".formatted(inner_name_index)); + if (inner_class_info_index != 0) + line = line.concat("#%d".formatted(inner_class_info_index)); + if (outer_class_info_index != 0) { + line = line.concat(" of #%d".formatted(outer_class_info_index)); + } + return line.concat(";"); + } + + @Override + public int getPrintSize() { + String line = getClassDefinitionString(EModifier.asKeywords(access, ClassFileContext.INNER_CLASS)); + return line.length() + 1; + } + + @Override + public void setMaxPrintSize(int size) { + this.maxSize = size; + } + + @Override + public int getMaxPrintSize() { + return this.maxSize; + } +} // end InnerClassData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InstructionAttr.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InstructionAttr.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InstructionAttr.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/InstructionAttr.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,385 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.Pair; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static java.lang.Math.max; +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.FRAMETYPE; +import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode; + +/** + * instruction attributes + */ +class InstructionAttr extends MemberData { + short lineNum = 0; + boolean referred = false; // from some other instruction + ArrayList vars; + ArrayList types; + ArrayList endVars; + ArrayList endTypes; + ArrayList handlers; + ArrayList traps; + ArrayList endTraps; + List stackMapWrappers; + StackMapData stackMapEntry; + ClassData classData; + private int attributeOffset; + + public InstructionAttr(MethodData methodData) { + super(methodData); + this.classData = methodData.data; + } + + void addTrap(TrapData trap) { + if (traps == null) { + traps = new ArrayList<>(4); + } + traps.add(trap); + } + + void addEndTrap(TrapData endTrap) { + if (endTraps == null) { + endTraps = new ArrayList<>(4); + } + endTraps.add(endTrap); + } + + void add_handler(TrapData endHandler) { + if (handlers == null) { + handlers = new ArrayList<>(4); + } + handlers.add(endHandler); + } + + public void printBegins(int shift) { + this.attributeOffset = shift; + // Prints additional information for instruction: + // source line number; + printInlinedLineNumber(); + // begin of exception handler; + printBeginOfExceptionHandlers(shift); + // begin of trap scores; + printBeginOfTrapScores(shift); + // begin of locVar and locVarTypes + printBeginOfLocVars(shift); + } + + public void printEnds(int shift) { + // Prints additional information for instruction: + // end of local variables, local variable types and trap scopes; + if (endTypes != null && !tableFormat) { + print(enlargedIndent(PadRight(Opcode.opc_endtype.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + println(endTypes.stream().map(ev -> Short.toString(ev.slot)).collect(Collectors.joining(",")) + ";"); + } + if (endVars != null && !tableFormat) { + print(enlargedIndent(PadRight(Opcode.opc_endvar.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + println(endVars.stream().map(ev -> Short.toString(ev.slot)).collect(Collectors.joining(",")) + ";"); + } + if (endTraps != null) { + print(enlargedIndent(PadRight(Opcode.opc_endtry.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + println(endTraps.stream().map(TrapData::id).collect(Collectors.joining(",")) + ";"); + } + } + + /** + * @param shift how is shifted a list of verification types of locals_map/stack_map + * @return true if something is printed + */ + public boolean printStackMap_Table(int shift) { + // will the stackmap(table) be printed as table if the table is chosen? + if (tableFormat || (stackMapEntry == null && stackMapWrappers == null)) { + return false; + } else if (stackMapEntry != null) { + return stackMapEntry.belongsToStackMapTable() ? printStackMapTable(shift) : printStackMap(shift); + } else { + return stackMapWrappers.get(0).belongsToStackMapTable() ? printStackMapTable(shift) : printStackMap(shift); + } + } + + private boolean printStackMapTable(int shift) { + int mapShift = getCommentOffset() - STACKMAP_TYPE_PLACEHOLDER_LENGTH; + boolean wrapped = stackMapWrappers != null; + String opCodeName = Opcode.opc_stack_frame_type.parseKey(); + String prefix = ""; + String listPrefix = INDENT_STRING; + // print wrappers if found + if (wrapped) { + for (int i = 0; i < stackMapWrappers.size(); i++) { + StackMapData smd = stackMapWrappers.get(i); + if (i > 0) { + opCodeName = Opcode.opc_frame_type.parseKey(); + prefix = INDENT_STRING; + listPrefix = prefix + INDENT_STRING; + } + printPadRight(prefix + opCodeName, STACKMAP_TYPE_PLACEHOLDER_LENGTH); + if (printCPIndex && !skipComments) { + print(PadRight(smd.stackEntryType.tagName() + ";", mapShift)). + println(" // %s %s".formatted(FRAMETYPE.parseKey(), smd.stackEntryTypeValue)); + } else { + println(smd.stackEntryType.tagName() + ";"); + } + int[] unsetFields = smd.unsetFields; + printFields(unsetFields, shift); + if ((unsetFields == null) || (unsetFields.length == 0)) { + println(this.enlargedIndent(listPrefix + Opcode.opc_unset_fields.parseKey() + ";", shift)); + } + print(enlargedIndent(attributeOffset)); + } + } + opCodeName = Opcode.opc_stack_frame_type.parseKey(); + // print StackMap entry + if (stackMapEntry != null) { + if (wrapped) { + opCodeName = Opcode.opc_frame_type.parseKey(); + prefix += INDENT_STRING; +// println("{").print(enlargedIndent(attributeOffset)); + } + listPrefix = prefix + INDENT_STRING; + printPadRight(prefix + opCodeName, STACKMAP_TYPE_PLACEHOLDER_LENGTH); + if (printCPIndex && !skipComments) { + print(PadRight(stackMapEntry.stackEntryType.tagName() + ";", mapShift)). + println(" // %s %s".formatted(FRAMETYPE.parseKey(), stackMapEntry.stackEntryTypeValue)); + } else { + println(stackMapEntry.stackEntryType.tagName() + ";"); + } + + int[] lockMap = stackMapEntry.lockMap; + if ((lockMap == null) || (lockMap.length == 0)) { + if (stackMapEntry.stackEntryType.hasLocalMap()) { + println(this.enlargedIndent(listPrefix + Opcode.opc_locals_map.parseKey() + ";", shift)); + } + } else { + mapShift = printEntries(stackMapEntry.getMapListAsString(lockMap, ""), + listPrefix + Opcode.opc_locals_map.parseKey(), shift, mapShift); + } + + int[] stackMap = stackMapEntry.stackMap; + if ((stackMap == null) || (stackMap.length == 0)) { + if (stackMapEntry.stackEntryType.hasStackMap()) { + println(this.enlargedIndent(listPrefix + Opcode.opc_stack_map.parseKey() + ";", shift)); + } + } else { + printEntries(stackMapEntry.getMapListAsString(stackMap, ""), + listPrefix + Opcode.opc_stack_map.parseKey(), shift, mapShift); + } +// if (wrapped) { +// println(enlargedIndent(attributeOffset) + "}"); +// } + } + return stackMapWrappers != null || stackMapEntry != null; + } + + private boolean printStackMap(int shift) { + int mapShift = getCommentOffset() - STACKMAP_TYPE_PLACEHOLDER_LENGTH; + printPadRight(Opcode.opc_stack_map_frame.parseKey() + ";", STACKMAP_TYPE_PLACEHOLDER_LENGTH); + if (printCPIndex && !skipComments) { + print(PadRight(" ", mapShift)).println(" // offset " + stackMapEntry.frame_pc); + } else { + println(); + } + mapShift = printEntries(stackMapEntry.getMapListAsString(stackMapEntry.lockMap, ""), + Opcode.opc_locals_map.parseKey(), shift, mapShift); + printEntries(stackMapEntry.getMapListAsString(stackMapEntry.stackMap, ""), + Opcode.opc_stack_map.parseKey(), shift, mapShift); + return true; + } + + private void printFields(int[] unsetFields, int shift) { + int mapShift = getCommentOffset() - STACKMAP_TYPE_PLACEHOLDER_LENGTH; + if (unsetFields != null && (unsetFields.length > 0)) { + final int limit = unsetFields.length - 1; + Pair, List> line = stackMapEntry.getFieldListAsString(unsetFields); + String left = line.first.stream().collect(Collectors.joining(", ")).concat(";"); + String right = line.second.stream().collect(Collectors.joining(", ")).concat(";"); + String title = enlargedIndent(PadRight(INDENT_STRING + Opcode.opc_unset_fields.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift); + print(title); + // empties the title to use it as indent. + title = nCopies(title.length()); + if (printCPIndex) { + if (skipComments) { + println(left); + } else { + if (limit == 0) { + print(PadRight(left, mapShift)).println(" // " + right); + } else { + print(PadRight(line.first.get(0).concat(","), mapShift)).println(" // " + line.second.get(0).concat(",")); + for (int i = 1; i <= limit; i++) { + String delim = i == limit ? ";" : ","; + String id = line.first.get(i).concat(delim); + String field = line.second.get(i).concat(delim); + print(title).print(PadRight(id, mapShift)).println(" // " + field); + } + } + } + } else { + if (limit == 0) { + println(right); + } else { + println(line.second.get(0).concat(",")); + for (int i = 1; i <= limit; i++) { + String delim = i == limit ? ";" : ","; + String field = line.second.get(i).concat(delim); + print(title).println(field); + } + } + } + } + } + + + private int printEntries(Pair entriesLine, String title, int shift, int mapShift) { + if (entriesLine != null) { + boolean isEmpty = entriesLine.first.isEmpty() && entriesLine.second.isEmpty(); + print(this.enlargedIndent(PadRight(title + (isEmpty ? ";" : ""), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + if (printCPIndex) { + if (skipComments) { + println(entriesLine.first); + } else { + print(PadRight(entriesLine.first, mapShift)); + mapShift = max(mapShift, entriesLine.first.length()); + if( !isEmpty ) { + print(" // "); + } + } + } + if (!printCPIndex || (printCPIndex && !skipComments)) { + println(entriesLine.second); + } + } + return mapShift; + } + + void addVar(LocalVariableData var) { + if (vars == null) { + vars = new ArrayList<>(4); + } + vars.add(var); + } + + void addType(LocalVariableTypeData type) { + if (types == null) { + types = new ArrayList<>(4); + } + types.add(type); + } + + + void addEndType(LocalVariableTypeData endType) { + if (endTypes == null) { + endTypes = new ArrayList<>(4); + } + endTypes.add(endType); + } + + void addEndVar(LocalVariableData endVar) { + if (endVars == null) { + endVars = new ArrayList<>(4); + } + endVars.add(endVar); + } + + private void printInlinedLineNumber() { + boolean eitherOpt = data.printLineTableNumbers || data.printLineTableLines; + boolean bothOpt = data.printLineTableNumbers && data.printLineTableLines; + if (eitherOpt && (lineNum != 0)) { + decIndent(); + if (bothOpt) { + String srcLine = classData.getSrcLine(lineNum); + printIndentLn("// " + lineNum + (srcLine != null ? "# " + srcLine : "")); + } else if (data.printLineTableNumbers) { + printIndentLn("// %d#", lineNum); + } else if (data.printLineTableLines) { + String srcLine = classData.getSrcLine(lineNum); + printIndentLn(srcLine != null ? "// " + srcLine : ""); + } + incIndent(); + } + } + + private void printBeginOfExceptionHandlers(int shift) { + if (handlers != null) { + for (TrapData line : handlers) { + print(this.enlargedIndent(PadRight(Opcode.opc_catch.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + if (printCPIndex) { + if (skipComments) { + println("%s #%d;", line.id(), line.catch_cpx); + } else { + print(PadRight(format("%s #%d;", line.id(), line.catch_cpx), + getCommentOffset() - STACKMAP_TYPE_PLACEHOLDER_LENGTH)); + println(" // " + (line.catch_cpx == 0 ? "any" : data.pool.getClassName(line.catch_cpx))); + } + } else { + println("%s %s;", line.id(), data.pool.getClassName(line.catch_cpx)); + } + } + } + } + + private void printBeginOfTrapScores(int shift) { + if (traps != null) { + print(this.enlargedIndent(PadRight(Opcode.opc_try.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + println(traps.stream().map(TrapData::id).collect(Collectors.joining(", ")) + ";"); + } + } + + private void printBeginOfLocVars(int shift) { + if ((vars != null) && !tableFormat) { + for (LocalVariableData line : vars) { + print(this.enlargedIndent(PadRight(Opcode.opc_var.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + if (printCPIndex) { + if (skipComments) { + println("%d #%d:#%d;", line.slot, line.name_cpx, line.sig_cpx); + } else { + print(PadRight(format("%d #%d:#%d;", line.slot, line.name_cpx, line.sig_cpx), + getCommentOffset() - STACKMAP_TYPE_PLACEHOLDER_LENGTH)); + println(" // %s:%s", data.pool.getName(line.name_cpx), data.pool.getName(line.sig_cpx)); + } + } else { + println("%d %s:%s;", line.slot, data.pool.getName(line.name_cpx), data.pool.getName(line.sig_cpx)); + } + } + } + if (types != null && !tableFormat) { + for (LocalVariableTypeData type : types) { + print(this.enlargedIndent(PadRight(Opcode.opc_type.parseKey(), STACKMAP_TYPE_PLACEHOLDER_LENGTH), shift)); + if (printCPIndex) { + if (skipComments) { + println("%d #%d:#%d;", type.slot, type.name_cpx, type.sig_cpx); + } else { + print(PadRight(format("%d #%d:#%d;", type.slot, type.name_cpx, type.sig_cpx), + getCommentOffset() - STACKMAP_TYPE_PLACEHOLDER_LENGTH)); + println(" // %s:%s", data.pool.getName(type.name_cpx), data.pool.getName(type.sig_cpx)); + } + } else { + println("%d %s:%s;", type.slot, data.pool.getName(type.name_cpx), data.pool.getName(type.sig_cpx)); + } + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisEnvironment.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisEnvironment.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisEnvironment.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisEnvironment.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.DecompilerLogger; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; + +public class JdisEnvironment extends Environment { + + /** + * @param builder the jdis environment builder + */ + private JdisEnvironment(Builder builder) { + super(builder); + } + + @Override + public void printErrorLn(String format, Object... args) { + getLogger().printErrorLn(format, args); + } + + @Override + public void warning(String format, Object... args) { + getLogger().warning(format, args); + } + + static class JdisBuilder extends Environment.Builder { + + public JdisBuilder(ToolOutput toolOutput, DualStreamToolOutput outerLog) { + super(toolOutput, new DecompilerLogger("jdis", JdisEnvironment.class, outerLog)); + } + + @Override + public JdisEnvironment build() { + return new JdisEnvironment(this); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisTool.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisTool.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisTool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/JdisTool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.Decoder; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; +import org.openjdk.asmtools.jdis.JdisEnvironment.JdisBuilder; + +public abstract class JdisTool extends Decoder { + + protected JdisTool(ToolOutput toolOutput, DualStreamToolOutput outerLog) { + super(toolOutput, outerLog); + } + + protected JdisTool(ToolOutput toolOutput) { + super(toolOutput, new StderrLog()); + } + + @Override + public JdisEnvironment getEnvironment(ToolOutput toolOutput, DualStreamToolOutput outerLog) { + JdisBuilder builder = new JdisBuilder(toolOutput, outerLog); + return builder.build(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LineNumberData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LineNumberData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LineNumberData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LineNumberData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,87 @@ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; + +import static org.openjdk.asmtools.jasm.JasmTokens.Token.LINETABLE_HEADER; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.LINE_NUMBERS; + +/** + * Represents a single line number data entry within a Line Number Table attribute. + * This class extends the Indenter class to provide indentation functionality. + */ +public class LineNumberData extends Indenter { + /** + * The starting program counter of this line number entry. + */ + protected short start_pc; + + /** + * The line number corresponding to the start_pc. + */ + protected short line_number; + + /** + * A format string used for printing the line number data. + */ + protected String format; + + /** + * Checks if this LineNumberData instance should be printed. + * + * @return true if either printLineTable or tableFormat is enabled, false otherwise. + */ + @Override + public boolean isPrintable() { + return printLineTable; + } + + /** + * Prints this LineNumberData instance in JASM format. + * + * @param index the index of this entry in the Line Number Table + * @param size the total number of entries in the Line Number Table + * @throws IOException if an I/O error occurs during printing + */ + @Override + protected void jasmPrint(int index, int size) throws IOException { + incIndent(); + if (index == 0) { + printIndentLn(getTitle()); + } + printIndentLn(format.formatted("line", line_number, start_pc)); + } + + @Override + protected String getTitle() { + return LINETABLE_HEADER.parseKey() + ":"; + } + + /** + * Prints this LineNumberData instance in Table(javap) format. + * + * @param index the index of this entry in the Line Number Table + * @param size the total number of entries in the Line Number Table + * @throws IOException if an I/O error occurs during printing + */ + @Override + protected void tablePrint(int index, int size) throws IOException { + //There are no differences between the simple (jasm) and extended (table) presentations of LineNumberTable info. + this.jasmPrint(index, size); + } + + /** + * Constructs a new LineNumberData instance from the given DataInputStream and MethodData. + * + * @param in the DataInputStream containing the line number data + * @param methodData the MethodData instance associated with this LineNumberData + * @throws IOException if an I/O error occurs during construction + */ + public LineNumberData(DataInputStream in, MethodData methodData) throws IOException { + start_pc = in.readShort(); + line_number = in.readShort(); + super.toolOutput = methodData.toolOutput; + int n = methodData.printProgramCounter ? PROGRAM_COUNTER_PLACEHOLDER_LENGTH + 4 : INSTR_PREFIX_LENGTH + 2; + format = "%" + n + "s %4d: %7d"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LoadableDescriptorsData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LoadableDescriptorsData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LoadableDescriptorsData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LoadableDescriptorsData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Valhalla: + *

+ * LoadableDescriptors_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_descriptors; + * u2 descriptors[number_of_descriptors]; + * } + */ +public class LoadableDescriptorsData extends Utf8ArrayData { + public LoadableDescriptorsData(ClassData cls) { + super(cls, JasmTokens.Token.LOADABLEDESCRIPTORS); + } + + public LoadableDescriptorsData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + return (LoadableDescriptorsData) super.read(in, attribute_length); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; +import java.text.MessageFormat; + +/** + * LocalTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 local_table_length; + * { u2 start_pc; + * u2 length; + * u2 name_index; + * u2 descriptor/signature_index; + * u2 index; + * } local_table[local__table_length]; + * } + */ +public abstract class LocalData> extends Indenter { + protected short start_pc, length, name_cpx, sig_cpx, slot; + protected ConstantPool pool; + protected String header; + protected String format; + + public LocalData(MemberData owner, DataInputStream in, MethodData methodData, String fieldFacet) throws IOException { + start_pc = in.readShort(); + length = in.readShort(); + name_cpx = in.readShort(); + sig_cpx = in.readShort(); + slot = in.readShort(); + super.toolOutput = methodData.toolOutput; + pool = methodData.getConstantPool(); + int shift = methodData.calculateInlinedTitleShift("Start"); + header = (MessageFormat.format("%{0}s Length Slot Name %s", shift)). + formatted("Start", fieldFacet); + format = MessageFormat.format("%{0}d %6d %4d %4s %s", shift); + } + + @Override + public int getCommentOffset() { + return super.getCommentOffset() + PROGRAM_COUNTER_PLACEHOLDER_LENGTH; + } + + @Override + protected void tablePrint(int index, int size) throws IOException { + incIndent(); + if (index == 0) { + printIndentLn(getTitle()); + printIndentLn(header); + } + String nameCpx = PadRight("#%s".formatted(name_cpx), 6); + String name = pool.StringValue(name_cpx); + String type = pool.StringValue(sig_cpx); + if (printCPIndex) { + if (skipComments) { + printIndentLn(format.formatted(start_pc, length, slot, nameCpx, "#%s".formatted(sig_cpx))); + } else { + String str = format.formatted(start_pc, length, slot, nameCpx, "%-4s".formatted("#" + sig_cpx)); + printIndent(PadRight(str, getCommentOffset())); + println(" // %s:%s".formatted(name, type)); + } + } else { + printIndentLn(format.formatted(start_pc, length, slot, PadRight(name, 6), type)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.TableFormatModel; + +import java.io.DataInputStream; +import java.io.IOException; + +import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; + +/** + * LocalVariableTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 local_variable_table_length; + * { u2 start_pc; + * u2 length; + * u2 name_index; + * u2 descriptor_index; + * u2 index; + * } local_variable_table[local_variable_table_length]; + * } + */ +public class LocalVariableData> extends LocalData { + + @Override + public boolean isPrintable() { + return printLocalVariables && tableFormat; + } + + public LocalVariableData(M owner, DataInputStream in, MethodData methodData) throws IOException { + super(owner, in, methodData, DESCRIPTOR.parseKey()); + } + + @Override + protected String getTitle() { + return LOCALVARIABLES_HEADER.parseKey() + ":"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableTypeData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableTypeData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableTypeData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/LocalVariableTypeData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; + +import static org.openjdk.asmtools.jasm.JasmTokens.Token.LOCALVARIABLETYPES_HEADER; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.SIGNATURE; + +/** + * LocalVariableTypeTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 local_variable_type_table_length; + * { u2 start_pc; + * u2 length; + * u2 name_index; + * u2 signature_index; + * u2 index; + * } local_variable_type_table[local_variable_type_table_length]; + * } + */ +public class LocalVariableTypeData> extends LocalData { + + public boolean isPrintable() { + return printLocalVariableTypes && tableFormat; + } + + public LocalVariableTypeData(M owner, DataInputStream in, MethodData methodData) throws IOException { + super(owner, in, methodData, SIGNATURE.parseKey()); + } + + @Override + protected String getTitle() { + return LOCALVARIABLETYPES_HEADER.parseKey() + ":"; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Main.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Main.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Main.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Main.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,314 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.inputs.FileInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.StdoutOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.DualOutputStreamOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; + +import java.io.DataInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static org.openjdk.asmtools.Main.WRITE_SWITCH; +import static org.openjdk.asmtools.common.Environment.FAILED; +import static org.openjdk.asmtools.common.Environment.OK; +import static org.openjdk.asmtools.common.outputs.FSOutput.FSDestination.DIR; +import static org.openjdk.asmtools.common.outputs.FSOutput.FSDestination.FILE; +import static org.openjdk.asmtools.jdis.Options.PrintOption; +import static org.openjdk.asmtools.jdis.Options.PrintOption.*; +import static org.openjdk.asmtools.util.ProductInfo.FULL_VERSION; + +/** + * jdis is a disassembler that accepts a .class file, and prints the plain-text translation of jasm source file + * to the standard output. + *

+ * Main program of the Java Disassembler :: class to jasm + */ +public class Main extends JdisTool { + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput... toolInputs) { + super(toolOutput, log); + Collections.addAll(fileList, toolInputs); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput) { + super(toolOutput, log); + fileList.add(toolInput); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput toolInput, String... argv) { + super(toolOutput, log); + if (toolInput != null) { + fileList.add(toolInput); + } + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, String... argv) { + super(toolOutput); + parseArgs(argv); + } + + public Main(ToolOutput toolOutput, DualStreamToolOutput logger, String... argv) { + super(toolOutput, logger); + parseArgs(argv); + } + + // jdis entry point + public static void main(String... argv) { + Main disassembler = new Main(new StdoutOutput(), argv); + System.exit(disassembler.disasm()); + } + + // Runs disassembler with args + public synchronized boolean disasm(String... argv) { + parseArgs(argv); + return this.disasm() == OK; + } + + @Override + public synchronized int decode() { + return this.disasm(); + } + + public synchronized boolean decode(String... argv) { + return this.disasm(argv); + } + + // Runs disassembler when args already parsed + public synchronized int disasm() { + int rc = OK; + for (ToolInput toolInput : fileList) { + ClassData classData = null; + try { + environment.setToolInput(toolInput); + classData = new ClassData(environment); + toolInput.setDetailedInput(classData.isDetailedOutput()); + try (DataInputStream dis = toolInput.getDataInputStream(Optional.of(environment))) { + classData.read(dis, Paths.get(toolInput.getName())); + } + environment.traceln(() -> "Options:\n%s\n".formatted(Options.getPrintOptions())); + environment.getToolOutput().startClass(classData.className, Optional.of(".jasm"), environment); + classData.print(); + environment.getToolOutput().finishClass(classData.className); + environment.getOutputs().flush(); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + environment.getLogger().flush(); + continue; + } catch (FileNotFoundException fnf) { + environment.printException(fnf); + environment.error("err.not_found", toolInput); + rc = FAILED; + } catch (IOException | ClassFormatError ioe) { + classData.postPrint(); + environment.error(ioe); + environment.printException(ioe); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + } catch (Error error) { + classData.postPrint(); + environment.error(error); + environment.printException(error); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + } catch (Exception ex) { + classData.postPrint(); + environment.error(ex); + environment.printException(ex); + rc += environment.getLogger().registerTotalIssues(rc, toolInput); + } + environment.getLogger().flush(); + break; + } + return rc; + } + + @Override + public void usage() { + environment.usage(List.of( + "info.usage", + "info.opt.d", + "info.opt.w", + "info.opt.g", + "info.opt.gg", + "info.opt.nc", + "info.opt.table", + "info.opt.hx", + "info.opt.instr.offset", + "info.opt.sysinfo", + "info.opt.lnt", + "info.opt.lvt", + "info.opt.drop", + "info.opt.b", + "info.opt.version", + "info.opt.t", + "info.opt.v" + )); + } + + @Override + protected void parseArgs(String... argv) { + Options.setDefaultOutputOptions(); + // Parse arguments + for (int i = 0; i < argv.length; i++) { + String arg = argv[i]; + switch (arg) { + case "-g": + Options.setDetailedOutputOptions(); + break; + case "-v": + Options.set(VERBOSE); + environment.setVerboseFlag(true); + break; + case "-sysinfo": + Options.set(SYSINFO); + break; + case "-t": + Options.set(VERBOSE); + Options.set(TRACE); + environment.setVerboseFlag(true); + environment.setTraceFlag(true); + break; + case "-pc": + Options.set(PRINT_BCI); + break; + case "-nc": + Options.set(NO_COMMENTS); + break; + case "-hx": + Options.set(HEX); + break; + case "-f": // -f + setFSDestination(FILE, ++i, argv); + break; + case org.openjdk.asmtools.Main.DIR_SWITCH: // -d + setFSDestination(DIR, ++i, argv); + break; + case WRITE_SWITCH: // -w + environment.setIgnorePackage(true); + setFSDestination(DIR, ++i, argv); + break; + case org.openjdk.asmtools.Main.DUAL_LOG_SWITCH: // -dls + this.environment.setOutputs(new DualOutputStreamOutput()); + break; + case org.openjdk.asmtools.Main.VERSION_SWITCH: // -version + environment.println(FULL_VERSION); + System.exit(OK); + case org.openjdk.asmtools.Main.STDIN_SWITCH: // - + addStdIn(); + break; + case "-h", "-help": + usage(); + System.exit(OK); + case "-best-effort": + Options.set(BEST_EFFORT); + break; + case "-gg": + Options.setDetailedOutputOptions(); + Options.set(EXTRA_DETAILED_Output); + break; + case "-table": + Options.set(PrintOption.TABLE); + break; + default: + if (arg.startsWith("-")) { + if (arg.startsWith("-drop")) { + if (!parseParameters("-drop", arg, "DROP", DROP_All)) { + usage(); + System.exit(FAILED); + } + } else if (arg.startsWith("-lnt")) { + if (!parseParameters("-lnt", arg, "LINE_NUMBER_TABLE", LINE_NUMBER_TABLE_All)) { + usage(); + System.exit(FAILED); + } + } else if (arg.startsWith("-lvt")) { + if (!parseParameters("-lvt", arg, "LOCAL_VARIABLE", LOCAL_VARIABLE_All)) { + usage(); + System.exit(FAILED); + } + } else { + environment.error("err.invalid_option", arg); + usage(); + System.exit(FAILED); + } + } else { + fileList.add(new FileInput(arg)); + } + } + } + if (fileList.isEmpty()) { + usage(); + System.exit(FAILED); + } + } + + /** + * Parse parameters group -option:parameters [parameters=option1,option2] + * + * @param option one of the options [-lvt, -drop, -lnt] + * @param parameters one of combinations corresponded to the option: + * , or + * + * @param optPrefix prefix of the PR: LINE_NUMBER_TABLE, LOCAL_VARIABLE or DROP + * @param blankOption option that is used if there are no parameters option1,option2... attached to the -option + * @return true if parameters group parsed successfully + */ + private boolean parseParameters(String option, String parameters, String optPrefix, PrintOption blankOption) { + parameters = parameters.substring(option.length()); + if (parameters.isBlank()) { + if (!blankOption.isActive()) { + environment.error("err.option.unsupported", option + ":all"); + return false; + } + blankOption.apply(); + } else if (parameters.matches("^[:=-]+.*")) { + parameters = parameters.substring(1); + String[] prmArray = parameters.split(","); + for (int i = 0; i < prmArray.length; i++) { + PrintOption printOption = getStringFlag(optPrefix, prmArray[i]); + if (printOption == null || !printOption.name().startsWith(optPrefix)) { + environment.error("err.invalid_parameter_of_option", prmArray[i], option); + return false; + } else if (!printOption.isActive()) { + environment.error("err.option.unsupported", "%s:%s".formatted(option, prmArray[i])); + return false; + } + printOption.apply(); + if (printOption.equals(blankOption)) { // blank options is equal to + return true; + } + } + } else { + environment.error("err.option.unsupported", option + parameters); + return false; + } + return true; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Measurable.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Measurable.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Measurable.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Measurable.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +/** + * Indicates that the element has a specific printable measurement/size. + */ +public interface Measurable { + int getPrintSize(); + + void setMaxPrintSize(int size); + + int getMaxPrintSize(); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MemberData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MemberData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MemberData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MemberData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static java.lang.String.format; + +/** + * Base class for ClassData, MethodData, FieldData and RecordData(JEP 360) + */ +public abstract class MemberData extends Indenter { + + // String prefix to print Defaults for Annotation Interface Elements + protected static final String DEFAULT_VALUE_PREFIX = "default { "; + + protected T data; + protected Environment environment; // Environment of this data + protected ConstantPool pool; + protected String memberType = ""; + private String contextDefaultValuePrefix = null; + + public MemberData setOwner(MemberData> owner) { + this.owner = owner; + return this; + } + + MemberData> owner; + + // access flags (modifiers) + protected int access; + + // extra flags + protected boolean isSynthetic = false; + protected boolean isDeprecated = false; + + // indicates the state of the annotation element + public enum AnnotationElementState { + HAS_DEFAULT_VALUE, // An annotation interface element has a default value + DEFAULT_STATE, + PARAMETER_ANNOTATION, + RIGHT_OPERAND, + INLINED_ELEMENT // An annotation element is element of an annotation element. + } + + private AnnotationElementState annotationElementState = AnnotationElementState.DEFAULT_STATE; + + // Signature can be located in ClassFile, field_info, method_info, and component_info + protected SignatureData signature; + + // The visible annotations for this class, member( field or method) or record component + protected ArrayList visibleAnnotations; + + // The invisible annotations for this class, member( field or method) or record component + protected ArrayList invisibleAnnotations; + + // The visible annotations for this class, member( field or method) or record component + protected ArrayList visibleTypeAnnotations; + + // The invisible annotations for this class, member( field or method) or record component + protected ArrayList invisibleTypeAnnotations; + + // The remaining attributes of this class, member( field or method) or record component + protected ArrayList attributes; + + public MemberData(T data) { + super(data.toolOutput); + this.environment = data.environment; + init(data); + } + + public MemberData(Environment environment) { + super(environment.getToolOutput()); + this.environment = environment; + } + + public void init(T data) { + this.data = data; + this.pool = data.pool; + } + + /** + * Prints system comments if the option -sysinfo is used. + */ + protected void printSysInfo() { + if (sysInfo) { + throw new RuntimeException("Not implemented yet"); + } + } + + public MemberData setSignature(SignatureData signatureData) { + this.signature = signatureData; + return this; + } + + public ConstantPool getConstantPool() { + return pool; + } + + protected boolean handleAttributes(DataInputStream in, + EAttribute attributeTag, + int attributeLength) throws IOException { + // sub-classes override + return false; + } + + protected boolean handleUnrecognizedAttributes(DataInputStream in, + int attributeNameCpx, + int attributeLength) throws IOException { + // sub-classes override + return false; + } + + protected String getPseudoFlagsAsString() { + String s = ""; + if (isSynthetic) + s += "%s ".formatted(JasmTokens.Token.SYNTHETIC.parseKey()); + if (isDeprecated) + s += "%s ".formatted(JasmTokens.Token.DEPRECATED.parseKey()); + return s; + } + + /** + * Gets a state of the annotation element + */ + public AnnotationElementState getAnnotationElementState() { + return annotationElementState; + } + + /** + * Sets the state of the annotation element + */ + public MemberData setElementState(AnnotationElementState state) { + annotationElementState = state; + return this; + } + + protected int getAnnotationsCount() { + return ((visibleAnnotations == null) ? 0 : visibleAnnotations.size()) + + ((invisibleAnnotations == null) ? 0 : invisibleAnnotations.size()) + + ((visibleTypeAnnotations == null) ? 0 : visibleTypeAnnotations.size()) + + ((invisibleTypeAnnotations == null) ? 0 : invisibleTypeAnnotations.size()); + } + + /** + * Print member's (ClassData, MethodData, FieldData and RecordData) annotations + * + * @throws IOException signals that an exception to some sort has occurred + */ + + protected void printAnnotations(List... annotationLists) throws IOException { + for (List list : annotationLists) { + if (list != null) { + for (T annotation : list) { + annotation.setTheSame(this).print(); + println(); + } + } + } + } + + protected void printAttributes(Container... tables) throws IOException { + for (Container table : tables) { + if (table != null && table.isPrintable()) { + table.setCommentOffset(this.getCommentOffset()).print(); + } + } + } + + /** + * Prints field or a record component + * + * @param prefix the field prefix: "private static final Field" or the component prefix: "synthetic Component" + * @param postfix String presentation of the end of line (either ":" or ";") + * @param name_cpx Field/Component name cpIndex + * @param type_cpx Field/Component type cpIndex + * @param value_cpx either cpIndex of an initial field's value or 0 + * if it's a component or the field doesn't have an initial value. + */ + protected void printVar(StringBuilder prefix, String postfix, String eol, int name_cpx, int type_cpx, int value_cpx) { + + Pair signInfo = (this.signature != null) ? + this.signature.getJasmPrintInfo((i) -> pool.inRange(i)) : + new Pair<>("", ""); + + if (printCPIndex) { + prefix.append('#').append(name_cpx).append(":#").append(type_cpx).append(signInfo.first); + if (value_cpx != UNDEFINED ) { + prefix.append(" = #").append(value_cpx); + } + prefix.append(eol); + if (skipComments) { + print(prefix.toString()); + } else { + printPadRight(prefix.toString(), getCommentOffset()).print(" // "); + print("%s:%s%s%s".formatted( + data.pool.getName(name_cpx), + data.pool.getName(type_cpx), + signInfo.second, + postfix != null ? postfix : "")); + } + } else { + prefix.append(data.pool.getName(name_cpx)).append(':'). + append(data.pool.getName(type_cpx)). + append(signInfo.second); + if (postfix != null) { + prefix.append(postfix); + } + print("%s%s".formatted(prefix, eol)); + } + println(); + } + + protected void readAttributes(DataInputStream in) throws IOException { + // Read the Attributes + int attributesCount = in.readUnsignedShort(); + attributes = new ArrayList<>(attributesCount); + environment.traceln(format("%s - Attributes[%d]", memberType, attributesCount)); + AttrData attrData; + for (int k = 0; k < attributesCount; k++) { + int name_cpx = in.readUnsignedShort(); + String attr_name = data.pool.getString(name_cpx, index -> "#" + index); + environment.traceln(format("Attribute#%d name[%d]=\"%s\"", k, name_cpx, attr_name)); + EAttribute tag = EAttribute.get(attr_name); + int attrLength = in.readInt(); + attrData = new AttrData(environment, tag); + attributes.add(attrData); + switch (tag) { + case ATT_Synthetic: + // Read Synthetic Attribute + if (attrLength != 0) { + if (bestEffort) { + environment.getLogger().error( + "err.invalid.attribute.length", tag.printValue(), attrLength); + } else { + throw new FormatError(environment.getLogger(), + "err.invalid.attribute.length", tag.printValue(), attrLength); + } + } + isSynthetic = true; + break; + case ATT_Deprecated: + // Read Deprecated Attribute + if (attrLength != 0) { + if (bestEffort) { + environment.getLogger().error( + "err.invalid.attribute.length", tag.printValue(), attrLength); + } else { + throw new FormatError(environment.getLogger(), + "err.invalid.attribute.length", tag.printValue(), attrLength); + } + } + isDeprecated = true; + break; + case ATT_RuntimeVisibleAnnotations: + case ATT_RuntimeInvisibleAnnotations: + // Read Annotations Attribute + int count = in.readShort(); + ArrayList annotations = new ArrayList<>(count); + boolean invisible = (tag == EAttribute.ATT_RuntimeInvisibleAnnotations); + for (int i = 0; i < count; i++) { + AnnotationData annotationData = new AnnotationData(data, invisible); + annotationData.read(in); + annotations.add(annotationData); + } + if (invisible) { + invisibleAnnotations = annotations; + } else { + visibleAnnotations = annotations; + } + break; + case ATT_RuntimeVisibleTypeAnnotations: + case ATT_RuntimeInvisibleTypeAnnotations: + // Read Type Annotations Attribute + count = in.readShort(); + ArrayList typeAnnotations = new ArrayList<>(count); + invisible = (tag == EAttribute.ATT_RuntimeInvisibleTypeAnnotations); + for (int i = 0; i < count; i++) { + TypeAnnotationData typeAnnotationData = new TypeAnnotationData(data, invisible); + typeAnnotationData.read(in); + typeAnnotations.add(typeAnnotationData); + } + if (invisible) { + invisibleTypeAnnotations = typeAnnotations; + } else { + visibleTypeAnnotations = typeAnnotations; + } + break; + case ATT_Unrecognized: + handleUnrecognizedAttributes(in,name_cpx, attrLength); + attrData.read(name_cpx, attrLength, in); + break; + default: + boolean handled = handleAttributes(in, tag, attrLength); + if (!handled) { + attrData.read(name_cpx, attrLength, in); + } else { + attrData.setNameCpx(name_cpx).setLength(attrLength); + } + break; + } + } + } + + public List getListOf(EAttribute attributeTag) { + return attributes.stream().filter(a -> a.getAttributeInfo().equals(attributeTag)).toList(); + } + + /** + * | 012: aad + * |iiSSSSSHeader.... + * ii - indent SSSS - shift that is returned. + */ + public int calculateInlinedTitleShift(String Header) { + return ( + (printProgramCounter) + ? PROGRAM_COUNTER_PLACEHOLDER_LENGTH + getIndentStep() * 2 + Header.length() - getIndentSize() + : INSTR_PREFIX_LENGTH + getIndentStep() * 2 + Header.length() - getIndentSize() * 2 + ) - getIndentSize(); + } + + protected String getDefaultValuePrefix() { + if( contextDefaultValuePrefix == null ) { + contextDefaultValuePrefix = printCPIndex ? DEFAULT_VALUE_PREFIX : " " + DEFAULT_VALUE_PREFIX; + } + return contextDefaultValuePrefix; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MethodData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MethodData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MethodData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/MethodData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,446 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.structure.ClassFileContext; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.EModifier; +import org.openjdk.asmtools.jdis.notations.Signature; +import org.openjdk.asmtools.jdis.notations.Type; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static java.lang.Math.max; +import static org.openjdk.asmtools.common.structure.ClassFileContext.METHOD; +import static org.openjdk.asmtools.jasm.JasmTokens.Token; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.METHOD_DATA; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.SIGNATURE; +import static org.openjdk.asmtools.jdis.ConstantPool.funcInvalidCPIndex; +import static org.openjdk.asmtools.jdis.MemberData.AnnotationElementState.HAS_DEFAULT_VALUE; +import static org.openjdk.asmtools.jdis.MemberData.AnnotationElementState.PARAMETER_ANNOTATION; + +/** + * Method data for method members in a class of the Java Disassembler + */ +public class MethodData extends MemberData { + + //ConstantPool index to the method name + protected int name_cpx; + + //ConstantPool index to the method descriptor, representing the types of parameters that the method takes, + // and a return descriptor, representing the type of the value (if any) that the method returns. + protected int descriptor_cpx; + + //The parameter names for this method + protected ArrayList methodParameters; + + //The visible parameter annotations for this method + protected ParameterAnnotationData visibleParameterAnnotations; + + //The invisible parameter annotations for this method + protected ParameterAnnotationData invisibleParameterAnnotations; + + // The invisible parameter annotations for this method + protected AnnotationElement.AnnotationValue defaultAnnotation; + + // The exception table (thrown exceptions) for this method. Maybe null + protected ExceptionData exceptions; + + // The code data for this method. Maybe null + private CodeData code; + + public MethodData(ClassData classData) { + super(classData); + tableToken = METHOD_DATA; + super.memberType = "MethodData"; + setCommentOffset(classData.pool.getCommentOffset()); + methodParameters = null; + } + + /* Read Methods */ + @Override + protected boolean handleAttributes(DataInputStream in, EAttribute attributeTag, int attributeLength) throws IOException { + // Read the Attributes + boolean handled = true; + switch (attributeTag) { + case ATT_Code -> { + code = new CodeData(this); + code.read(in, attributeLength); + } + case ATT_Signature -> { + if (this.signature != null) { + environment.warning("warn.one.attribute.required", "Signature", "method_info"); + } + setSignature(new SignatureData(data).read(in, attributeLength)); + } + case ATT_Exceptions -> exceptions = new ExceptionData(data).read(in, attributeLength); + case ATT_MethodParameters -> readMethodParameters(in); + case ATT_RuntimeVisibleParameterAnnotations, ATT_RuntimeInvisibleParameterAnnotations -> { + boolean invisible = (attributeTag == EAttribute.ATT_RuntimeInvisibleParameterAnnotations); + ParameterAnnotationData parameterAnnotationData = new ParameterAnnotationData(this, invisible); + parameterAnnotationData.read(in); + if (invisible) { + invisibleParameterAnnotations = parameterAnnotationData; + } else { + visibleParameterAnnotations = parameterAnnotationData; + } + } + case ATT_AnnotationDefault -> defaultAnnotation = AnnotationElement.readValue(in, data, false); + default -> handled = false; + } + return handled; + } + + /** + * Read and resolve the method data called from ClassData. + * Precondition: Meth has already been read from the stream. + */ + public void read(DataInputStream in) throws IOException { + // read the Methods CP indexes + access = in.readUnsignedShort(); // & MM_METHOD; // Q + name_cpx = in.readUnsignedShort(); + descriptor_cpx = in.readUnsignedShort(); + environment.traceln(() -> "MethodData: {modifiers[%d]}:%s name[%d]=%s signature[%d]=%s" + .formatted(access, + EModifier.asNames(access, ClassFileContext.METHOD).isEmpty() ? "" : + EModifier.asNames(access, ClassFileContext.METHOD).isEmpty(), + name_cpx, data.pool.getString(name_cpx, index -> "???"), + descriptor_cpx, data.pool.getString(descriptor_cpx, index -> "???"))); + // Read the attributes + readAttributes(in); + } + + private void readMethodParameters(DataInputStream in) throws IOException { + // this is not really a CodeAttr attribute, it's part of the CodeAttr + int num_params = in.readUnsignedByte(); + environment.traceln(() -> "MethodParametersAttr[%d]".formatted(num_params)); + methodParameters = new ArrayList<>(num_params); + for (int i = 0; i < num_params; i++) { + short paramNameCpx = (short) in.readUnsignedShort(); + int paramAccess = in.readUnsignedShort(); + environment.traceln("()->MethodParameter[%d] = { name[%d]: \"%s\" modifiers[%d]: %s}". + formatted(i, paramNameCpx, + pool.getString(paramNameCpx, index -> "???"), + paramAccess, EModifier.asNames(paramAccess, ClassFileContext.METHOD))); + methodParameters.add(i, new MethodParameterData(paramNameCpx, paramAccess)); + } + } + + private record ParameterAnnotationsSizes(int visibleParameterAnnotationsCount, + int invisibleParameterAnnotationsCount) { + boolean hasParameterAnnotations() { + return visibleParameterAnnotationsCount > 0 || invisibleParameterAnnotationsCount > 0; + } + } + + private ParameterAnnotationsSizes parameterAnnotationsSizes = null; + + private ParameterAnnotationsSizes ParameterAnnotationsSizes() { + if (parameterAnnotationsSizes == null) { + parameterAnnotationsSizes = new ParameterAnnotationsSizes( + visibleParameterAnnotations != null ? visibleParameterAnnotations.numParameters() : 0, + invisibleParameterAnnotations != null ? invisibleParameterAnnotations.numParameters() : 0); + } + return parameterAnnotationsSizes; + } + + private boolean hasAnnotationParameters() { + return ParameterAnnotationsSizes().hasParameterAnnotations() || + methodParameters != null && methodParameters.size() > 0; + } + + private boolean hasDefaultAnnotation() { + return defaultAnnotation != null; + } + + /** + * Print The MethodParameters Attribute and the parameter annotations for this method. + * Called from CodeAttr (since JASM code integrates the ParameterAnnotation Syntax inside the method body). + */ + public void printMethodParameters() throws IOException { + // ParameterAnnotation(s) or MethodParameters found. + if (hasAnnotationParameters()) { + incIndent(); + int totalWidth = printProgramCounter ? 7 : 5; + int pNumSize = methodParameters != null ? methodParameters.size() : 0; + int maxParams = max(pNumSize, parameterAnnotationsSizes.invisibleParameterAnnotationsCount()); + maxParams = max(parameterAnnotationsSizes.visibleParameterAnnotationsCount(), maxParams); + + String[] paramNames = getPrintableParameterNames(maxParams); + + for (int paramNum = 0; paramNum < maxParams; paramNum++) { + ArrayList visAnnotationDataList = + (visibleParameterAnnotations != null && paramNum < parameterAnnotationsSizes.visibleParameterAnnotationsCount()) ? + visibleParameterAnnotations.get(paramNum) : null; + + ArrayList invisAnnotationDataList = + (invisibleParameterAnnotations != null && paramNum < parameterAnnotationsSizes.invisibleParameterAnnotationsCount()) ? + invisibleParameterAnnotations.get(paramNum) : null; + + MethodParameterData methodParameterData = (methodParameters != null) ? methodParameters.get(paramNum) : null; + boolean hasAnnotations = ((visAnnotationDataList != null) || (invisAnnotationDataList != null)); + + if ((methodParameterData != null) || hasAnnotations) { + // Print the Param number (header) + int annotOffset = 3; + printIndent(PadRight("%2d: ".formatted(paramNum), totalWidth)); + + // Print the Parameter name + if (methodParameterData != null) { + printPadRight(paramNames[paramNum], annotOffset); + } + + // Print any visible param annotations + printAnnotationDataList(visAnnotationDataList, annotOffset); + + // Print any invisible param annotations + printAnnotationDataList(invisAnnotationDataList, annotOffset); + + // Reset the line if there were parameters + println(); + } + } + decIndent(); + } + } + + /** + * Prints a list of Visible/Invisible parameter annotations + */ + private void printAnnotationDataList(List annotationDataList, int offset) + throws IOException { + if (annotationDataList != null) { + for (AnnotationData annot : annotationDataList) { + println().print(enlargedIndent(offset)); + annot.setElementState(PARAMETER_ANNOTATION).setOffset(offset + getIndentSize()).print(); + } + } + } + + private String[] getPrintableParameterNames(int maxParams) { + String[] names = new String[maxParams]; + if (methodParameters != null) { + for (int paramNum = 0; paramNum < maxParams; paramNum++) { + MethodParameterData methodParameterData = methodParameters.get(paramNum); + // get printable parameter name + names[paramNum] = Token.PARAM_NAME.parseKey() + "{ "; + if (printCPIndex) { + names[paramNum] += "#%d ".formatted(methodParameterData.name_cpx); + if (!skipComments && methodParameterData.name_cpx != 0) { + names[paramNum] += "/* %s */ ".formatted(data.pool.getString(methodParameterData.name_cpx, index -> "#" + index)); + } + if (methodParameterData.access != 0) { + names[paramNum] += EModifier.asKeywords(methodParameterData.access, ClassFileContext.METHOD_PARAMETERS); + } + } else { + if (methodParameterData.name_cpx != 0) { + names[paramNum] += data.pool.getString(methodParameterData.name_cpx, index -> "#" + index) + " "; + } else { + names[paramNum] += "#0 "; + } + if (methodParameterData.access != 0) { + names[paramNum] += EModifier.asKeywords(methodParameterData.access, ClassFileContext.METHOD_PARAMETERS); + } + } + names[paramNum] += "}"; + } + } + return names; + } + + private String getMethodModifiers() { + return EModifier.asKeywords(access, ClassFileContext.METHOD). + // add synthetic, deprecated if necessary + concat(getPseudoFlagsAsString()); + } + + /** + * Prints the method data to the current output stream. Called from ClassData. + * [SystemInfo]? + * [@(=|-)Annotations]* + * [modifiers]* Method name:descriptor[:signature]?(1) [;]?(2) + * 1) :signature if !table + * 2) if !tableSignatureFormat AND !hasCode AND !hasAnnotationParameters AND !hasException + * [default(;|,)(3)] 3) ; if + * + */ + @Override + protected void jasmPrint(int index, int size) throws IOException { + boolean isSignaturePrintable = this.signature != null && this.signature.isPrintable(); + boolean tableSignatureFormat = isSignaturePrintable && this.signature.isTableOutput(); + boolean hasExceptions = exceptions != null; + boolean hasCode = code != null; + + boolean hasCodeInfo = hasCode || hasAnnotationParameters() || hasExceptions; + boolean noExtraInfo = !hasCodeInfo && !tableSignatureFormat; + if (index > 0) { + // Print empty line between methods + println(); + } + printSysInfo(); + super.printAnnotations(visibleAnnotations, invisibleAnnotations); + super.printAnnotations(visibleTypeAnnotations, invisibleTypeAnnotations); + String methSignature = getMethodModifiers(); + methSignature = methSignature.concat(Token.METHODREF.parseKey()); + methSignature = PadRight(methSignature, max(methSignature.length() + 1, SIGNATURE.parseKey().length() + getIndentSize() * 2)); + int keywordPadding = methSignature.length() - getIndentSize(); + // get JASM Signature info + Pair jasmSignInfo = (isSignaturePrintable) ? + signature.getJasmPrintInfo((i) -> pool.inRange(i)) : + new Pair<>("", ""); + + if (printCPIndex) { + // print the CPX method descriptor + methSignature = methSignature.concat("#%d:#%d".formatted(name_cpx, descriptor_cpx)).concat(jasmSignInfo.first); + if (noExtraInfo && !hasDefaultAnnotation()) { + methSignature = methSignature.concat(";"); + } + if (skipComments) { + if (defaultAnnotation != null) { + printIndent(PadRight(methSignature, getCommentOffset())); + } else { + printIndent(methSignature); + } + } else { + printIndent(PadRight(methSignature, getCommentOffset())); + String comment = (defaultAnnotation != null ? " /* " : " // "). + concat("%s:%s".formatted(data.pool.getName(name_cpx), data.pool.getName(descriptor_cpx), jasmSignInfo.second)). + concat(jasmSignInfo.second). + concat(defaultAnnotation != null ? " */ " : " "); + print(comment); + } + } else { + methSignature = methSignature.concat(data.pool.getName(name_cpx) + ":"). + concat(data.pool.getName(descriptor_cpx)). + concat(jasmSignInfo.second); + if (noExtraInfo && !hasDefaultAnnotation()) { + methSignature = methSignature.concat(";"); + } + printIndent(methSignature); + } + + // followed by default annotation (JLS 9.6.2) + // public abstract Method #7:#8 /* ivalue:"()I" */ default { #10 /* 1 */ }; + if (hasDefaultAnnotation()) { + // printIndent(PadRight(methSignature, getCommentOffset())); + defaultAnnotation.incIndent().setCommentOffset(getIndentSize() - getIndentStep()); + defaultAnnotation.setElementState(HAS_DEFAULT_VALUE); + defaultAnnotation.print(); + // finish up the method declaration + if (!hasCodeInfo) { + print(!tableSignatureFormat ? ";" : ","); + } + } + + if (tableSignatureFormat) { + // print separately + println(); + signature.disableNewLine().setKeywordPadding(keywordPadding).incIndent(). + setCommentOffset(this.getCommentOffset() - getIndentStep()); + signature.terminateMethodSignature(!hasExceptions); + signature.print(); + } + + // followed by exception table + if (exceptions != null) { + println(); + exceptions.setKeywordPadding(keywordPadding).incIndent().setCommentOffset(this.getCommentOffset() - getIndentStep()); + exceptions.print(); + } else { + println(); + } + + if (code != null) { + code.setCommentOffset(this.getCommentOffset()); + code.print(); + } else { + if (hasAnnotationParameters()) { + printMethodParameters(); + } + } + } + + @Override + public void tablePrint(int index, int size) throws IOException { + //There are no differences between the simple (jasm) and extended (table) presentations of record_component_info. + jasmPrint(index, size); + } + + + @Override + protected void printSysInfo() { + if (sysInfo) { + int paramCount = EModifier.isStatic(access) ? 0 : 1; + String prefix = getIndentString() + " * "; + String methodModifiers = getMethodModifiers(); + Type signatureType = signature != null ? signature.getSignatureType() : + new Signature<>(environment.getLogger(), descriptor_cpx).getType(pool); + String methodName = data.pool.getString(name_cpx, funcInvalidCPIndex); + boolean isConstructor = methodName.equals(""); + String methodSignature = signatureType.toString(); + if (signatureType instanceof Type.MethodType methodType) { + paramCount += methodType.paramTypes.size(); + } + int i = 0; + if (isConstructor) { + methodName = data.getClassName(); + methodSignature = methodSignature.substring(methodSignature.indexOf("(")); + } else { + i = methodSignature.indexOf('('); + } + methodName = methodSignature.substring(0, i).concat(methodName). + concat(methodSignature.substring(i)).replaceAll("/", "."); + String descriptor = data.pool.getString(descriptor_cpx, funcInvalidCPIndex); + + printIndentLn("/**"); + println(prefix + methodModifiers + methodName); + prefix = prefix.concat(getIndentString()); + println(prefix + "descriptor: " + descriptor); + if (signature != null) { + println(prefix + "signature: " + data.pool.getString(signature.getCPIndex(), funcInvalidCPIndex)); + } + println(prefix + "flags: (0x%04x) %s".formatted(access, EModifier.asNames(access, METHOD))); + println(prefix + "stack: %d, locals: %d, args_size: %d".formatted(this.code.max_stack, + this.code.max_locals, paramCount)); + printIndentLn(" */"); + } + } + + /** + * MethodParamData + */ + static class MethodParameterData { + + public int access; + public int name_cpx; + + public MethodParameterData(int name, int access) { + this.access = access; + this.name_cpx = name; + } + } +} // end MethodData diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleContent.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleContent.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleContent.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleContent.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.structure.ClassFileContext; +import org.openjdk.asmtools.common.structure.EModifier; +import org.openjdk.asmtools.jasm.NameInfo; + +import java.util.*; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.openjdk.asmtools.common.structure.ClassFileContext.*; +import static org.openjdk.asmtools.jdis.ConstantPool.TAG.*; + +/** + * Internal presentation of a module + */ +public final class ModuleContent extends Indenter { + + private static int MODULE_DIRECTIVE_PADDING = 9; + //* A module name and module_flags + public final Header header; + //* A service dependence's of this module + public final Set uses; + //* Modules on which the current module has a dependence. + public final Set requires; + //* A module exports, may be qualified or unqualified. + public final Map> exports; + //* Packages, to be opened by the current module + public final Map> opens; + //* A service that a dule provides one or more implementations of. + public final Map> provides; + + private ModuleContent(Builder builder) { + this.header = builder.header; + this.requires = Collections.unmodifiableSet(builder.requires); + this.exports = Collections.unmodifiableMap(builder.exports); + this.opens = Collections.unmodifiableMap(builder.opens); + this.uses = Collections.unmodifiableSet(builder.uses); + this.provides = Collections.unmodifiableMap(builder.provides); + } + + public String getModuleFlags() { + return EModifier.asKeywords(header.getFlags(), MODULE); + } + + public String getModuleName() { + return header.getModuleName(); + } + + // Gets the Constant Pool index to this module + public int getModuleCPX() { + return header.getModuleCPX(); + } + + public String getModuleVersion() { + return header.getModuleVersion(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + requires.stream().forEach( + d -> sb.append(IndentPadRight("requires", MODULE_DIRECTIVE_PADDING)). + append(d). + append(format(";%s%n", d.getModuleVersion() == null ? "" : " // @" + d.getModuleVersion()))); + // + exports.entrySet().stream() + .filter(e -> e.getValue().isEmpty()) + .map(e -> IndentPadRight("exports", MODULE_DIRECTIVE_PADDING).concat(format("%s;%n", e.getKey().toString()))) + .forEach(sb::append); + exports.entrySet().stream() + .filter(e -> !e.getValue().isEmpty()) + .map(e -> IndentPadRight("exports", MODULE_DIRECTIVE_PADDING). + concat(format("%s to%n%s;%n", e.getKey().toString(), + e.getValue().stream(). + map(mn -> this.enlargedIndent(mn.toString(), MODULE_DIRECTIVE_PADDING)). + collect(Collectors.joining(",\n")))) + ).forEach(sb::append); + // + opens.entrySet().stream() + .filter(e -> e.getValue().isEmpty()) + .map(e -> IndentPadRight("opens", MODULE_DIRECTIVE_PADDING).concat(format("%s;%n", e.getKey().toString()))) + .forEach(sb::append); + opens.entrySet().stream() + .filter(e -> !e.getValue().isEmpty()) + .map(e -> IndentPadRight("opens", MODULE_DIRECTIVE_PADDING). + concat(format("%s to%n%s;%n", e.getKey().toString(), + e.getValue().stream() + .map(mn -> this.enlargedIndent(mn.toString(), MODULE_DIRECTIVE_PADDING)) + .collect(Collectors.joining(",\n"))))) + .forEach(sb::append); + // + uses.stream().map(s -> IndentPadRight("uses", MODULE_DIRECTIVE_PADDING).concat(format("%s;%n", s))) + .forEach(sb::append); + // + provides.entrySet().stream() + .filter(e -> !e.getValue().isEmpty()) + .map(e -> IndentPadRight("provides", MODULE_DIRECTIVE_PADDING). + concat(format("%s with%n%s;%n", e.getKey().toString(), + e.getValue().stream() + .map(mn -> this.enlargedIndent(mn.toString(), MODULE_DIRECTIVE_PADDING)) + .collect(Collectors.joining(",\n"))))) + .forEach(sb::append); + // + if (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { + sb.deleteCharAt(sb.length() - 1); + } + return sb.toString(); + } + + // A module header consists of a module name and module flags + public final static class Header extends VersionedFlaggedTargetType { + + Header(int cpIndex, String typeName, int flag, String moduleVersion) { + super(CONSTANT_MODULE, cpIndex, typeName, flag, MODULE, moduleVersion); + } + + public String getModuleName() { + return getTypeName(); + } + + public int getModuleFlags() { + return getFlags(); + } + + public String getModuleVersion() { + return getVersion(); + } + + // Gets the Constant Pool index to this module + public int getModuleCPX() { + return getCPIndex(); + } + } + + //* A module on which the current module has a dependence. + public final static class Dependence extends VersionedFlaggedTargetType { + public Dependence(int cpIndex, String moduleName, int flag, String moduleVersion) { + super(CONSTANT_MODULE, cpIndex, moduleName, flag, REQUIRES, moduleVersion); + } + + public String getModuleVersion() { + return getVersion(); + } + } + + public final static class Uses extends TargetType { + public Uses(int cpIndex, String typeName) { + super(CONSTANT_CLASS, cpIndex, typeName); + } + + public Uses(TargetType targetType) { + this(targetType.getCPIndex(), targetType.getTypeName()); + } + } + + //* A provided type of the current module. + public final static class Provided extends TargetType { + public Provided(int cpIndex, String typeName) { + super(CONSTANT_CLASS, cpIndex, typeName); + } + + public Provided(TargetType targetType) { + this(targetType.getCPIndex(), targetType.getTypeName()); + } + + } + + //* An opened package of the current module. + public final static class Opened extends FlaggedTargetType { + public Opened(int cpIndex, String typeName, int opensFlags) { + super(CONSTANT_PACKAGE, cpIndex, typeName, opensFlags, OPENS); + } + + public Opened(FlaggedTargetType targetType) { + this(targetType.getCPIndex(), targetType.getTypeName(), targetType.getFlags()); + } + } + + //* An exported package of the current module. + public final static class Exported extends FlaggedTargetType { + public Exported(int cpIndex, String typeName, int exportsFlags) { + super(CONSTANT_PACKAGE, cpIndex, typeName, exportsFlags, EXPORTS); + } + + public Exported(FlaggedTargetType targetType) { + this(targetType.getCPIndex(), targetType.getTypeName(), targetType.getFlags()); + } + } + + public static class VersionedFlaggedTargetType extends FlaggedTargetType { + private String version; + + VersionedFlaggedTargetType(ConstantPool.TAG tag, int cpIndex, String typeName, int flag, ClassFileContext context, String version) { + super(tag, cpIndex, typeName, flag, context); + this.version = version != null && !version.isEmpty() ? version : null; + } + + public String getVersion() { + return version; + } + + @Override + public int hashCode() { + int code = version == null ? 0 : version.hashCode(); + return code + super.hashCode(); + } + } + + public static class FlaggedTargetType extends TargetType { + private int flag; + private ClassFileContext context; + + public FlaggedTargetType(ConstantPool.TAG tag, int cpIndex, String typeName, int flag, ClassFileContext context) { + super(tag, cpIndex, typeName); + this.flag = flag; + this.context = context; + } + + public boolean isFlagged() { + return true; + } + + public int getFlags() { + return flag; + } + + public void setFlag(int value) { + flag = value; + } + + @Override + public int hashCode() { + return super.hashCode() + flag; + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) && ((FlaggedTargetType) obj).flag == this.flag; + } + + @Override + public String toString() { + return EModifier.asKeywords(this.flag, context) + super.toString(); + } + } + + public static class TargetType extends NameInfo implements Comparable { + + // Type of constant in the constant pool + private final ConstantPool.TAG tag; + + public TargetType(ConstantPool.TAG tag, int cpIndex, String typeName) { + super(cpIndex, typeName); + this.tag = tag; + } + + public String getTypeName() { + return super.name(); + } + + public int getCPIndex() { + return super.cpIndex(); + } + + public boolean isFlagged() { + return false; + } + + @Override + public int hashCode() { + return super.cpIndex() + super.name().hashCode() * 11; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TargetType) { + TargetType t = (TargetType) obj; + return this.name().equals(t.getTypeName()); + } + return false; + } + + @Override + public int compareTo(TargetType t) { + return this.name().compareTo(t.getTypeName()); + } + + @Override + public String toString() { + return (Options.contains(Options.PrintOption.CP_INDEX)) ? String.format("#%-4d /* %s */", getCPIndex(), name()) : name(); + } + } + + /** + * The module builder. + */ + public static final class Builder { + final Set requires = new HashSet<>(); + final Map> exports = new HashMap<>(); + final Map> opens = new HashMap<>(); + final Set uses = new HashSet<>(); + final Map> provides = new HashMap<>(); + private Header header; + private int moduleFlags = EModifier.ACC_NONE.getFlag(); + private int cpIndex; + private String moduleName; + private String moduleVersion; + + public Builder() { + } + + public Builder(int cpIndex, String moduleName, int moduleFlags, String moduleVersion) { + this.cpIndex = cpIndex; + this.moduleFlags = moduleFlags; + this.moduleName = moduleName; + this.moduleVersion = moduleVersion; + } + + public void setModuleFlags(int moduleFlags) { + this.moduleFlags = moduleFlags; + } + + public void setCpIndex(int cpIndex) { + this.cpIndex = cpIndex; + } + + public void setModuleName(String moduleName) { + this.moduleName = moduleName; + } + + public void setModuleVersion(String moduleVersion) { + this.moduleVersion = moduleVersion; + } + + public Builder require(int cpIndex, String d, int requiresFlag, String version) { + return require(new Dependence(cpIndex, d, requiresFlag, version)); + } + + public Builder require(Dependence dependence) { + requires.add(dependence); + return this; + } + + public Builder exports(Exported p, Set ms) { + return add(exports, p, ms); + } + + public Builder exports(int cpIndex, String packageName, int exportFlags) { + return add(exports, new Exported(cpIndex, packageName, exportFlags), new HashSet<>()); + } + + public Builder exports(int cpIndex, String packageName, int exportFlags, Set ms) { + return add(exports, new Exported(cpIndex, packageName, exportFlags), ms); + } + + public Builder opens(Opened p, Set ms) { + return add(opens, p, ms); + } + + public Builder opens(int cpIndex, String packageName, int exportFlags) { + return add(opens, new Opened(cpIndex, packageName, exportFlags), new HashSet<>()); + } + + public Builder opens(int cpIndex, String packageName, int exportFlags, Set ms) { + return add(opens, new Opened(cpIndex, packageName, exportFlags), ms); + } + + public Builder provides(Provided t, Set implementations) { + return add(provides, t, implementations); + } + + public Builder provides(int cpIndex, String serviceName, Set implementations) { + return this.provides(new Provided(cpIndex, serviceName), implementations); + } + + public Builder uses(int cpIndex, String serviceName) { + return this.uses(new Uses(cpIndex, serviceName)); + } + + public Builder uses(Uses service) { + uses.add(service); + return this; + } + + /** + * @return The new module + */ + public ModuleContent build() { + header = new Header(cpIndex, moduleName, moduleFlags, moduleVersion); + return new ModuleContent(this); + } + + private Builder add(Map> collection, T source, Set target) { + Objects.requireNonNull(source); + Objects.requireNonNull(target); + if (!collection.containsKey(source)) + collection.put(source, new HashSet<>()); + collection.get(source).addAll(target); + return this; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ModuleData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import static org.openjdk.asmtools.jdis.ConstantPool.TAG.CONSTANT_CLASS; +import static org.openjdk.asmtools.jdis.ConstantPool.TAG.CONSTANT_MODULE; +import static org.openjdk.asmtools.jdis.Options.PrintOption.CP_INDEX; + +/** + * The module attribute data. + */ +public class ModuleData extends MemberData { + + protected final boolean printCPIndex = Options.contains(CP_INDEX); + private ModuleContent moduleContent; + + public ModuleData(ClassData classData) { + super(classData); + } + + public String getModuleName() { + return moduleContent == null ? "N/A" : moduleContent.getModuleName(); + } + + public String getModuleVersion() { + return moduleContent == null ? null : moduleContent.getModuleVersion(); + } + + public String getModuleHeader(String versionString) { + StringBuilder sb = new StringBuilder(25); + if (moduleContent == null) { + sb.append(JasmTokens.Token.MODULE.parseKey()); + sb.append(' '); + if (printCPIndex) { + sb.append(String.format("#?? /* %s */", getModuleName())); + } else { + sb.append(getModuleName()); + } + if (versionString != null && versionString.length() > 0) { + sb.append(' ').append(versionString); + } + } else { + sb.append(moduleContent.getModuleFlags()); + sb.append(JasmTokens.Token.MODULE.parseKey()).append(' '); + if (printCPIndex) { + sb.append(String.format("#%d /* %s%s%s", + moduleContent.getModuleCPX(), + moduleContent.getModuleName(), + moduleContent.getModuleVersion() != null ? "@" + moduleContent.getModuleVersion() + " */" : " */", + (versionString != null && versionString.length() > 0) ? " " + versionString : "")); + } else { + sb.append(moduleContent.getModuleName()); + if (versionString != null && versionString.length() > 0) { + sb.append(' ').append(versionString); + } + if (moduleContent.getModuleVersion() != null) { + sb.append("// @").append(moduleContent.getModuleVersion()); + } + } + } + return sb.toString(); + } + + /** + * Reads and resolve the method's attribute data called from ClassData. + */ + public void read(DataInputStream in) throws FormatError { + int index, moduleFlags, versionIndex; + String moduleName, version; + ModuleContent.Builder builder = null; + try { + // u2 module_name_index; + index = in.readUnsignedShort(); + moduleName = pool.getModuleName(index); + + // u2 module_flags; + moduleFlags = in.readUnsignedShort(); + + // u2 module_version_index; + versionIndex = in.readUnsignedShort(); + version = pool.getString(versionIndex, ind -> null); + builder = new ModuleContent.Builder(index, moduleName, moduleFlags, version); + } catch (IOException ioe) { + if (bestEffort) { + environment.getLogger().error("err.invalid_header"); + if (builder == null) { + return; + } + } else { + throw new FormatError(environment.getLogger(), "err.invalid_header"); + } + } + try { + int requires_count = in.readUnsignedShort(); + for (int i = 0; i < requires_count; i++) { + index = in.readUnsignedShort(); + int requiresFlags = in.readUnsignedShort(); + versionIndex = in.readUnsignedShort(); + + moduleName = pool.getModuleName(index); + version = pool.getString(versionIndex, ind -> null); + builder.require(index, moduleName, requiresFlags, version); + } + } catch (IOException ioe) { + if (bestEffort) { + environment.getLogger().error("err.invalid_requires"); + } else { + throw new FormatError(environment.getLogger(), "err.invalid_requires"); + } + } + + try { + int exports_count = in.readUnsignedShort(); + if (exports_count > 0) { + for (int i = 0; i < exports_count; i++) { + index = in.readUnsignedShort(); + String packageName = pool.getPackageName(index); + int exportsFlags = in.readUnsignedShort(); + int exports_to_count = in.readUnsignedShort(); + if (exports_to_count > 0) { + Set targets = new HashSet<>(exports_to_count); + for (int j = 0; j < exports_to_count; j++) { + int exports_to_index = in.readUnsignedShort(); + targets.add(new ModuleContent.TargetType(CONSTANT_MODULE, exports_to_index, pool.getModuleName(exports_to_index))); + } + builder.exports(index, packageName, exportsFlags, targets); + } else { + builder.exports(index, packageName, exportsFlags); + } + } + } + } catch (IOException ioe) { + if (bestEffort) { + environment.getLogger().error("err.invalid_exports"); + } else { + throw new FormatError(environment.getLogger(), "err.invalid_exports"); + } + } + + try { + int opens_count = in.readUnsignedShort(); + if (opens_count > 0) { + for (int i = 0; i < opens_count; i++) { + index = in.readUnsignedShort(); + String packageName = pool.getPackageName(index); + int opensFlags = in.readUnsignedShort(); + int opens_to_count = in.readUnsignedShort(); + if (opens_to_count > 0) { + Set opens = new HashSet<>(opens_to_count); + for (int j = 0; j < opens_to_count; j++) { + int opens_to_index = in.readUnsignedShort(); + opens.add(new ModuleContent.TargetType(CONSTANT_MODULE, opens_to_index, pool.getModuleName(opens_to_index))); + } + builder.opens(index, packageName, opensFlags, opens); + } else { + builder.opens(index, packageName, opensFlags); + } + } + } + } catch (IOException ioe) { + if (bestEffort) { + environment.getLogger().error("err.invalid_opens"); + } else { + throw new FormatError(environment.getLogger(), "err.invalid_opens"); + } + } + + try { + int uses_count = in.readUnsignedShort(); + if (uses_count > 0) { + for (int i = 0; i < uses_count; i++) { + index = in.readUnsignedShort(); + String serviceName = pool.getClassName(index); + builder.uses(index, serviceName); + } + } + } catch (IOException ioe) { + if (bestEffort) { + environment.getLogger().error("err.invalid_uses"); + } else { + throw new FormatError(environment.getLogger(), "err.invalid_uses"); + } + } + + try { + int provides_count = in.readUnsignedShort(); + if (provides_count > 0) { + for (int i = 0; i < provides_count; i++) { + index = in.readUnsignedShort(); + String serviceName = pool.getClassName(index); + int provides_with_count = in.readUnsignedShort(); + Set implNames = new HashSet<>(provides_with_count); + for (int j = 0; j < provides_with_count; j++) { + int provides_with_index = in.readUnsignedShort(); + implNames.add(new ModuleContent.TargetType(CONSTANT_CLASS, provides_with_index, pool.getClassName(provides_with_index))); + } + builder.provides(index, serviceName, implNames); + } + } + } catch (IOException ioe) { + if (bestEffort) { + environment.getLogger().error("err.invalid_provides"); + } else { + throw new FormatError(environment.getLogger(), "err.invalid_provides"); + } + } + moduleContent = builder.build(); + } + + /* Print Module Content */ + public void print() { + if (moduleContent != null) { + String s = moduleContent.toString(); + if (!s.isEmpty()) { + println(s); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestHostData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestHostData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestHostData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestHostData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.NEST_HOST; + +/** + * The NestHost attribute data + *

+ * NestHost_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 host_class_index; + * } + * since class file 55.0 (JEP 181) + */ +public class NestHostData extends AttributeData { + + public NestHostData(ClassData classData) { + super(classData, NEST_HOST); + } + + public String calculateName() { + if (this.name == null) { + this.name = pool.getClassName(cpx, + index -> "%s #%d".formatted(logger.getResourceString("info.invalid_cp_entry"), index)); + } + return this.name; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestMembersData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestMembersData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestMembersData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/NestMembersData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; + +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.NEST_MEMBERS; + +/** + * The NestMembers attribute data + *

+ * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + */ +public class NestMembersData extends ClassArrayData { + public NestMembersData(ClassData cls) { + super(cls, JasmTokens.Token.NESTMEMBERS); + tableToken = NEST_MEMBERS; + } + + public NestMembersData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + return (NestMembersData) super.read(in, attribute_length); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Options.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Options.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Options.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Options.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.util.EnumSet; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.openjdk.asmtools.jdis.Indenter.*; +import static org.openjdk.asmtools.jdis.Options.PrintOption.*; + +/** + * The singleton class to share global options among jdis classes. + */ +public class Options { + + // Initial options correspond to calling the tool without options. + static private final EnumSet PRINT_OPTIONS = EnumSet.of( + // default option(s) + LABELS); + + public static String getPrintOptions() { + return PRINT_OPTIONS.stream().map(op -> format("%-26s: \"%s\"", op.name(), op.descriptor)). + collect(Collectors.joining("\n")); + } + + // Print Options + public enum PrintOption { + NONE("No options"), + CONSTANT_POOL("Constant Pool"), + PRINT_BCI("Program Counter - for all instructions"), + LABELS("Labels (as identifiers)"), + CP_INDEX("CP index along with arguments"), + LINE_NUMBER_TABLE_Numbers("Line Numbers in comments"), + LINE_NUMBER_TABLE_Lines("Java Source Lines in comments"), + LINE_NUMBER_TABLE_Table("LineNumberTable attribute as table"), + LINE_NUMBER_TABLE_All("Line Numbers, Source Lines, attribute as Table", (option) -> setGroupOption(option)), + LOCAL_VARIABLE_Vars("Print LocalVariableTable attribute"), + LOCAL_VARIABLE_Types("Print LocalVariableTypeTable attribute"), + LOCAL_VARIABLE_All("Print both LocalVariableTable and LocalVariableTypeTable attributes", (option) -> setGroupOption(option)), + HEX("Numbers as hexadecimals"), + TRACE("Print internal traces, debug information"), + SYSINFO("system information"), + NO_COMMENTS("No comments, suppress printing comments"), + VERBOSE("Verbose information"), + TABLE("Attributes as table"), + DROP_Source("Discard SourceFile attribute"), + DROP_Signatures("Discard Signature attribute"), + DROP_Classes("Discard this_class and super_class pair"), + DROP_CharacterRange("Discard CharacterRangeTable attribute"), + DROP_All("Discard SourceFile, CharacterRangeTable attributes, this_class and super_class pair", (option) -> setGroupOption(option)), + DETAILED_Output("Detailed output"), + EXTRA_DETAILED_Output("Detailed output, this_class and super_class pair"), + BEST_EFFORT("Print as much as possible despite errors"); + + final String descriptor; + final Consumer action; + + PrintOption(String descriptor) { + this.descriptor = descriptor; + this.action = null; + } + + PrintOption(String descriptor, Consumer action) { + this.descriptor = descriptor; + this.action = action; + } + + public void apply() { + if (this.action != null) + action.accept(this); + else + set(this); + } + + /** + * @return PR if PR value has format {Prefix}{Any Chars}_{flag} and flag == postfix otherwise null + */ + public static PrintOption getStringFlag(String prefix, String flag) { + for (PrintOption item : PrintOption.values()) { + String name = item.name(); + if (name.startsWith(prefix)) { + int ind = item.name().lastIndexOf('_'); + if (ind > 0 && name.substring(ind + 1).equalsIgnoreCase(flag)) { + return item; + } + } + } + return null; + } + + private static final EnumSet inProgresses = EnumSet.of( + DROP_CharacterRange); + + public boolean isActive() { + return !PrintOption.inProgresses.contains(this); + } + } + + static private final EnumSet DETAILED_OUTPUT = EnumSet.of( // -g: detailed output format + CONSTANT_POOL, + PRINT_BCI, + CP_INDEX, + // Print LocalVariables, LocalVariableTypes only if it's specified. + // LOCAL_VARIABLE_Vars, LOCAL_VARIABLE_Types, + DETAILED_Output + ); + + static private final EnumSet DROP_ALL = EnumSet.of( // -drop || -drop:all + DROP_Source, + DROP_Classes, + DROP_CharacterRange + ); + + static private final EnumSet LINE_NUMBER_TABLE_ALL = EnumSet.of( + LINE_NUMBER_TABLE_Numbers, + LINE_NUMBER_TABLE_Lines, + LINE_NUMBER_TABLE_Table + ); + + static private final EnumSet LOCAL_VARIABLE_ALL = EnumSet.of( + LOCAL_VARIABLE_Vars, + LOCAL_VARIABLE_Types + ); + + + public static void set(PrintOption val) { + if (val == PRINT_BCI) { + TABLE_PADDING = OPERAND_PLACEHOLDER_LENGTH + INSTR_PREFIX_LENGTH + 3; + } + PRINT_OPTIONS.add(val); + } + + public static void unset(PrintOption val) { + if (val == PRINT_BCI) { + TABLE_PADDING = OPERAND_PLACEHOLDER_LENGTH + INSTR_PREFIX_LENGTH + 1; + } + PRINT_OPTIONS.remove(val); + } + + public static void setDetailedOutputOptions() { + set(DETAILED_OUTPUT); + unset(PrintOption.LABELS); + } + + public static void set(EnumSet vals) { + for (PrintOption val : vals) { + set(val); + } + } + + public static void unset(EnumSet vals) { + for (PrintOption val : vals) { + unset(val); + } + } + + public static void setGroupOption(PrintOption option) { + switch (option) { + case LOCAL_VARIABLE_All -> set(LOCAL_VARIABLE_ALL); + case LINE_NUMBER_TABLE_All -> set(LINE_NUMBER_TABLE_ALL); + case DROP_All -> set(DROP_ALL); + default -> throw new RuntimeException("%s ia not group option".formatted(option.name())); + } + } + + public static void setDefaultOutputOptions() { + PRINT_OPTIONS.clear(); + set(PrintOption.LABELS); + } + + public static boolean contains(PrintOption... vals) { + for (PrintOption val : vals) { + if (PRINT_OPTIONS.contains(val)) { + return true; + } + } + return false; + } + + public static String asShortString() { + return format("[ %s ]", + PRINT_OPTIONS.stream().map(item -> item.name()).collect(Collectors.joining(", "))); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ParameterAnnotationData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ParameterAnnotationData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ParameterAnnotationData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/ParameterAnnotationData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; + +/** + * 4.7.18. The RuntimeVisibleParameterAnnotations Attribute + * 4.7.19. The RuntimeInvisibleParameterAnnotations Attribute + * + * RuntimeVisibleParameterAnnotations | RuntimeInvisibleParameterAnnotations_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u1 num_parameters; + * { u2 num_annotations; + * annotation annotations[num_annotations]; + * } parameter_annotations[num_parameters]; + * } + * + */ +public class ParameterAnnotationData extends MemberData{ + + private final boolean invisible; + private ArrayList>> array = null; + + public ParameterAnnotationData(T data, boolean invisible) { + super(data); + this.invisible = invisible; + } + + public int numParameters() { + return (array == null) ? 0 : array.size(); + } + + public ArrayList> get(int i) { + return array.get(i); + } + + public void read(DataInputStream in) throws IOException { + int numParams = in.readByte(); + environment.traceln("ParameterAnnotationData[%d]:", numParams); + array = new ArrayList<>(numParams); + for (int paramNum = 0; paramNum < numParams; paramNum++) { + int numAnnotations = in.readShort(); + environment.traceln(" Param#[%d]: numAnnotations= %d", paramNum, numAnnotations); + if (numAnnotations > 0) { + // read annotation + ArrayList> paramAnnotationList = new ArrayList<>(numAnnotations); + for (int annotIndex = 0; annotIndex < numAnnotations; annotIndex++) { + AnnotationData annotationData = new AnnotationData(data, invisible); + annotationData.read(in); + paramAnnotationList.add(annotationData); + } + array.add(paramNum, paramAnnotationList); + } else { + array.add(paramNum, null); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/PermittedSubclassesData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/PermittedSubclassesData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/PermittedSubclassesData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/PermittedSubclassesData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * The PermittedSubclasses attribute data + *

+ * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubclasses_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + */ +public class PermittedSubclassesData extends ClassArrayData { + public PermittedSubclassesData(ClassData cls) { + super(cls, JasmTokens.Token.PERMITTEDSUBCLASSES); + } + + public PermittedSubclassesData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + return (PermittedSubclassesData) super.read(in, attribute_length); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Printable.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Printable.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Printable.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Printable.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.IOException; + +public interface Printable { + + void print() throws IOException; + + default boolean isPrintable() { + return true; + } + + /** + * @return true if a table format is supported + */ + default boolean tableFormatSupported() { + return false; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/RecordData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/RecordData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/RecordData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/RecordData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.jasm.JasmTokens; +import org.openjdk.asmtools.jasm.TableFormatModel; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.openjdk.asmtools.jasm.JasmTokens.Token.RECORD; + +/** + * The Record attribute data + *

+ * since class file 58.65535 (JEP 359) + */ +public class RecordData extends MemberData { + + private List components; + + public RecordData(ClassData classData) { + super(classData); + this.tableToken = TableFormatModel.Token.RECORD_DATA; + } + + public RecordData read(DataInputStream in) throws IOException { + int count = in.readUnsignedShort(); + environment.traceln("components=" + count); + components = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + components.add(new Component(data).read(in)); + } + return this; + } + + /** + * Prints the record data to the current output stream. Called from ClassData. + */ + @Override + public void print() throws IOException { + int count = components.size(); + if (count > 0) { + boolean isExtendedPrintingSupported = tableToken.isExtendedPrintingSupported(); + printIndentLn("%s {".formatted(RECORD.parseKey())); + for (int i = 0; i < count; i++) { + Component cn = components.get(i); + cn.setCommentOffset(getCommentOffset() + getIndentSize()).incIndent(); + if (isExtendedPrintingSupported && isTableOutput()) + cn.tablePrint(i, count); + else + cn.jasmPrint(i, count); + } + printIndentLn("}"); + } + } + + /** + * record_component_info { + * u2 name_index; + * u2 descriptor_index; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + * } + */ + public static class Component extends MemberData { + // CP index to a CONSTANT_Utf8_info structure representing a valid unqualified name denoting the record component + private int name_cpx; + // CP index to a CONSTANT_Utf8_info structure representing a field descriptor which encodes the type of the record component (§4.3.2). + private int descriptor_cpx; + + public Component(ClassData classData) { + super(classData); + memberType = "RecordData"; + } + + @Override + protected boolean handleAttributes(DataInputStream in, EAttribute attributeTag, int attributeLength) throws IOException { + // Read the Attributes + boolean handled = true; + if (attributeTag == EAttribute.ATT_Signature) { + if (signature != null) { + environment.warning("warn.one.attribute.required", "Signature", "record_component_info"); + } + signature = new SignatureData(data).read(in, attributeLength); + } else { + handled = false; + } + return handled; + } + + /** + * Read and resolve the component data called from ClassData. + */ + public Component read(DataInputStream in) throws IOException { + // read the Component CP indexes + name_cpx = in.readUnsignedShort(); + descriptor_cpx = in.readUnsignedShort(); + environment.traceln("RecordComponent: name[%d]=%s descriptor[%d]=%s". + formatted(name_cpx, data.pool.getString(name_cpx, index -> "?"), + descriptor_cpx, data.pool.getString(descriptor_cpx, index -> "?"))); + // Read the attributes + readAttributes(in); + return this; + } + + /** + * Prints the component data to the current output stream. Called from RecordData. + */ + @Override + public void jasmPrint(int index, int size) throws IOException { + boolean printSignature = signature != null && signature.isPrintable() && tableFormat; + // print component's attributes + super.printAnnotations(visibleAnnotations, invisibleAnnotations); + super.printAnnotations(visibleTypeAnnotations, invisibleTypeAnnotations); + // print component: add synthetic, deprecated if necessary + int keywordPadding = getPrintAttributeKeyPadding() + getIndentSize() * 2 - INDENT_STEP; + String prefix = PadRight( + Indent(getPseudoFlagsAsString()).concat(JasmTokens.Token.COMPONENT.parseKey()), keywordPadding); + printVar(new StringBuilder(prefix), null, + printSignature ? ":" : ";", + name_cpx, descriptor_cpx, UNDEFINED); + // print Signature if necessary + if (printSignature) { + keywordPadding -= getIndentSize() + INDENT_STEP; + signature.setKeywordPadding(keywordPadding).incIndent().incIndent(). + setCommentOffset(this.getCommentOffset() - getIndentStep() * 2 - INDENT_STEP); + signature.print(); + } + } + + @Override + public void tablePrint(int index, int size) throws IOException { + //There are no differences between the simple (jasm) and extended (table) presentations of record_component_info. + jasmPrint(index, size); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SignatureData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SignatureData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SignatureData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SignatureData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.jdis.notations.Signature; +import org.openjdk.asmtools.jdis.notations.Type; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.function.Function; + +import static java.lang.String.format; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.SIGNATURE; + +/** + * The Signature attribute data since class file 49.0 + *

+ * Signature_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 signature_index; + * } + */ +public class SignatureData extends MemberData { + private int cpIndex; + private Type signatureType = null; + private int keywordPadding = -1; + private String attributeTerminator = ";"; + + // in some cases, the new line should not end the printed signature + private String eol = System.getProperty("line.separator"); + + public SignatureData(ClassData classData) { + super(classData); + this.tableToken = SIGNATURE; + } + + public int getCPIndex() { + return cpIndex; + } + + @Override + public boolean isPrintable() { + return !dropSignatures; + } + + public SignatureData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + if (attribute_length != 2) { + if (bestEffort) { + environment.getLogger().error( + "err.invalid.attribute.length", EAttribute.ATT_Signature.printValue(), attribute_length); + } else { + throw new FormatError(environment.getLogger(), + "err.invalid.attribute.length", EAttribute.ATT_Signature.printValue(), attribute_length); + } + } + cpIndex = in.readUnsignedShort(); + return this; + } + + @Override + public String toString() { + return format("signature[%d]=%s", cpIndex, pool.StringValue(cpIndex)); + } + + public String getJavaSignature() { + if (signatureType == null) { + signatureType = new Signature(environment.getLogger(), cpIndex).getType(pool); + } + return signatureType != null ? + signatureType.toString().replace('/', '.') : + pool.StringValue(cpIndex); + } + + public Type getSignatureType() { + if (signatureType == null) { + signatureType = new Signature(environment.getLogger(), cpIndex).getType(pool); + } + return signatureType; + } + + public SignatureData setKeywordPadding(int keywordPadding) { + this.keywordPadding = keywordPadding; + return this; + } + + @Override + protected int getPrintAttributeKeyPadding() { + return keywordPadding == -1 ? super.getPrintAttributeKeyPadding() : keywordPadding; + } + + public SignatureData disableNewLine() { + this.eol = ""; + return this; + } + + public SignatureData enableNewLine() { + this.eol = System.getProperty("line.separator"); + return this; + } + + @Override + protected void tablePrint() { + printIndent(PadRight(tableToken.printKey(), getPrintAttributeKeyPadding())); + String sign = pool.StringValue(cpIndex); + if (printCPIndex) { + if (skipComments) { + print("#%d%s".formatted(cpIndex,this.attributeTerminator).concat(eol)); + } else { + print(PadRight("#%d%s".formatted(cpIndex,this.attributeTerminator), getPrintAttributeCommentPadding())). + print(" // ".concat(sign).concat(eol)); + } + } else { + print(sign.concat("%s".formatted(this.attributeTerminator)).concat(eol)); + } + } + + @Override + protected void jasmPrint() { + printIndent(PadRight(SIGNATURE.parseKey(), getPrintAttributeKeyPadding())); + String sign = pool.StringValue(cpIndex); + if (printCPIndex) { + if (skipComments) { + print("#%d%s".formatted(cpIndex,this.attributeTerminator).concat(eol)); + } else { + print(PadRight("#%d%s".formatted(cpIndex,this.attributeTerminator), getPrintAttributeCommentPadding())). + print(" // ".concat(sign).concat(eol)); + } + } else { + print(sign.concat("%s".formatted(this.attributeTerminator)).concat(eol)); + } + } + + /** + * @param checkRange function to check that index belongs CP + * @return a string representation of the index and signature used to print the JASM-specific signature + * of ClassFile, field_info, method_info, or record_component_info. + * Alternatively, return an empty pair (new Pair("", "")) if extended (table-specific) printing is requested. + */ + public Pair getJasmPrintInfo(Function checkRange) { + return (tableFormat) ? + new Pair<>("", "") : + new Pair<>(format(":#%d", cpIndex), + checkRange.apply(cpIndex) ? ":" + pool.StringValue(cpIndex) : + ":?%d Invalid constant_pool index".formatted(cpIndex)); + } + + public void terminateMethodSignature(boolean value) { + this.attributeTerminator = value ? ";" : ","; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceDebugExtensionData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceDebugExtensionData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceDebugExtensionData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceDebugExtensionData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.List; + +import static org.openjdk.asmtools.asmutils.StringUtils.readUtf8String; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.SOURCEDEBUGEXTENSION; + +/** + * The SourceDebugExtension attribute + *

+ * SourceDebugExtension_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u1 debug_extension[attribute_length]; + * } + */ +public class SourceDebugExtensionData extends Indenter { + + List debug_extension; + + public SourceDebugExtensionData(ClassData classData) { + super(classData.toolOutput); + } + + public SourceDebugExtensionData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + debug_extension = readUtf8String(in, attribute_length, 76 - getIndentSize()); + return this; + } + + @Override + public void print() { + printIndentLn(SOURCEDEBUGEXTENSION.parseKey() + " {"); + incIndent(); + debug_extension.forEach(s -> printIndentLn(s)); + decIndent(); + printIndentLn("}"); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceFileData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceFileData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceFileData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/SourceFileData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.SOURCE_FILE; + +/** + * The SourceFile attribute since 45.3 + *

+ * SourceFile_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 sourcefile_index; + * } + */ +public class SourceFileData extends AttributeData { + + public SourceFileData(ClassData classData) { + super(classData, SOURCE_FILE); + } + + @Override + public boolean isPrintable() { + return !dropSourceFile && calculateName() != null; + } + + public String calculateName() { + if (this.name == null) { + this.name = pool.getString(cpx, index -> null); + } + return this.name; + } + + public SourceFileData getName() { + name = pool.getString(cpx, index -> "#%d".formatted(index)); + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,497 @@ +/* + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.asmutils.Pair; +import org.openjdk.asmtools.asmutils.Range; +import org.openjdk.asmtools.common.structure.EAttribute; +import org.openjdk.asmtools.common.structure.StackMap; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.openjdk.asmtools.asmutils.StringUtils.mapToHexString; +import static org.openjdk.asmtools.common.structure.EAttribute.ATT_StackMap; +import static org.openjdk.asmtools.common.structure.EAttribute.ATT_StackMapTable; +import static org.openjdk.asmtools.common.structure.StackMap.EntryType.EARLY_LARVAL; +import static org.openjdk.asmtools.common.structure.StackMap.EntryType.FULL_FRAME; +import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.STACK_MAP; +import static org.openjdk.asmtools.jasm.TableFormatModel.Token.STACK_MAP_TABLE; + +/** + * Represents one entry of StackMapTable attribute: + *

+ * union stack_map_entry { + * same_frame; + * same_locals_1_stack_item_frame; + * same_locals_1_stack_item_frame_extended; + * chop_frame; + * same_frame_extended; + * append_frame; + * full_frame; + * } + *

+ * or StackMap attribute + *

+ * stack_map_entry { + * u2 offset; + * u2 number_of_locals; + * verification_type_info locals[number_of_locals]; + * u2 number_of_stack_items; + * verification_type_info stack[number_of_stack_items]; + * } + * + * @see Code Attribute + * @see StackMapTable Attribute + */ +public class StackMapData extends MemberData { + + static Range range = new Range<>(247, 255); + + private final EAttribute attribute; + + StackMap.EntryType stackEntryType; + // stack frame type value + int stackEntryTypeValue; + boolean isWrapped = false; + int wrapLevel = 0; // isWrapped == false + int frame_pc; + int offset; + int[] lockMap; + int[] stackMap; + int[] unsetFields; + + private Printer printer; + private int doubleIndent = getIndentStep() * 2; + private int tripleIndent = getIndentStep() * 3; + private String intLine = ""; + private String strLine = ""; + private int shift; + private String tableHeader = ""; + + @FunctionalInterface + public interface Printer { + void accept(Integer t, Integer u) throws IOException; + } + + /** + * Prints the StackMap data in Jasm format. + * + * @param index the index of the current entry + * @param size the total number of entries + * @throws IOException if an I/O error occurs while printing + */ + @Override + protected void jasmPrint(int index, int size) throws IOException { + incIndent(); + if (index == 0) { + printIndentLn(tableHeader); + } + printer.accept(index, size); + decIndent(); + } + + private void stackMapPrinter(int index, int size) throws IOException { + println(enlargedIndent(intLine.formatted(BYTECODEOFFSET.parseKey(), frame_pc), getIndentStep())); + for (Map.Entry> entry : Map.of( + "%-10s".formatted(STACKMAP.parseKey()), new Pair<>(stackMap != null, stackMap), + "%-10s".formatted(LOCALSMAP.parseKey()), new Pair<>(lockMap != null, lockMap)).entrySet()) { + if (entry.getValue().first) { + int[] map = entry.getValue().second; + Pair line = getMapListAsString(map, " "); + String record = strLine.formatted(entry.getKey(), "[" + (printCPIndex ? line.first : line.second) + "]"); + if (printCPIndex) { + if (skipComments) { + println(enlargedIndent(record, getIndentStep() * 2)); + } else { + print(PadRight(enlargedIndent(record, getIndentStep()), getCommentOffsetFor(27, 2))); + println(map.length == 0 ? "" : " //" + line.second); + } + } else { + println(enlargedIndent(record, getIndentStep() * 2)); + } + } + } + } + + private void stackMapTablePrinter(int index, int size) { + String strFrameType = intLine.formatted(FRAMETYPE.parseKey(), stackEntryTypeValue); + int padding = 0; + + if (isWrapped) { + incIndent(wrapLevel); + } + + if (skipComments && printCPIndex) { + printIndentLn(strFrameType); + } else { + padding = doubleIndent + ((printCPIndex) ? + getCommentOffsetFor(strFrameType, 2) : + strFrameType.length() + padding * getIndentStep()); + if (printCPIndex) { + printIndent(PadRight(strFrameType, padding - getIndentStep() * (wrapLevel + 2))); + println(skipComments ? "" : " // " + stackEntryType.printName()); + } else { + printIndent(PadRight(strFrameType, padding - getIndentStep() * wrapLevel)); + println(skipComments ? "" : " // " + stackEntryType.printName()); + } + } + if (range.in(stackEntryTypeValue)) { + println(enlargedIndent(intLine.formatted(OFFSETDELTA.parseKey(), offset), doubleIndent)); + } + + if (stackEntryType == EARLY_LARVAL) { + if (unsetFields != null) { + final int limit = unsetFields.length - 1; + String delim = limit >= 0 ? "; " : ""; + String prefix = "%-12s".formatted(UNSETFIELDS.parseKey()); + Pair, List> line = getFieldListAsString(unsetFields); + String left = line.first.stream().collect(Collectors.joining(", ")).concat(delim); + String right = line.second.stream().collect(Collectors.joining(", ")).concat(delim); + String record = strLine.formatted(prefix, "[ " + (printCPIndex ? left : right) + "] {"); + if (printCPIndex) { + if (skipComments) { + println(enlargedIndent(record, doubleIndent)); + } else { + if (limit <= 0) { + print(PadRight(enlargedIndent(record, doubleIndent), padding)); + println(unsetFields.length == 0 ? "" : " // " + right); + } else { + String str = PadRight(enlargedIndent(strLine.formatted( + prefix, "[ " + line.first.get(0).concat(",")), doubleIndent), padding); + int offs = str.indexOf('[') - INDENT_STEP * (wrapLevel + 1); + print(str).println(" // " + line.second.get(0)); + for (int i = 1; i <= limit; i++) { + delim = i == limit ? "; ] {" : ","; + String id = line.first.get(i); + String field = line.second.get(i); + print(PadRight(enlargedIndent(id.concat(delim), offs), padding)). + println(" // " + field); + } + } + } + } else { + if (limit <= 0) { + println(enlargedIndent(record, doubleIndent)); + } else { + // first element + println(enlargedIndent(strLine.formatted( + prefix, "[ " + line.second.get(0).concat(",")), doubleIndent)); + for (int i = 1; i <= limit; i++) { + delim = i == limit ? "; ] {" : ","; + String field = line.second.get(i); + println(enlargedIndent(" %s%s".formatted(field, delim), padding - 2)); + } + } + } + } + } else { + for (Map.Entry> entry : Map.of( + STACKMAP.parseKey(), new Pair<>(stackMap != null, stackMap), + LOCALSMAP.parseKey(), new Pair<>(lockMap != null, lockMap)).entrySet()) { + if (entry.getValue().first) { + // map found + int[] map = entry.getValue().second; + Pair line = getMapListAsString(map, " "); + String record = "[" + (printCPIndex ? line.first : line.second) + "]"; + if (printCPIndex) { + if (skipComments) { + println(enlargedIndent(strLine.formatted(entry.getKey(), record), doubleIndent)); + } else { + print(PadRight(enlargedIndent(strLine.formatted(entry.getKey(), record), doubleIndent), padding)). + println(" //" + line.second); + } + } else { + println(enlargedIndent(strLine.formatted(entry.getKey(), record), doubleIndent)); + } + } + } + if (isWrapped) { + for (int i = 0; i < wrapLevel; i++) { + println(enlargedIndent(" }", (printCPIndex) ? tripleIndent : doubleIndent)); + decIndent(); + } + } + } + } + + @Override + protected void tablePrint(int index, int size) throws IOException { + //There are no differences between the simple (jasm) and extended (table) presentations of StackMapTable attribute. + this.jasmPrint(index, size); + } + + @Override + public boolean isPrintable() { + return tableFormat; + } + + /** + * Constructor for ATT_StackMap (Java 5,6) + * + * @param code the code attribute where this attribute is located + * @param in the input stream + * @throws IOException the exception if something went wrong + */ + public StackMapData(CodeData code, DataInputStream in) throws IOException { + super(code); + this.attribute = ATT_StackMap; + + super.memberType = ATT_StackMap.parseKey(); + super.tableToken = STACK_MAP; + this.printer = this::stackMapPrinter; + this.stackEntryType = FULL_FRAME; + this.stackEntryTypeValue = FULL_FRAME.fromTag(); + this.frame_pc = in.readUnsignedShort(); + this.lockMap = readMap(in); + this.stackMap = readMap(in); + environment.traceln(() -> " stack_map_entry:pc=%d numloc=%s numstack=%s".formatted(frame_pc, + mapToHexString(lockMap), mapToHexString(stackMap))); + } + + /** + * Constructor for ATT_StackMapTable (Java 6, 7+) + * + * @param firstStackMap is it an entries[0] in the stack_map_entry structure? i.e. Does the StackMapData describe + * the second stack map frame of the method? + * @param prevFrame_pc the bytecode offset of the previous entry (entries[current_index-1]) + * @param code the code attribute where this attribute is located + * @param in the input stream + * @throws IOException the exception if something went wrong + */ + public StackMapData(boolean firstStackMap, int prevFrame_pc, CodeData code, DataInputStream in) throws IOException { + super(code); + this.attribute = ATT_StackMapTable; + + super.memberType = ATT_StackMapTable.parseKey(); + super.tableToken = STACK_MAP_TABLE; + stackEntryTypeValue = in.readUnsignedByte(); + stackEntryType = StackMap.stackMapEntryType(stackEntryTypeValue); + printer = this::stackMapTablePrinter; + switch (stackEntryType) { + case EARLY_LARVAL -> { + // Valhalla: The entry type is early_larval_frame (246) + offset = UNDEFINED; + this.unsetFields = readFields(in); + environment.traceln(() -> " early_larval_frame=%d".formatted(stackEntryTypeValue)); + } + case SAME_FRAME -> { + // The entry type is same_frame; + offset = stackEntryTypeValue; + environment.traceln(() -> " same_frame=%d".formatted(stackEntryTypeValue)); + } + case SAME_FRAME_EXTENDED -> { + // The entry type is same_frame_extended; + offset = in.readUnsignedShort(); + environment.traceln(() -> " same_frame_extended=%d, offset=%d".formatted(stackEntryTypeValue, offset)); + } + case SAME_LOCALS_1_STACK_ITEM_FRAME -> { + // The entry type is same_locals_1_stack_item_frame + offset = stackEntryTypeValue - 64; + stackMap = readMapElements(in, 1); + environment.traceln(() -> " same_locals_1_stack_item_frame=%d, offset=%d, numstack=%s".formatted( + stackEntryTypeValue, offset, mapToHexString(stackMap))); + } + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED -> { + // The entry type is same_locals_1_stack_item_frame_extended + offset = in.readUnsignedShort(); + stackMap = readMapElements(in, 1); + environment.traceln(() -> " same_locals_1_stack_item_frame_extended=%d, offset=%d, numstack=%s".formatted( + stackEntryTypeValue, offset, mapToHexString(stackMap))); + } + case CHOP_1_FRAME, CHOP_2_FRAME, CHOP_3_FRAME -> { + // The entry type is chop_frame + offset = in.readUnsignedShort(); + environment.traceln(() -> " chop_frame=%d offset=%d".formatted(stackEntryTypeValue, offset)); + } + case APPEND_FRAME -> { + // The entry type is append_frame + offset = in.readUnsignedShort(); + lockMap = readMapElements(in, stackEntryTypeValue - 251); + environment.traceln(() -> " append_frame=%d offset=%d numlock=%s".formatted( + stackEntryTypeValue, offset, mapToHexString(lockMap))); + } + case FULL_FRAME -> { + // The entry type is full_frame + offset = in.readUnsignedShort(); + lockMap = readMap(in); + stackMap = readMap(in); + environment.traceln(() -> " full_frame=%d offset=%d numloc=%s numstack=%s".formatted( + stackEntryTypeValue, offset, mapToHexString(lockMap), mapToHexString(stackMap))); + } + default -> environment.traceln(() -> "incorrect entry_type argument"); + } + if (prevFrame_pc <= 0 && firstStackMap) { + frame_pc = offset; + } else { + frame_pc = prevFrame_pc + offset + 1; + } + } + + /** + * @return the bytecode offset at which a stack map frame applies + */ + public int getFramePC() { + return frame_pc; + } + + public StackMap.EntryType getStackEntryType() { + return stackEntryType; + } + + public Pair, List> getFieldListAsString(int[] fields) { + int count = fields.length; + ArrayList left = new ArrayList<>(count); + ArrayList right = new ArrayList<>(count); + for (int index : fields) { + if (data.printCPIndex) { + left.add("#%d".formatted(index)); + } + right.add(data.pool.getFieldNameTypeAsString(index)); + } + return new Pair<>(left, right); + } + + public Pair getMapListAsString(int[] map, String delimiter) { + if (map == null || map.length == 0) { + return new Pair<>("", ""); + } + StringBuilder left = new StringBuilder(); + StringBuilder right = new StringBuilder(); + int count = map.length - 1; + for (int k = 0; k <= count; k++) { + if (k == 0) { + left.append(delimiter); + right.append(delimiter); + } + int fullMapType = map[k]; + int mtVal = fullMapType & 0xFF; + StackMap.VerificationType mapVerificationType = StackMap.getVerificationType(mtVal, Optional.of((s, a) -> environment.error(s, a))); + String prefix = k == 0 ? "" : " "; + int argument = fullMapType >> 8; + switch (mapVerificationType) { + case ITEM_Object -> { + if (data.printCPIndex) { + left.append(prefix).append("#").append(argument); + } + right.append(prefix).append(data.pool.ConstantStrValue(argument)); + } + case ITEM_NewObject -> { + if (data.printCPIndex) { + left.append(prefix).append(mtVal); + left.append(" ").append(getLabelPrefix()).append(argument); + } + right.append(prefix).append(mapVerificationType.printName()); + right.append(" ").append(getLabelPrefix()).append(argument); + } + default -> { + if (data.printCPIndex) { + left.append(prefix).append(mtVal); + } + right.append(prefix).append(mapVerificationType.printName()); + } + } + if (data.printCPIndex) { + left.append(k == count ? ';' : ','); + } + right.append((k == count ? ';' : ',')); + if (k == count) { + left.append(delimiter); + right.append(delimiter); + } + } + return new Pair<>(left.toString(), right.toString()); + } + + /** + * @return true if the entity presents a StackMapTable since Java 6 + */ + public boolean belongsToStackMapTable() { + return attribute == ATT_StackMapTable; + } + + /** + * Sets helper printing particles + */ + public StackMapData setPrintParticles(String intLine, String strLine, int shift) { + this.intLine = intLine; + this.strLine = strLine; + this.shift = shift; + return this; + } + + /** + * Sets table header + */ + public StackMapData setHeader(String header) { + this.tableHeader = header; + return this; + } + + private int[] readMap(DataInputStream in) throws IOException { + int num = in.readUnsignedShort(); + return readMapElements(in, num); + } + + private int[] readFields(DataInputStream in) throws IOException { + int num = in.readUnsignedShort(); + int[] fields = new int[num]; + for (int i = 0; i < num; i++) { + fields[i] = in.readUnsignedShort(); + } + return fields; + } + + private int[] readMapElements(DataInputStream in, int num) throws IOException { + int[] map = new int[num]; + for (int k = 0; k < num; k++) { + int mt_val; + mt_val = in.readUnsignedByte(); + StackMap.VerificationType stackMapVerificationType = StackMap.getVerificationType(mt_val, Optional.of((s, a) -> environment.error(s, a))); + switch (stackMapVerificationType) { + case ITEM_Object -> mt_val = mt_val | (in.readUnsignedShort() << 8); + case ITEM_NewObject -> { + int pc = in.readUnsignedShort(); + data.getInstructionAttribute(pc).referred = true; + mt_val = mt_val | (pc << 8); + } + } + map[k] = mt_val; + } + return map; + } + + private int getCommentOffsetFor(String line, int shiftCount) { + return owner.getPrintAttributeCommentPadding() + shift + line.length() - shiftCount * getIndentStep() - 2; + } + + private int getCommentOffsetFor(int lineLength, int shiftCount) { + return owner.getPrintAttributeCommentPadding() + shift + lineLength - shiftCount * getIndentStep() - 2; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapTable.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapTable.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapTable.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/StackMapTable.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.structure.EAttribute; + +import java.io.IOException; +import java.util.ArrayList; + +import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; + +/** + * StackMapTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_entries; + * stack_map_frame entries[number_of_entries]; + * } + */ +public class StackMapTable extends Container { + + private final EAttribute attribute; + // Container for flags of elements: true is for a container element is a wrapper + // (i.e. early_larval_frame) for the next one. + protected final ArrayList wrappers; + private String jasmHeader = ": number_of_entries = %d"; + private String intLine = "n/a"; + private String strLine = "n/a"; + private int shift; + + /** + * @param attribute either Implicit stack map attribute or the StackMapTable attribute of the container + * @param owner + * @param initialCapacity initial capacity of the stack_map_frame entries[number_of_entries]; + */ + public StackMapTable(EAttribute attribute, CodeData owner, int initialCapacity) { + super(owner, StackMapData.class, initialCapacity); + this.wrappers = new ArrayList<>(initialCapacity); + this.attribute = attribute; + switch (this.attribute) { + case ATT_StackMap -> { + shift = owner.calculateInlinedTitleShift(LOCALSMAP.parseKey()); + jasmHeader = STACKMAP_HEADER.parseKey() + jasmHeader; + } + case ATT_StackMapTable -> { + shift = owner.calculateInlinedTitleShift(FRAMETYPE.parseKey()); + jasmHeader = STACKMAPTABLE_HEADER.parseKey() + jasmHeader; + } + default -> throw new IllegalStateException("Unexpected value: " + this.attribute); + } + intLine = "%" + shift + "s = %-3d"; + strLine = "%" + shift + "s = %s"; + } + + public void add(StackMapData element, boolean isWrapper) throws IOException { + element.setPrintParticles(intLine, strLine, shift); + super.add(element); + wrappers.add(isWrapper); + } + + public int real_size() { + int mWrappers = (int) wrappers.stream() + .filter(Boolean::booleanValue) + .count(); + return elements.size() - mWrappers; + } + + /** + * Prints StackMapTable_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_entries; + * stack_map_frame entries[number_of_entries]; + * } + * + * There are no differences between the simple (jasm) and extended (table) presentations of StackMapTable attribute. + * + * @throws IOException if an I/O error occurs while printing + */ + @Override + public void print() throws IOException { + int size = this.size(); + if (size > 0) { + elements.get(0).setHeader(jasmHeader.formatted(real_size())); + setMaxPrintSize(getPrintSize()); + for (int i = 0; i < size; i++) { + StackMapData element = elements.get(i); + element.setCommentOffset(this.getCommentOffset()); + element.jasmPrint(i, size); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TextLines.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TextLines.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TextLines.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TextLines.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * A container for the java sources tied to an asm output when -sl in on + */ +public class TextLines { + + final Path file; + List lines; + + public TextLines(Path directory, String sourceFileName) { + file = directory == null ? Paths.get(sourceFileName) : directory.resolve(sourceFileName); + try { + lines = Files.readAllLines(file, StandardCharsets.UTF_8); + } catch (IOException ignore) {} + } + + public String getLine(int index) { + if( lines != null ) { + if (index < 1 || index >= lines.size()) { + return String.format("Line number %d is out of range in \"%s\"", index, file); + } + return lines.get(index - 1); + } + return String.format("\"%s\" not found", file); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TrapData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TrapData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TrapData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TrapData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Exception table entry (JVMS 4.7.3 The Code Attribute) describes one exception handler + * in the code array {@link CodeData}. + */ +class TrapData { + + int num; + + // exception_table + int start_pc, // u2 + end_pc, // u2 + handler_pc, // u2 + catch_cpx; // u2 + + public TrapData(DataInputStream in, int num) throws IOException { + this.num = num; + start_pc = in.readUnsignedShort(); + end_pc = in.readUnsignedShort(); + handler_pc = in.readUnsignedShort(); + catch_cpx = in.readUnsignedShort(); + } + + // returns recommended identifier + public String id() { + return "T" + num; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TypeAnnotationData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TypeAnnotationData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TypeAnnotationData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/TypeAnnotationData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,297 @@ +/* + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.TypeAnnotationTargetInfoData; +import org.openjdk.asmtools.jasm.TypeAnnotationTypePathData; + +import java.io.DataInputStream; +import java.io.IOException; + +import static org.openjdk.asmtools.jasm.TypeAnnotationTargetInfoData.*; +import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.*; + +/** + * Type Annotation data is a specific kind of AnnotationData. As well as the normal data + * items needed to present an annotation, Type annotations require a TargetInfo + * descriptor. This descriptor is based on a TargetType, and it optionally may contain a + * location descriptor (when the Type is embedded in a collection). + *

+ * The TypeAnnotationData class is based on JDis's AnnotationData class, and contains the + * (jasm) class for representing TargetInfo. + */ +public class TypeAnnotationData extends AnnotationData { + + private final TargetTypeVisitor targetTypeVisitor = new TargetTypeVisitor(); + private TypeAnnotationTargetInfoData targetInfo; + private final TypeAnnotationTypePathData typePath; + + public TypeAnnotationData(T data, boolean invisible) { + super(data, invisible); + targetInfo = null; + typePath = new TypeAnnotationTypePathData(); + visibleAnnotationToken = "@T+"; + invisibleAnnotationToken = "@T-"; + dataName = "TypeAnnotationData"; + } + + @Override + public void read(DataInputStream in) throws IOException { + + int targetTypeID = in.readUnsignedByte(); + ETargetType targetType = ETargetType.getTargetType(targetTypeID); + + if (targetType == null) { + // Throw some kind of error for bad target type index + throw new IOException("Bad target type: " + targetTypeID + " in TypeAnnotationData"); + } + + // read the target info + targetTypeVisitor.init(in); + targetTypeVisitor.visitExcept(targetType); + targetInfo = targetTypeVisitor.getTargetInfo(); + + // read the target path info + int len = in.readUnsignedByte(); + environment.traceln("[TypeAnnotationData.read]: Reading Location (length = " + len + ")."); + environment.trace("[TypeAnnotationData.read]: [ "); + for (int i = 0; i < len; i++) { + int pathType = in.readUnsignedByte(); + String pk = (getPathKind(pathType)).parseKey(); + char pathArgIndex = (char) in.readUnsignedByte(); + typePath.addTypePathEntry(new TypePathEntry(pathType, pathArgIndex)); + environment.trace(" " + pk + "(" + pathType + "," + pathArgIndex + "), "); + } + environment.traceln("] "); + super.read(in); + } + + @Override + protected void printBody() throws IOException { + // For a type annotation, print out brackets, + // print out the (regular) annotation name/value pairs, + // then print out the target types. + /* Previous version + -------------------------------------------------------------------------------------------- + out.print(" {"); + super.printBody(out, ""); + targetInfo.print(out, tab); + typePath.print(out, tab); + out.print(tab + "}"); + -------------------------------------------------------------------------------------------- + */ + if (isEmpty()) { + // Marker annotation + print(" { { }"); + } else { + println(" {"); + setElementState(AnnotationElementState.INLINED_ELEMENT); + super.printBody(); + } + print(targetInfo.toPrintString()); + String location = typePath.toPrintString(); + if (!location.isBlank()) { + print(location + " "); + } + print("}"); + } + + /** + * Target Type visitor, used for constructing the target-info within a type + * annotation. visitExcept() is the entry point. ti is the constructed target info. + */ + private class TargetTypeVisitor extends TypeAnnotationTargetVisitor { + + private TypeAnnotationTargetInfoData targetInfo = null; + private IOException IOProb = null; + private DataInputStream in; + + public void init(DataInputStream in) { + this.in = in; + } + + public int scanByteVal() { + int val = 0; + try { + val = in.readUnsignedByte(); + } catch (IOException e) { + IOProb = e; + } + return val; + } + + public int scanShortVal() { + int val = 0; + try { + val = in.readUnsignedShort(); + } catch (IOException e) { + IOProb = e; + } + return val; + } + + //This is the entry point for a visitor that tunnels exceptions + public void visitExcept(ETargetType targetType) throws IOException { + IOProb = null; + targetInfo = null; + environment.traceln("Target Type: " + targetType.parseKey()); + visit(targetType); + + if (IOProb != null) { + throw IOProb; + } + } + + public TypeAnnotationTargetInfoData getTargetInfo() { + return targetInfo; + } + + private boolean error() { + return IOProb != null; + } + + @Override + public void visit_type_param_target(ETargetType targetType) { + environment.trace("Type Param Target: "); + int paramIndex = scanByteVal(); + environment.traceln("{ param_index: " + paramIndex + "}"); + if (!error()) { + targetInfo = new type_parameter_target(targetType, paramIndex); + } + } + + @Override + public void visit_supertype_target(ETargetType targetType) { + environment.trace("SuperType Target: "); + int typeIndex = scanShortVal(); + environment.traceln("{ type_index: " + typeIndex + "}"); + if (!error()) { + targetInfo = new supertype_target(targetType, typeIndex); + } + } + + @Override + public void visit_typeparam_bound_target(ETargetType targetType) { + environment.trace("TypeParam Bound Target: "); + int paramIndex = scanByteVal(); + if (error()) { + return; + } + int boundIndex = scanByteVal(); + if (error()) { + return; + } + environment.traceln("{ param_index: " + paramIndex + " bound_index: " + boundIndex + "}"); + targetInfo = new type_parameter_bound_target(targetType, paramIndex, boundIndex); + } + + @Override + public void visit_empty_target(ETargetType targetType) { + environment.traceln("Empty Target: "); + if (!error()) { + targetInfo = new empty_target(targetType); + } + } + + @Override + public void visit_methodformalparam_target(ETargetType targetType) { + environment.trace("MethodFormalParam Target: "); + int paramIndex = scanByteVal(); + environment.traceln("{ param_index: " + paramIndex + "}"); + if (!error()) { + targetInfo = new formal_parameter_target(targetType, paramIndex); + } + } + + @Override + public void visit_throws_target(ETargetType targetType) { + environment.trace("Throws Target: "); + int exceptionIndex = scanShortVal(); + environment.traceln("{ exception_index: " + exceptionIndex + "}"); + if (!error()) { + targetInfo = new throws_target(targetType, exceptionIndex); + } + } + + @Override + public void visit_localvar_target(ETargetType targetType) { + environment.traceln("LocalVar Target: "); + int tableLength = scanShortVal(); // table length (short) + if (error()) { + return; + } + localvar_target locvartab = new localvar_target(targetType, tableLength); + targetInfo = locvartab; + + for (int i = 0; i < tableLength; i++) { + int startPC = scanShortVal(); + if (error()) { + return; + } + int length = scanShortVal(); + if (error()) { + return; + } + int CPX = scanShortVal(); + environment.trace("LocalVar[" + i + "]: "); + environment.traceln("{ startPC: " + startPC + ", length: " + length + ", CPX: " + CPX + "}"); + locvartab.addEntry(startPC, length, CPX); + } + } + + @Override + public void visit_catch_target(ETargetType targetType) { + environment.trace("Catch Target: "); + int catchIndex = scanShortVal(); + environment.traceln("{ catch_index: " + catchIndex + "}"); + if (!error()) { + targetInfo = new catch_target(targetType, catchIndex); + } + } + + @Override + public void visit_offset_target(ETargetType targetType) { + environment.trace("Offset Target: "); + int offsetIndex = scanShortVal(); + environment.traceln("{ offset_index: " + offsetIndex + "}"); + if (!error()) { + targetInfo = new offset_target(targetType, offsetIndex); + } + } + + @Override + public void visit_typearg_target(ETargetType targetType) { + environment.trace("TypeArg Target: "); + int offset = scanShortVal(); + if (error()) { + return; + } + int typeIndex = scanByteVal(); + if (error()) { + return; + } + environment.traceln("{ offset: " + offset + " type_index: " + typeIndex + "}"); + targetInfo = new type_argument_target(targetType, offset, typeIndex); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utf8ArrayData.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utf8ArrayData.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utf8ArrayData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utf8ArrayData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,57 @@ +package org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.jasm.ConstantPool; +import org.openjdk.asmtools.jasm.DataVector; +import org.openjdk.asmtools.jasm.JasmTokens; + +public class Utf8ArrayData extends ClassArrayData { + protected > Utf8ArrayData(M classData, JasmTokens.Token token) { + super(classData, token); + } + + public void jasmPrintShort() { + StringBuilder indexes = new StringBuilder(); + StringBuilder names = new StringBuilder(); + int lastIndex = this.indexes.length - 1; + String eoNames = (printCPIndex) ? "" : ";"; + for (int i = 0; i <= lastIndex; i++) { + if (printCPIndex) { + indexes.append("#").append(this.indexes[i]).append(i == lastIndex ? ";" : ", "); + } + names.append(pool.StringValue(this.indexes[i])).append(i == lastIndex ? eoNames : ", "); + } + printIndent(PadRight(token.parseKey(), getPrintAttributeKeyPadding())); + if (printCPIndex) { + if (skipComments) { + println(indexes.toString()); + } else { + print(PadRight(indexes.toString(), getPrintAttributeCommentPadding())).println(" // " + names); + } + } else { + println(names.toString()); + } + } + + public void jasmPrintLong() { + String name = token.parseKey(); + String locIndent = " ".repeat(name.length()); + int lastIndex = indexes.length - 1; + for (int i = 0; i <= lastIndex; i++) { + if (printCPIndex) { + if (skipComments) { + printIndent(PadRight((i == 0) ? name : locIndent, getPrintAttributeKeyPadding())). + print("#%d".formatted(indexes[i])).println(i == lastIndex ? ";" : ","); + } else { + printIndent(PadRight((i == 0) ? name : locIndent, getPrintAttributeKeyPadding())). + print(PadRight("#%d%s".formatted(indexes[i], (i == lastIndex) ? ";" : ","), getPrintAttributeCommentPadding())). + println(" // %s".formatted(pool.StringValue(indexes[i]))); + } + } else { + printIndent(PadRight((i == 0) ? name : locIndent, getPrintAttributeKeyPadding())). + print(pool.StringValue(indexes[i])).println(i == lastIndex ? ";" : ","); + } + } + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utils.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utils.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/Utils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +public class Utils { + + static public String javaName(String name) { + if (name == null) { + return "null"; + } + int len = name.length(); + if (len == 0) { + return "\"\""; + } + char cc = '/'; + fullname: + { // xxx/yyy/zzz + for (int k = 0; k < len; k++) { + char c = name.charAt(k); + if (cc == '/') { + if (!Character.isJavaIdentifierStart(c) && c != '-') { + break fullname; + } + } else if (c != '/') { + if (!Character.isJavaIdentifierPart(c) && c != '-') { + break fullname; + } + } + cc = c; + } + return name; + } + return "\"" + name + "\""; + } + + static public boolean isClassArrayDescriptor(String name) { + return (name != null) && name.startsWith("["); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/i18n.properties jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/i18n.properties --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/i18n.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/i18n.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,98 @@ +# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +info.usage=\ +Usage: java -jar asmtools.jar jdis [options] |- decompile into jasm file(s)\n\ +\ if - is provided, is used\n\ +where possible options include: +# see also shared section in asmtools/i18 +info.opt.g=\ +\ -g Generate a detailed output format. +info.opt.b=\ +\ -best-effort Print as much information as possible despite errors; suppresses the -v option. +info.opt.gg=\ +\ -gg Generate a detailed output format. This includes displaying\ +\nthe pair of this_class and super_class. +info.opt.lnt=\ +\ -lnt:\n Print the LineNumberTable attribute in a Code attribute:\ +\n table - print the LineNumberTable attribute as a table \ +\n numbers - print numbers of source lines in inlined comments\ +\n lines - print Java source lines if a class file with LineNumberTable attribute and Java source file are in the same folder\ +\n all - print both line numbers and Java source lines in inlined comments, and LineNumberTable attribute as a table\ +\nThe ''-lnt'' without parameters functions the same way as ''-lnt:all'' +info.opt.lvt=\ +\ -lvt:\n Print LocalVariableTable,LocalVariableTypeTable attributes in a Code attribute:\ +\n vars - print LocalVariableTable attribute\ +\n types - print LocalVariableTypeTable attribute\ +\n all - print both LocalVariableTable and LocalVariableTypeTable attributes\ +\nThe ''-lvt'' without parameters functions the same way as ''-lvt:all'' +info.opt.instr.offset=\ +\ -pc Print instruction offsets when the output is not detailed with the options -g or -gg. +info.opt.nc=\ +\ -nc Don''t print comments +info.opt.hx=\ +\ -hx Generate floating-point constants in hexadecimal format. +info.opt.table=\ +\ -table Print specific attributes in a table format resembling the style of the ''javap'' command. +info.opt.sysinfo=\ +\ -sysinfo Show system info (path, size, date, SHA-256 hash) of class being processed +info.opt.drop=\ +\ -drop:\n Discard some attributes or their groups where:\ +\n source - SourceFile attribute\ +\n classes - this_class, super_class pair\ +\n all - SourceFile attribute, this_class and super_class pair\ +\n The ''-drop'' without parameters functions the same way as ''-drop:all'' +#info.opt.drop.ex=\ +#\ -drop:\n Discard some attributes or their groups where:\ +#\n all=SourceFile,CharacterRange\ +#\nThe ''-drop'' without parameters functions the same way as ''-drop:all'' + +err.cannot.write=Cannot write to {0} + +err.invalid_option=Invalid option: {0} +err.invalid_parameter_of_option=Invalid parameter \"{0}\" of option: {1} +err.option.unsupported=Not implemented yet: {0} +err.not_found=No such file: {0} +err.count.issues={0}{1}in the file: {2} +err.unknown.tag=Unknown tag in annotation \"{0}\" [0x{1}] +err.invalid.attribute.length={0}: Invalid attribute length #{1} +warn.one.attribute.required=There is more than one \"{0}\" attribute in the attributes table of a \"{1}\" structure. The last one is used. +warn.attribute.name.corrupted=The value of the attribute_name_index #{0} item is not a valid index into the constant_pool table. The attribute is ignored. +warn.attribute.name.incorrect=The attribute_name_index #{0} refers to an unknown attribute name. The attribute is ignored. +warn.attribute.type.incorrect=The constant_pool entry \"{0}\" is not of an appropriate type for the field. +warn.attribute.constantvalue.incorrect=The constantvalue_index \"{0}\" is not a valid index into the constant_pool table. +warn.attribute.constantvalue.unrecognized=Unrecognized constantvalue_index: #{0} [ {1} ] + +warn.field.nametype.required=The ConstantPool[{0}] must be a CONSTANT_NameAndType_info structure with a field descriptor +err.invalid_header=Invalid Module attributes table +err.invalid_requires=Invalid requires table +err.invalid_exports=Invalid exports table +err.invalid_opens=Invalid opens table +err.invalid_uses=Invalid uses table +err.invalid_provides=Invalid provides table +err.invalid.desc=Invalid descriptor \"{0}\" +err.invalid.desc.at=Descriptor is invalid at offset \"{0}\" in \"{1}\" +err.eof=The end of the file was unexpectedly reached while reading class data +info.corrupted_cp_entry=??? The entry is missing from the constant_pool table +info.invalid_cp_entry=??? Invalid constant_pool reference +info.corrupted_bootstrap_method_ref=??? Invalid bootstrap method reference +warn.wrong.magic=The magic number identifying the class file format is expected to be {0}. The invalid magic number {1} will be ignored. +err.out.of.range=The index {0} is out of range for the code array of the method. diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Descriptor.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Descriptor.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Descriptor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Descriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.asmtools.jdis.notations; + +import org.openjdk.asmtools.common.FormatError; +import org.openjdk.asmtools.common.ToolLogger; +import org.openjdk.asmtools.jdis.ConstantPool; + +/** + * See JVMS, section 4.4. + */ +public class Descriptor { + private static final int UNDEF = -1; + + public static class InvalidDescriptor extends FormatError { + InvalidDescriptor(T logger, String desc) { + super(logger, "err.invalid.desc", desc); + } + + InvalidDescriptor(T logger, String desc, int index) { + super(logger, "err.invalid.desc.at", index, desc); + } + } + + + public final int index; + public final String descriptor; + public final T logger; + + /** + * Constructor for the descriptor placed in the constant_pool + * + * @param logger to log any exceptions if they occur. + * @param index a valid reference into the constant_pool table + */ + public Descriptor(T logger, int index) { + this.index = index; + this.descriptor = null; + this.logger = logger; + } + + /** + * Constructor for the descriptor presented as String + * + * @param logger to log any exceptions if they occur. + * @param descriptor the string presentation of the descriptor + */ + public Descriptor(T logger, String descriptor) { + this.index = UNDEF; + this.descriptor = descriptor; + this.logger = logger; + } + + + public String getValue(ConstantPool pool) { + return pool == null ? this.descriptor : pool.getString(index, i -> "#" + index); + } + + + + public int getParameterCount(ConstantPool constant_pool) throws InvalidDescriptor { + String desc = getValue(constant_pool); + int end = desc.indexOf(")"); + if (end == -1) + throw new InvalidDescriptor(logger, desc); + parse(desc, 0, end + 1); + return count; + + } + + public String getParameterTypes(ConstantPool constant_pool) throws InvalidDescriptor { + String desc = getValue(constant_pool); + + int end = desc.indexOf(")"); + if (end == -1) + throw new InvalidDescriptor(logger, desc); + return parse(desc, 0, end + 1); + } + + public String getReturnType(ConstantPool constant_pool) + throws InvalidDescriptor { + String desc = getValue(constant_pool); + int end = desc.indexOf(")"); + if (end == -1) + throw new InvalidDescriptor(logger, desc); + return parse(desc, end + 1, desc.length()); + } + + public String getFieldType(ConstantPool constant_pool) + throws InvalidDescriptor { + String desc = getValue(constant_pool); + return parse(desc, 0, desc.length()); + } + + private String parse(String desc, int start, int end) + throws InvalidDescriptor { + int p = start; + StringBuilder sb = new StringBuilder(); + int dims = 0; + count = 0; + + while (p < end) { + String type; + char ch; + switch (ch = desc.charAt(p++)) { + case '(': + sb.append('('); + continue; + + case ')': + sb.append(')'); + continue; + + case '[': + dims++; + continue; + + case 'B': + type = "byte"; + break; + + case 'C': + type = "char"; + break; + + case 'D': + type = "double"; + break; + + case 'F': + type = "float"; + break; + + case 'I': + type = "int"; + break; + + case 'J': + type = "long"; + break; + + case 'L': + int sep = desc.indexOf(';', p); + if (sep == -1) + throw new InvalidDescriptor(logger, desc, p - 1); + type = desc.substring(p, sep).replace('/', '.'); + p = sep + 1; + break; + + case 'S': + type = "short"; + break; + + case 'Z': + type = "boolean"; + break; + + case 'V': + type = "void"; + break; + + default: + throw new InvalidDescriptor(logger, desc, p - 1); + } + + if (sb.length() > 1 && sb.charAt(0) == '(') + sb.append(", "); + sb.append(type); + for (; dims > 0; dims--) + sb.append("[]"); + + count++; + } + return sb.toString(); + } + + private int count; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/DescriptorException.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/DescriptorException.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/DescriptorException.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/DescriptorException.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.asmtools.jdis.notations; +public class DescriptorException extends Exception { + private static final long serialVersionUID = 2411890273788901032L; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Signature.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Signature.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Signature.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Signature.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.asmtools.jdis.notations; + +import org.openjdk.asmtools.common.ToolLogger; +import org.openjdk.asmtools.jdis.ConstantPool; +import org.openjdk.asmtools.jdis.notations.Type.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * See JVMS 4.4.4. + */ +public class Signature extends Descriptor { + + /** + * Constructor for the signature placed in the constant_pool + * + * @param logger to log any exceptions, if they occur. + * @param index a valid reference into the constant_pool table + */ + public Signature(T logger, int index) { + super(logger, index); + } + + /** + * Constructor for the descriptor presented as String + * + * @param logger to log any exceptions if they occur. + * @param signature the string presentation of the descriptor + */ + public Signature(T logger, String signature) { + super(logger, signature); + } + + public Type getType(ConstantPool pool) { + if (type == null) + type = parse(getValue(pool)); + return type; + } + + @Override + public int getParameterCount(ConstantPool pool) { + MethodType m = (MethodType) getType(pool); + return m.paramTypes.size(); + } + + @Override + public String getParameterTypes(ConstantPool pool) { + MethodType m = (MethodType) getType(pool); + StringBuilder sb = new StringBuilder(); + sb.append("("); + String sep = ""; + for (Type paramType : m.paramTypes) { + sb.append(sep); + sb.append(paramType); + sep = ", "; + } + sb.append(")"); + return sb.toString(); + } + + @Override + public String getReturnType(ConstantPool pool) { + MethodType m = (MethodType) getType(pool); + return m.returnType.toString(); + } + + @Override + public String getFieldType(ConstantPool pool) { + return getType(pool).toString(); + } + + private Type parse(String sig) { + this.sig = sig; + sigp = 0; + + List typeParamTypes = null; + if (sig.charAt(sigp) == '<') + typeParamTypes = parseTypeParamTypes(); + + if (sig.charAt(sigp) == '(') { + List paramTypes = parseTypeSignatures(')'); + Type returnType = parseTypeSignature(); + List throwsTypes = null; + while (sigp < sig.length() && sig.charAt(sigp) == '^') { + sigp++; + if (throwsTypes == null) + throwsTypes = new ArrayList<>(); + throwsTypes.add(parseTypeSignature()); + } + return new MethodType(typeParamTypes, paramTypes, returnType, throwsTypes); + } else { + Type t = parseTypeSignature(); + if (typeParamTypes == null && sigp == sig.length()) + return t; + Type superclass = t; + List superinterfaces = null; + while (sigp < sig.length()) { + if (superinterfaces == null) + superinterfaces = new ArrayList<>(); + superinterfaces.add(parseTypeSignature()); + } + return new ClassSigType(typeParamTypes, superclass, superinterfaces); + } + } + + private Type parseTypeSignature() { + switch (sig.charAt(sigp)) { + case 'B': + sigp++; + return new SimpleType("byte"); + + case 'C': + sigp++; + return new SimpleType("char"); + + case 'D': + sigp++; + return new SimpleType("double"); + + case 'F': + sigp++; + return new SimpleType("float"); + + case 'I': + sigp++; + return new SimpleType("int"); + + case 'J': + sigp++; + return new SimpleType("long"); + + case 'L': + return parseClassTypeSignature(); + + case 'S': + sigp++; + return new SimpleType("short"); + + case 'T': + return parseTypeVariableSignature(); + + case 'V': + sigp++; + return new SimpleType("void"); + + case 'Z': + sigp++; + return new SimpleType("boolean"); + + case '[': + sigp++; + return new ArrayType(parseTypeSignature()); + + case '*': + sigp++; + return new WildcardType(); + + case '+': + sigp++; + return new WildcardType(WildcardType.Kind.EXTENDS, parseTypeSignature()); + + case '-': + sigp++; + return new WildcardType(WildcardType.Kind.SUPER, parseTypeSignature()); + + default: + throw new IllegalStateException(debugInfo()); + } + } + + private List parseTypeSignatures(char term) { + sigp++; + List types = new ArrayList<>(); + while (sig.charAt(sigp) != term) + types.add(parseTypeSignature()); + sigp++; + return types; + } + + private Type parseClassTypeSignature() { + assert sig.charAt(sigp) == 'L'; + sigp++; + return parseClassTypeSignatureRest(); + } + + private Type parseClassTypeSignatureRest() { + StringBuilder sb = new StringBuilder(); + List argTypes = null; + ClassType t = null; + char sigch; + + do { + switch (sigch = sig.charAt(sigp)) { + case '<': + argTypes = parseTypeSignatures('>'); + break; + + case '.': + case ';': + sigp++; + t = new ClassType(t, sb.toString(), argTypes); + sb.setLength(0); + argTypes = null; + break; + + default: + sigp++; + sb.append(sigch); + break; + } + } while (sigch != ';'); + + return t; + } + + private List parseTypeParamTypes() { + assert sig.charAt(sigp) == '<'; + sigp++; + List types = new ArrayList<>(); + while (sig.charAt(sigp) != '>') + types.add(parseTypeParamType()); + sigp++; + return types; + } + + private TypeParamType parseTypeParamType() { + int sep = sig.indexOf(":", sigp); + String name = sig.substring(sigp, sep); + Type classBound = null; + List interfaceBounds = null; + sigp = sep + 1; + if (sig.charAt(sigp) != ':') + classBound = parseTypeSignature(); + while (sig.charAt(sigp) == ':') { + sigp++; + if (interfaceBounds == null) + interfaceBounds = new ArrayList<>(); + interfaceBounds.add(parseTypeSignature()); + } + return new TypeParamType(name, classBound, interfaceBounds); + } + + private Type parseTypeVariableSignature() { + sigp++; + int sep = sig.indexOf(';', sigp); + Type t = new SimpleType(sig.substring(sigp, sep)); + sigp = sep + 1; + return t; + } + + private String debugInfo() { + return sig.substring(0, sigp) + "!" + sig.charAt(sigp) + "!" + sig.substring(sigp + 1); + } + + private String sig; + private int sigp; + + private Type type; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Type.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Type.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Type.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/jdis/notations/Type.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.asmtools.jdis.notations; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Family of classes used to represent the parsed form of a {@link Descriptor} + * or {@link Signature}. + */ +public abstract class Type { + protected Type() { + } + + public boolean isObject() { + return false; + } + + public abstract R accept(Visitor visitor, D data); + + protected static void append(StringBuilder sb, String prefix, List types, String suffix) { + sb.append(prefix); + String sep = ""; + for (Type t : types) { + sb.append(sep); + sb.append(t); + sep = ", "; + } + sb.append(suffix); + } + + protected static void appendIfNotEmpty(StringBuilder sb, String prefix, List types, String suffix) { + if (types != null && types.size() > 0) + append(sb, prefix, types, suffix); + } + + public interface Visitor { + R visitSimpleType(SimpleType type, P p); + + R visitArrayType(ArrayType type, P p); + + R visitMethodType(MethodType type, P p); + + R visitClassSigType(ClassSigType type, P p); + + R visitClassType(ClassType type, P p); + + R visitTypeParamType(TypeParamType type, P p); + + R visitWildcardType(WildcardType type, P p); + } + + /** + * Represents a type signature with a simple name. The name may be that of a + * primitive type, such "{@code int}, {@code float}, etc + * or that of a type argument, such as {@code T}, {@code K}, {@code V}, etc. + *

+ * See: + * JVMS 4.3.2 + * BaseType: + * {@code B}, {@code C}, {@code D}, {@code F}, {@code I}, + * {@code J}, {@code S}, {@code Z}; + * VoidDescriptor: + * {@code V}; + * JVMS 4.3.4 + * TypeVariableSignature: + * {@code T} Identifier {@code ;} + */ + public static class SimpleType extends Type { + public SimpleType(String name) { + this.name = name; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitSimpleType(this, data); + } + + public boolean isPrimitiveType() { + return primitiveTypes.contains(name); + } + + // where + private static final Set primitiveTypes = new HashSet<>(Arrays.asList( + "boolean", "byte", "char", "double", "float", "int", "long", "short", "void")); + + @Override + public String toString() { + return name; + } + + public final String name; + } + + /** + * Represents an array type signature. + *

+ * See: + * JVMS 4.3.4 + * ArrayTypeSignature: + * {@code [} TypeSignature {@code ]} + */ + public static class ArrayType extends Type { + public ArrayType(Type elemType) { + this.elemType = elemType; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitArrayType(this, data); + } + + @Override + public String toString() { + return elemType + "[]"; + } + + public final Type elemType; + } + + /** + * Represents a method type signature. + *

+ * See; + * JVMS 4.3.4 + * MethodTypeSignature: + * FormalTypeParameters_opt {@code (} TypeSignature* {@code)} ReturnType + * ThrowsSignature* + */ + public static class MethodType extends Type { + public MethodType(List paramTypes, Type resultType) { + this(null, paramTypes, resultType, null); + } + + public MethodType(List typeParamTypes, + List paramTypes, + Type returnType, + List throwsTypes) { + this.typeParamTypes = typeParamTypes; + this.paramTypes = paramTypes; + this.returnType = returnType; + this.throwsTypes = throwsTypes; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitMethodType(this, data); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendIfNotEmpty(sb, "<", typeParamTypes, "> "); + sb.append(returnType); + append(sb, " (", paramTypes, ")"); + appendIfNotEmpty(sb, " throws ", throwsTypes, ""); + return sb.toString(); + } + + public final List typeParamTypes; + public final List paramTypes; + public final Type returnType; + public final List throwsTypes; + } + + /** + * Represents a class signature. These describe the signature of + * a class that has type arguments. + *

+ * See: + * JVMS 4.3.4 + * ClassSignature: + * FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature* + */ + public static class ClassSigType extends Type { + public ClassSigType(List typeParamTypes, Type superclassType, + List superinterfaceTypes) { + this.typeParamTypes = typeParamTypes; + this.superclassType = superclassType; + this.superinterfaceTypes = superinterfaceTypes; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitClassSigType(this, data); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendIfNotEmpty(sb, "<", typeParamTypes, ">"); + if (superclassType != null) { + sb.append(" extends "); + sb.append(superclassType); + } + appendIfNotEmpty(sb, " implements ", superinterfaceTypes, ""); + return sb.toString(); + } + + public final List typeParamTypes; + public final Type superclassType; + public final List superinterfaceTypes; + } + + /** + * Represents a class type signature. This is used to represent a + * reference to a class, such as in a field, parameter, return type, etc. + *

+ * See: + * JVMS 4.3.4 + * ClassTypeSignature: + * {@code L} PackageSpecifier_opt SimpleClassTypeSignature + * ClassTypeSignatureSuffix* {@code ;} + * PackageSpecifier: + * Identifier {@code /} PackageSpecifier* + * SimpleClassTypeSignature: + * Identifier TypeArguments_opt } + * ClassTypeSignatureSuffix: + * {@code .} SimpleClassTypeSignature + */ + public static class ClassType extends Type { + public ClassType(ClassType outerType, String name, List typeArgs) { + this.outerType = outerType; + this.name = name; + this.typeArgs = typeArgs; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitClassType(this, data); + } + + public String getBinaryName() { + if (outerType == null) + return name; + else + return (outerType.getBinaryName() + "$" + name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (outerType != null) { + sb.append(outerType); + sb.append("."); + } + sb.append(name); + appendIfNotEmpty(sb, "<", typeArgs, ">"); + return sb.toString(); + } + + @Override + public boolean isObject() { + return (outerType == null) + && name.equals("java/lang/Object") + && (typeArgs == null || typeArgs.isEmpty()); + } + + public final ClassType outerType; + public final String name; + public final List typeArgs; + } + + /** + * Represents a FormalTypeParameter. These are used to declare the type + * parameters for generic classes and methods. + *

+ * See: + * JVMS 4.3.4 + * FormalTypeParameters: + * {@code <} FormalTypeParameter+ {@code >} + * FormalTypeParameter: + * Identifier ClassBound InterfaceBound* + * ClassBound: + * {@code :} FieldTypeSignature_opt + * InterfaceBound: + * {@code :} FieldTypeSignature + */ + public static class TypeParamType extends Type { + public TypeParamType(String name, Type classBound, List interfaceBounds) { + this.name = name; + this.classBound = classBound; + this.interfaceBounds = interfaceBounds; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitTypeParamType(this, data); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(name); + String sep = " extends "; + if (classBound != null) { + sb.append(sep); + sb.append(classBound); + sep = " & "; + } + if (interfaceBounds != null) { + for (Type bound : interfaceBounds) { + sb.append(sep); + sb.append(bound); + sep = " & "; + } + } + return sb.toString(); + } + + public final String name; + public final Type classBound; + public final List interfaceBounds; + } + + /** + * Represents a wildcard type argument. A type argument that is not a + * wildcard type argument will be represented by a ClassType, ArrayType, etc. + *

+ * See: + * JVMS 4.3.4 + * TypeArgument: + * WildcardIndicator_opt FieldTypeSignature + * {@code *} + * WildcardIndicator: + * {@code +} + * {@code -} + */ + public static class WildcardType extends Type { + public enum Kind {UNBOUNDED, EXTENDS, SUPER} + + public WildcardType() { + this(Kind.UNBOUNDED, null); + } + + public WildcardType(Kind kind, Type boundType) { + this.kind = kind; + this.boundType = boundType; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitWildcardType(this, data); + } + + @Override + public String toString() { + switch (kind) { + case UNBOUNDED: + return "?"; + case EXTENDS: + return "? extends " + boundType; + case SUPER: + return "? super " + boundType; + default: + throw new AssertionError(); + } + } + + public final Kind kind; + public final Type boundType; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/util/I18NResourceBundle.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/I18NResourceBundle.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/util/I18NResourceBundle.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/I18NResourceBundle.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.util; + +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * A class that lazily opens a package-specific resource bundle containing localization + * data for a class. + */ +public class I18NResourceBundle extends ResourceBundle { + + private boolean warn = true; + + /** + * Get a package-specific resource bundle for a class containing localization data. + * The bundle is named i18n.properties in the same package as the given class. + * + * @param c the class for which to obtain the resource bundle + * @return the appropriate resource bundle for the class + */ + public static I18NResourceBundle getBundleForClass(Class c) { + String cn = c.getName(); + int dot = cn.lastIndexOf('.'); + String rn = (dot == -1 ? "i18n" : cn.substring(0, dot) + ".i18n"); + return new I18NResourceBundle(rn, c.getClassLoader()); + } + + /** + * Create a resource bundle for the given name. The actual resource bundle will not be + * loaded until it is needed. + * + * @param name The name of the actual resource bundle to use. + */ + private I18NResourceBundle(String name, ClassLoader cl) { + this.name = name; + this.classLoader = cl; + } + +// /** +// * Get an entry from the resource bundle. If the resource cannot be found, a message +// * is printed to the console and the result will be a string containing the method +// * parameters. +// * +// * @param key the name of the entry to be returned +// * @param arg an argument to be formatted into the result using +// * {@link java.text.MessageFormat#format} +// * @return the formatted string +// */ +// public String getString(String key, Object arg) { +// return getString(key, new Object[]{arg}); +// } + + /** + * Get an entry from the resource bundle. If the resource cannot be found, a message + * is printed to the console and the result will be a string containing the method + * parameters. + * + * @param key the name of the entry to be returned + * @param args an array of arguments to be formatted into the result using + * {@link java.text.MessageFormat#format} + * @return the formatted string + */ + public String getString(String key, Object... args) { + try { + String resourceString = getString(key); + return MessageFormat.format(resourceString, args); + } catch (MissingResourceException mre) { + return null; + } catch(IllegalArgumentException iae) { + return iae.getMessage(); + } + } + + /** + * Get an entry from the bundle, returning null if it is not found. + * + * @param key the name of the entry to be returned + * @return the value of the entry, or null if it is not found. + */ + public String getOptionalString(String key) { + if (delegate == null) { + delegate = ResourceBundle.getBundle(name, Locale.getDefault(), classLoader); + } + try { + String s = (String) (delegate.getObject(key)); + if (s != null) { + System.out.println("i18n: " + key); + } + return s; + } catch (MissingResourceException e) { + return null; + } + } + + public void setWarn(boolean warn) { + this.warn = warn; + } + + /** + * A required internal method for ResourceBundle. Load the actual resource bundle, if + * it has not yet been loaded, then hand the request off to that bundle. If the + * resource cannot be found, a message is printed to the console and the result will + * be the original tag. + */ + protected Object handleGetObject(String key) throws MissingResourceException { + try { + if (delegate == null) { + delegate = ResourceBundle.getBundle(name, Locale.getDefault(), classLoader); + } + return delegate.getObject(key); + } catch (MissingResourceException e) { + if (warn) { + System.err.println("WARNING: resource: '" + key + "' not found in " + name); + } + return key; + } + } + + /** + * A required internal method for ResourceBundle. Load the actual resource bundle, if + * it has not yet been loaded, then hand the request off to that bundle. + */ + public Enumeration getKeys() { + if (delegate == null) { + delegate = ResourceBundle.getBundle(name); + } + return delegate.getKeys(); + } + + /** + * Returns the name of this bundle (useful for methods using bundle name instead of + * instance, such as Logger creation, + * + * @return the name of this resource bundle + */ + public String getName() { + return name; + } + + private String name; + private ResourceBundle delegate; + private ClassLoader classLoader; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/util/ProductInfo.java jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/ProductInfo.java --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/util/ProductInfo.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/ProductInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.util; + +import java.util.ResourceBundle; + +/** + * Class providing access to the product info. + * productinfo.properties will be generated during the build + */ +public class ProductInfo { + + static { + init(); + } + + /** + * Returns the value of the specified property + */ + public static String getProperty(String propName) { + try { + return bundle.getString(propName); + } catch (java.util.MissingResourceException e) { + return null; + } + } + + /** + * Version of the product in the short format, like 5.0 + */ + public static final String VERSION = version(); + + /** + * Full version of the product, including build number and date of creation + */ + public static final String FULL_VERSION = fullVersion(); + + private static final String BUNDLE_NAME = "org.openjdk.asmtools.util.productinfo"; + + private static ResourceBundle bundle; + + /** + * Initializes the bundle + */ + private static void init() { + bundle = ResourceBundle.getBundle(BUNDLE_NAME); + } + + private static String version() { + return getProperty("PRODUCT_VERSION"); + } + + private static String fullVersion() { + return getProperty("PRODUCT_NAME_LONG") + ", version " + version() + + " " + getProperty("PRODUCT_MILESTONE") + + " " + getProperty("PRODUCT_BUILDNUMBER") + + " (" + getProperty("PRODUCT_DATE") + ")"; + + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/util/productinfo.properties jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/productinfo.properties --- jtreg8-8.1+1+ds1/asmtools/src/org/openjdk/asmtools/util/productinfo.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/src/org/openjdk/asmtools/util/productinfo.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +# Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +PRODUCT_NAME = %%PRODUCT_NAME%% +PRODUCT_VERSION = %%PRODUCT_VERSION%% +PRODUCT_MILESTONE = %%PRODUCT_MILESTONE%% +PRODUCT_BUILDNUMBER = %%PRODUCT_BUILDNUMBER%% +PRODUCT_NAME_LONG = %%PRODUCT_NAME_LONG%% +PRODUCT_DATE = %%BUILD_DATE%% diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/BootstrapMethodsAttributeTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/BootstrapMethodsAttributeTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/BootstrapMethodsAttributeTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/BootstrapMethodsAttributeTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.BootstrapMethods; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.openjdk.asmtools.lib.action.EAsmTool; +import org.openjdk.asmtools.lib.action.EToolArguments; +import org.openjdk.asmtools.lib.action.Jdis; +import org.openjdk.asmtools.lib.attributes.Attribute; +import org.openjdk.asmtools.lib.ext.CaptureSystemOutput; +import org.openjdk.asmtools.lib.log.LogAndReturn; + +import java.io.IOException; +import java.util.stream.Stream; + +import static org.hamcrest.Matchers.containsString; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.OUTPUT; + +public class BootstrapMethodsAttributeTests { + + private static Jdis jdis = new Jdis(); + + @ParameterizedTest + @ArgumentsSource(BootstrapMethodsAttributeProvider.class) + @CaptureSystemOutput(value = OUTPUT, mute = true) + void testOutput(Attribute data, CaptureSystemOutput.OutputCapture outputCapture) throws IOException { + outputCapture.expect(containsString(data.getClassName())); + int rc = data.run(); + Assertions.assertEquals(data.getExpectedRc(), rc); + for (EToolArguments args : EToolArguments.ofTool(EAsmTool.JDIS)) { + String fname = data.getSimpleClassName() + args.getPostfix(); + LogAndReturn res = jdis.setArgs(args).decode(data.getContent()); + } + } + + @BeforeAll + public static void setUp() throws IOException { + jdis.setDestDir().setDebug(false); + } + + @AfterAll + public static void tearDown() throws IOException { + } +} + +class BootstrapMethodsAttributeProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext context) { + String packageName = BootstrapMethodsAttributeTests.class.getPackage().getName(); + return Stream.of( + Arguments.of(new Attribute(Attribute.Kind.CLASS_MAIN, packageName.concat(".data.BootstrapExample01"), 1)), + Arguments.of(new Attribute(Attribute.Kind.CLASS_MAIN, packageName.concat(".data.BootstrapExample02"), 4)) + ); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/Case7903791.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/Case7903791.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/Case7903791.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/Case7903791.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.BootstrapMethods; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.core.AllOf.allOf; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcNormalizeText; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Case7903791 { + + private Jasm jasm = new Jasm(); + private Jcoder jcoder = new Jcoder(); + private File resourceDir; + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("BSMCase7903791.jasm", EToolArguments.JDIS_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + containsString("_:\"()Ljava/lang/String;\"{}"), + containsString("I:\"Ljava/lang/Class;\"{},") + )), + (Consumer) (text) -> + Assertions.assertEquals(3, funcSubStrCount.apply(text, "{}")), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "{ }")) + ) + ), + Arguments.of("BSMCase7903791.g.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + containsString("_:\"()Ljava/lang/String;\"{}"), + containsString("I:\"Ljava/lang/Class;\"{},") + )), + (Consumer) (text) -> + Assertions.assertEquals(1, funcSubStrCount.apply(text, "Arguments")), + (Consumer) (text) -> + Assertions.assertEquals(3, funcSubStrCount.apply(text, "{}")), + (Consumer) (text) -> + Assertions.assertEquals(0, funcSubStrCount.apply(text, "{ }")) + ) + ), + Arguments.of("BSMCase7903791.g.t.jasm", EToolArguments.JDIS, List.of( + (Consumer) (text) -> assertThat(text, allOf( + containsString("_:\"()Ljava/lang/String;\"{}"), + containsString("I:\"Ljava/lang/Class;\"{},") + )), + (Consumer) (text) -> + Assertions.assertEquals(3, funcSubStrCount.apply(text, "{}")), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "{ }")) + ) + ) + ); + } + + private static Stream getJcodParameters() { + return Stream.of( + Arguments.of("BSMCase7903791.g.jcod", EToolArguments.JDEC_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + containsString("[3] { // bootstrap_methods"), + containsString("[4] { // bootstrap_arguments") + )), + (Consumer) (text) -> + Assertions.assertEquals(1, funcSubStrCount.apply(text, "[4] { // bootstrap_arguments")), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "[0] { // bootstrap_arguments")) + ) + ) + ); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(Objects.requireNonNull(this.getClass(). + getResource("BSMCase7903791.jasm")).getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getJasmParameters") + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + // jasm to class in memory + // jasm.setDebug(true); + LogAndBinResults binResult = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertTrue(binResult.log.toString().isEmpty()); + Assertions.assertEquals(0, binResult.result); + + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + + Assertions.assertEquals(0, textResult.result); + String jasmText = textResult.getResultAsString(Function.identity()); + String normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // jasm to class + binResult = jasm.compile(new StringInput(jasmText)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jasm + textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + jasmText = textResult.getResultAsString(Function.identity()); + normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // class to jcod + textResult = new Jdec().setArgs(EToolArguments.JDEC_G).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + // jcod to class + binResult = jcoder.compile(new StringInput(textResult.getResultAsString(Function.identity()))); + Assertions.assertEquals(0, binResult.result); + } + + @ParameterizedTest + @MethodSource("getJcodParameters") + public void jcoderTest(String resourceName, EToolArguments args, List> tests) { + // jcod to class in memory + LogAndBinResults binResult = jcoder.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jcod + LogAndTextResults textResult = new Jdec().setArgs(args).decode(binResult.getAsByteInput()); + String jcoderText = textResult.getResultAsString(funcNormalizeText); + Assertions.assertEquals(0, textResult.result); + for (Consumer testConsumer : tests) { + testConsumer.accept(jcoderText); + } + // class to jasm twice + textResult = new Jdis().setArgs(EToolArguments.JDIS_G_T_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + textResult = new Jdis().setArgs(EToolArguments.JDIS_GG_NC_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample01.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample01.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample01.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample01.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.BootstrapMethods.data; + +import java.lang.invoke.*; + +public class BootstrapExample01 { + + public static int main(String[] args) throws Throwable { + // Dynamically resolve and invoke a method + MethodHandle dynamicHandle = getDynamicInvoker(); + // Expected multiline output: + // Bootstrap method called with: + // Lookup: BootstrapExample01 + // Method Name: dynamicInvoke + // Method Type: (String)void + // Target method called with message: Hello, BootstrapExample01! + dynamicHandle.invokeExact("Hello, BootstrapExample01!"); + return 1; + } + + // Bootstrap method - this defines the linkage for invokedynamic + public static CallSite bootstrap(MethodHandles.Lookup lookup, String methodName, MethodType methodType) throws Throwable { + System.out.println("Bootstrap method called with:"); + System.out.println("Lookup: " + lookup); + System.out.println("Method Name: " + methodName); + System.out.println("Method Type: " + methodType); + + // Resolve the target method (example: static method in this class) + MethodHandle targetHandle = lookup.findStatic(BootstrapExample01.class, "targetMethod", methodType); + return new ConstantCallSite(targetHandle); + } + + // Target method to be invoked dynamically + public static void targetMethod(String message) { + System.out.println("Target method called with message: " + message); + } + + // Invokedynamic simulation for demonstration + public static MethodHandle getDynamicInvoker() throws Throwable { + MethodType bootstrapMethodType = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); + MethodHandle bootstrapHandle = MethodHandles.lookup().findStatic(BootstrapExample01.class, "bootstrap", bootstrapMethodType); + + // Define the signature of the invokedynamic target + MethodType targetMethodType = MethodType.methodType(void.class, String.class); + CallSite callSite = (CallSite) bootstrapHandle.invoke(MethodHandles.lookup(), "dynamicInvoke", targetMethodType); + return callSite.dynamicInvoker(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample02.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample02.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample02.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/BootstrapMethods/data/BootstrapExample02.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.BootstrapMethods.data; + +import java.util.function.Function; + +public class BootstrapExample02 { + public static int main(String[] args) { + Function string = s -> " = 2 x " + s; + Function square = i -> (int) Math.pow(i, 2); + + Integer result = square.apply(2); + String message = string.apply("2"); + // expected: 4 = 2 x 2 + System.out.println("%s %s%s".formatted(BootstrapExample02.class.getName(), result, message)); + return result; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/ConstantValue/ConstantValueAttributeTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/ConstantValue/ConstantValueAttributeTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/ConstantValue/ConstantValueAttributeTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/ConstantValue/ConstantValueAttributeTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.ConstantValue; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.openjdk.asmtools.lib.action.Jcoder; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.transform.ResultChecker; +import org.openjdk.asmtools.lib.transform.TransformLoader; +import org.openjdk.asmtools.lib.transform.pipeline.*; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +// TODO: The -g option should be added to JDIS. It will allow keeping incorrect references to CP, and after the JASM-to-class step, the class will be loaded with CFE. +public class ConstantValueAttributeTests extends ResultChecker { + private static final boolean DEBUG = false; + + private static final String PACKAGE_PREFIX = "javasoft.sqe.tests.vm.classfmt.atr"; + + @ParameterizedTest(name = "{0} - {2}") + @ArgumentsSource(ConstantValueAttributeJcodProvider_1.class) + void testClassJasmClassChaining(String jcodFileName, String fqClassName, + Class expectedException) throws IOException { + JcodToClassConverter inputConverter = new JcodToClassConverter(); + + // Define the pipeline + Pipeline pipeline = new Pipeline<>(inputConverter) + .addStage(new ClassToJasmConverter()) + .addStage(new JasmToClassConverter()) + .addStage(new ClassToJcodConverter()) + .addStage(new JcodToClassConverter()); + + Path jcodFilePath = Path.of(loadJcodFile(jcodFileName)); + Jcod jcodInput = new Jcod(new Pipeline.Status(jcodFilePath), true); + + // Execute the pipeline + Clazz finalOutput = pipeline.execute(jcodInput); + + byte[] classBytes = finalOutput.record().byteOutput().getOutputs().get(0).getBody(); + + // Step 3: Load the transformed class + TransformLoader transformLoader = new TransformLoader(ConstantValueAttributeTests.class.getClassLoader()) + .setTransformFilter(className -> className.contains(PACKAGE_PREFIX)); + + if (expectedException == null) { + // Positive scenario: Class file should load successfully + Optional loadedClass = Optional.empty(); + try { + loadedClass = transformLoader.loadClassFromBuffer( + PACKAGE_PREFIX.concat(".").concat(fqClassName), classBytes, false + ); + } catch (Exception e) { + fail(e); + } + assertTrue(loadedClass.isPresent(), "Class loading failed: No object returned."); + assertEquals(Class.class, loadedClass.get().getClass(), "Loaded object is not a Class."); + } else { + // Negative scenario: Class file fails to load and throws an expected exception + assertThrows(expectedException, + () -> transformLoader.loadClassFromBuffer( + PACKAGE_PREFIX.concat(".").concat(fqClassName), classBytes, false) + + ); + } + } + + /** + * The test tries to use 'jdis' tool to compile jasm file that is illegal in content. Generation should fail. + *
    + *
  • Setup: Locate the JCod file. Resolves the jcod file path stored in the test repository and compile this using 'jcoder' tool
  • + *
  • Step 1: Generate (Class -> Jasm). Generate jasm file from the class file 'jdis' tool
  • + *
      + *
    • Positive scenario: None
    • + *
    • Negative scenario: 'jdis' operation fails with Fatal error in file
    • + *
    + *
+ * + * @param jcodFileName - jcod File in the test resources repository + * @throws IOException - Thrown from the GeneratorAction, CompileAction and temporary file operations. + */ + @ParameterizedTest(name = "{0}") + @ArgumentsSource(ProviderForToolError_1.class) + void testJdisError_InvalidAttrLength_01(String jcodFileName) throws IOException { + final String expectedStageToFail = "classToJasm2"; + var jcodToClass = new JcodToClassConverter("jcodToClass1"); + var classToJasmFails = new ClassToJasmConverter(expectedStageToFail); //Failure is expected here + var jasmToClass = new JasmToClassConverter("jasmToClass3"); + var classToJcod = new ClassToJcodConverter("classToJcod4"); + // Define the pipeline + Pipeline pipeline = new Pipeline<>(jcodToClass) + .addStage(classToJasmFails) + .addStage(jasmToClass) + .addStage(classToJcod); + + Path jcodFilePath = Path.of(loadJcodFile(jcodFileName)); + Jcod jcodInput = new Jcod(new Pipeline.Status(jcodFilePath), true); + + // Execute the pipeline + Jcod finalOutput = pipeline.execute(jcodInput); + + // Step 1.1: Verify jdis output + assertThat(classToJasmFails.record().log().toString(), Matchers.allOf( + Matchers.containsString("jdis - ERROR: ATT_ConstantValue: Invalid attribute length #4"), + Matchers.containsString("1 error(s) in the file: bytes/bytes") + ) + ); + + assertThat(finalOutput.record().log().toString(), Matchers.allOf( + Matchers.containsString("jdis - ERROR: ATT_ConstantValue: Invalid attribute length #4"), + Matchers.containsString("1 error(s) in the file: bytes/bytes") + ) + ); + } + + @Test + //The field_info structure contains two ConstantValue attributes in the attributes table. + void testClassJasmClassChainingX() throws IOException { + String jcodFileName = "atrcvl00301m1n.jcod"; + String fqClassName = "atrcvl003.atrcvl00301m1.atrcvl00301m1n"; + + JcodToClassConverter inputConverter = new JcodToClassConverter(); + ClassToJasmConverter warningConverter = new ClassToJasmConverter(); + JasmToClassConverter xx = new JasmToClassConverter(); + // Define the pipeline + Pipeline pipeline = new Pipeline<>(inputConverter) + .addStage(warningConverter) + .addStage(new JasmToClassConverter()) + .addStage(new ClassToJcodConverter()) + .addStage(new JcodToClassConverter()); + + Path jcodFilePath = Path.of(loadJcodFile(jcodFileName)); + Jcod jcodInput = new Jcod(new Pipeline.Status(jcodFilePath), true); + + // Execute the pipeline + Clazz finalOutput = pipeline.execute(jcodInput); + byte[] classBytes = finalOutput.record().byteOutput().getOutputs().get(0).getBody(); + + assertThat(warningConverter.record().log().toString(), Matchers.allOf( + Matchers.containsString("WARN: There is more than one \"ATT_ConstantValue\" " + + "attribute in the attributes table of a \"field_info\" structure. " + + "The last one is used") + ) + ); + + // Step 3: Load the transformed class + TransformLoader transformLoader = new TransformLoader(ConstantValueAttributeTests.class.getClassLoader()) + .setTransformFilter(className -> className.contains(PACKAGE_PREFIX)); + + Optional loadedClass = Optional.empty(); + try { + loadedClass = transformLoader.loadClassFromBuffer( + PACKAGE_PREFIX.concat(".").concat(fqClassName), classBytes, false + ); + } catch (Exception e) { + fail(e); + } + assertTrue(loadedClass.isPresent(), "Class loading failed: No object returned."); + assertEquals(Class.class, loadedClass.get().getClass(), "Loaded object is not a Class."); + } + + /** + * Locate the JCod file. Resolves the jcod file path stored in the test repository and compile this using 'jcoder' tool + * + * @param jcodFileName jcod File in the test resources repository + * @return Output of the CompileAction + * @throws IOException CompileAction fails + */ + private LogAndBinResults produceClassInputFromJcod(String jcodFileName) throws IOException { + // Step 1: Locate the JCod file + String jcodFilePath = loadJcodFile(jcodFileName); + + // Step 1.1: Compile JCod -> Class + LogAndBinResults compileResult = new Jcoder().compile(List.of(jcodFilePath)); + println("Compile JCod to Class", compileResult.log.toString()); + return compileResult; + } + + /** + * Loads a JCOD file from the resources' directory. + * + * @param jcodFileName The name of the JCOD file. + * @return The JCOD file content as a byte array. + */ + private String loadJcodFile(String jcodFileName) { + String resourceName = String.format("/jcod-files/%s", jcodFileName); + File resourceDir = new File(Objects.requireNonNull(this.getClass().getResource(resourceName)).getFile()).getParentFile(); + return resourceDir + File.separator + jcodFileName; + } + + /** + * Writes the given byte array to a temporary file with the specified file name and extension. + * + * @param fileName The prefix for the temporary file name. + * @param ext The suffix (extension) for the temporary file. + * @param buffer The byte array to write to the file. + * @return The path to the created temporary file. + * @throws IOException If an I/O error occurs. + * @throws NullPointerException If any of the arguments are null. + */ + public static Path writeBytesToFile(String fileName, String ext, byte[] buffer) throws IOException { + // Validate input parameters + Objects.requireNonNull(fileName, "File name must not be null"); + Objects.requireNonNull(ext, "File extension must not be null"); + Objects.requireNonNull(buffer, "Buffer must not be null"); + + // Create a temporary file with the given prefix and suffix + Path tempFile = Files.createTempFile(fileName, ext); + + // Write the byte array to the file + Files.write(tempFile, buffer, StandardOpenOption.WRITE); + + return tempFile; + } + + /** + * Provides test arguments for the parameterized test. + */ + static class ConstantValueAttributeJcodProvider_1 implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + Arguments.of("atrcvl00101m10p.jcod", "atrcvl001.atrcvl00101m1.atrcvl00101m10p", null), + Arguments.of("atrcvl00101m1t0p.jcod", "atrcvl001.atrcvl00101m1t.atrcvl00101m1t0p", null), + Arguments.of("atrcvl00102m10p.jcod", "atrcvl001.atrcvl00102m1.atrcvl00102m10p", null), + Arguments.of("atrcvl00102m1t0p.jcod", "atrcvl001.atrcvl00102m1t.atrcvl00102m1t0p", null), + // The field_info structure contains two ConstantValue attributes in the attributes table. + //TODO: Warning is thrown (not error) + Arguments.of("atrcvl00301m1n.jcod", "atrcvl003.atrcvl00301m1.atrcvl00301m1n", null), + Arguments.of("atrcvl00301m1p.jcod", "atrcvl003.atrcvl00301m1.atrcvl00301m1p", null), + // TODO: Need a way to compile a .java file for p to access n file + // Arguments.of("atrcvl00401m1p.jcod", "atrcvl004.atrcvl00401m1.atrcvl00401m1p", null), + // The value of the attribute_name_index item is equal to zero. + //TODO: Warning is thrown (not error) + Arguments.of("atrcvl00501m1n.jcod", "atrcvl005.atrcvl00501m1.atrcvl00501m1n", null), + Arguments.of("atrcvl00501m1p.jcod", "atrcvl005.atrcvl00501m1.atrcvl00501m1p", null), + // The value of the attribute_name_index item is equal to constant_pool_length. + //TODO: Warning is thrown (not error) + Arguments.of("atrcvl00502m1n.jcod", "atrcvl005.atrcvl00502m1.atrcvl00502m1n", null), + Arguments.of("atrcvl00502m1p.jcod", "atrcvl005.atrcvl00502m1.atrcvl00502m1p", null), + // The constant_pool entry at the attribute_name_index is not a CONSTANT_Utf8_info structure. + //TODO: Warning is thrown (not error) + Arguments.of("atrcvl00601m1n.jcod", "atrcvl006.atrcvl00601m1.atrcvl00601m1n", null), + Arguments.of("atrcvl00601m1p.jcod", "atrcvl006.atrcvl00601m1.atrcvl00601m1p", null), + Arguments.of("atrcvl00701m10p.jcod", "atrcvl007.atrcvl00701m1.atrcvl00701m10p", null), + Arguments.of("atrcvl00702m10p.jcod", "atrcvl007.atrcvl00702m1.atrcvl00702m10p", null), + Arguments.of("atrcvl00702m11p.jcod", "atrcvl007.atrcvl00702m1.atrcvl00702m11p", null), + //TODO: Warning is thrown (not error) + Arguments.of("atrcvl00801m1n.jcod", "atrcvl008.atrcvl00801m1.atrcvl00801m1n", ClassFormatError.class), + Arguments.of("atrcvl00801m1p.jcod", "atrcvl008.atrcvl00801m1.atrcvl00801m1p", null), + Arguments.of("atrcvl00802m1n.jcod", "atrcvl008.atrcvl00802m1.atrcvl00802m1n", ClassFormatError.class), + Arguments.of("atrcvl00802m1p.jcod", "atrcvl008.atrcvl00802m1.atrcvl00802m1p", null), + Arguments.of("atrcvl00901m1n.jcod", "atrcvl009.atrcvl00901m1.atrcvl00901m1n", ClassFormatError.class), + Arguments.of("atrcvl00901m1p.jcod", "atrcvl009.atrcvl00901m1.atrcvl00901m1p", null), + Arguments.of("atrcvl00902m1n.jcod", "atrcvl009.atrcvl00902m1.atrcvl00902m1n", ClassFormatError.class), + Arguments.of("atrcvl00902m1p.jcod", "atrcvl009.atrcvl00902m1.atrcvl00902m1p", null), + Arguments.of("atrcvl00903m1n.jcod", "atrcvl009.atrcvl00903m1.atrcvl00903m1n", ClassFormatError.class), + Arguments.of("atrcvl00903m1p.jcod", "atrcvl009.atrcvl00903m1.atrcvl00903m1p", null), + Arguments.of("atrcvl00904m1n.jcod", "atrcvl009.atrcvl00904m1.atrcvl00904m1n", ClassFormatError.class), + Arguments.of("atrcvl00904m1p.jcod", "atrcvl009.atrcvl00904m1.atrcvl00904m1p", null), + Arguments.of("atrcvl00905m1n.jcod", "atrcvl009.atrcvl00905m1.atrcvl00905m1n", ClassFormatError.class), + Arguments.of("atrcvl00905m1p.jcod", "atrcvl009.atrcvl00905m1.atrcvl00905m1p", null), + Arguments.of("atrcvl00906m1n.jcod", "atrcvl009.atrcvl00906m1.atrcvl00906m1n", ClassFormatError.class), + Arguments.of("atrcvl00906m1p.jcod", "atrcvl009.atrcvl00906m1.atrcvl00906m1p", null), + Arguments.of("atrcvl00907m1n.jcod", "atrcvl009.atrcvl00907m1.atrcvl00907m1n", ClassFormatError.class), + Arguments.of("atrcvl00907m1p.jcod", "atrcvl009.atrcvl00907m1.atrcvl00907m1p", null), + Arguments.of("atrcvl00908m1n.jcod", "atrcvl009.atrcvl00908m1.atrcvl00908m1n", ClassFormatError.class), + Arguments.of("atrcvl00908m1p.jcod", "atrcvl009.atrcvl00908m1.atrcvl00908m1p", null), + Arguments.of("atrcvl00909m1n.jcod", "atrcvl009.atrcvl00909m1.atrcvl00909m1n", ClassFormatError.class), + Arguments.of("atrcvl00909m1p.jcod", "atrcvl009.atrcvl00909m1.atrcvl00909m1p", null), + Arguments.of("atrcvl01001m1n.jcod", "atrcvl010.atrcvl01001m1.atrcvl01001m1n", ClassFormatError.class), + Arguments.of("atrcvl01001m1p.jcod", "atrcvl010.atrcvl01001m1.atrcvl01001m1p", null), + Arguments.of("atrcvl01002m10p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m10p", null), + Arguments.of("atrcvl01002m110p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m110p", null), + Arguments.of("atrcvl01002m111n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m111n", ClassFormatError.class), + Arguments.of("atrcvl01002m112n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m112n", ClassFormatError.class), + Arguments.of("atrcvl01002m113n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m113n", ClassFormatError.class), + Arguments.of("atrcvl01002m114n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m114n", ClassFormatError.class), + Arguments.of("atrcvl01002m115p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m115p", null), + Arguments.of("atrcvl01002m116n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m116n", ClassFormatError.class), + Arguments.of("atrcvl01002m117n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m117n", ClassFormatError.class), + Arguments.of("atrcvl01002m118n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m118n", ClassFormatError.class), + Arguments.of("atrcvl01002m119n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m119n", ClassFormatError.class), + Arguments.of("atrcvl01002m11n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m11n", ClassFormatError.class), + Arguments.of("atrcvl01002m120p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m120p", null), + Arguments.of("atrcvl01002m121n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m121n", ClassFormatError.class), + Arguments.of("atrcvl01002m122n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m122n", ClassFormatError.class), + Arguments.of("atrcvl01002m123n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m123n", ClassFormatError.class), + Arguments.of("atrcvl01002m124n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m124n", ClassFormatError.class), + Arguments.of("atrcvl01002m125n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m125n", ClassFormatError.class), + Arguments.of("atrcvl01002m126n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m126n", ClassFormatError.class), + Arguments.of("atrcvl01002m127n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m127n", ClassFormatError.class), + Arguments.of("atrcvl01002m128n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m128n", ClassFormatError.class), + Arguments.of("atrcvl01002m129n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m129n", ClassFormatError.class), + Arguments.of("atrcvl01002m12n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m12n", ClassFormatError.class), + Arguments.of("atrcvl01002m130p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m130p", null), + Arguments.of("atrcvl01002m131n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m131n", ClassFormatError.class), + Arguments.of("atrcvl01002m132n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m132n", ClassFormatError.class), + Arguments.of("atrcvl01002m133n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m133n", ClassFormatError.class), + Arguments.of("atrcvl01002m134n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m134n", ClassFormatError.class), + Arguments.of("atrcvl01002m135n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m135n", ClassFormatError.class), + Arguments.of("atrcvl01002m136n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m136n", ClassFormatError.class), + Arguments.of("atrcvl01002m137n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m137n", ClassFormatError.class), + Arguments.of("atrcvl01002m138n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m138n", ClassFormatError.class), + Arguments.of("atrcvl01002m139n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m139n", ClassFormatError.class), + Arguments.of("atrcvl01002m13n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m13n", ClassFormatError.class), + Arguments.of("atrcvl01002m140p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m140p", null), + Arguments.of("atrcvl01002m141n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m141n", ClassFormatError.class), + Arguments.of("atrcvl01002m142n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m142n", ClassFormatError.class), + Arguments.of("atrcvl01002m143n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m143n", ClassFormatError.class), + Arguments.of("atrcvl01002m144n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m144n", ClassFormatError.class), + Arguments.of("atrcvl01002m145n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m145n", ClassFormatError.class), + Arguments.of("atrcvl01002m146n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m146n", ClassFormatError.class), + Arguments.of("atrcvl01002m147n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m147n", ClassFormatError.class), + Arguments.of("atrcvl01002m148n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m148n", ClassFormatError.class), + Arguments.of("atrcvl01002m149n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m149n", ClassFormatError.class), + Arguments.of("atrcvl01002m14n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m14n", ClassFormatError.class), + Arguments.of("atrcvl01002m150p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m150p", null), + Arguments.of("atrcvl01002m151n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m151n", ClassFormatError.class), + Arguments.of("atrcvl01002m152n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m152n", ClassFormatError.class), + Arguments.of("atrcvl01002m153n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m153n", ClassFormatError.class), + Arguments.of("atrcvl01002m154n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m154n", ClassFormatError.class), + Arguments.of("atrcvl01002m155n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m155n", ClassFormatError.class), + Arguments.of("atrcvl01002m156n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m156n", ClassFormatError.class), + Arguments.of("atrcvl01002m157n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m157n", ClassFormatError.class), + Arguments.of("atrcvl01002m158n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m158n", ClassFormatError.class), + Arguments.of("atrcvl01002m159n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m159n", ClassFormatError.class), + Arguments.of("atrcvl01002m15p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m15p", null), + Arguments.of("atrcvl01002m160p.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m160p", null), + Arguments.of("atrcvl01002m16n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m16n", ClassFormatError.class), + Arguments.of("atrcvl01002m17n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m17n", ClassFormatError.class), + Arguments.of("atrcvl01002m18n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m18n", ClassFormatError.class), + Arguments.of("atrcvl01002m19n.jcod", "atrcvl010.atrcvl01002m1.atrcvl01002m19n", ClassFormatError.class), + + Arguments.of("atrcod00101m1p.jcod", "atrcod001.atrcod00101m1.atrcod00101m1p", null), + // TODO: CFE not found + Arguments.of("atrcod00101m1n.jcod", "atrcod001.atrcod00101m1.atrcod00101m1n", null) + ); + } + } + + /** + * Provides test arguments for the parameterized test. + */ + static class ProviderForToolError_1 implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + // Instead of 2, length of the ConstantValue attribute is set to 4. + Arguments.of("atrcvl00701m11n.jcod", "atrcvl007.atrcvl00701m1.atrcvl00701m11n", null), + // Length of an attribute with a name like "ConstantValue" is set to 4. + Arguments.of("atrcvl00702m12n.jcod", "atrcvl007.atrcvl00702m1.atrcvl00702m12n", ClassFormatError.class) + ); + } + } + + /* + Debug logger + */ + private void println(String context, String text) { + if (DEBUG && text != null && !text.isEmpty()) + System.out.printf("[%s] %s%n", context, text); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.LoadableDescriptors; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.core.AllOf.allOf; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcNormalizeText; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class LoadableDescriptorsTests { + + private Jasm jasm = new Jasm(); + private Jcoder jcoder = new Jcoder(); + private File resourceDir; + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("Test01.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*const #\\d = Utf8 \"LLoadableDescriptors01;\";.*"), + matchesPattern(".*const #\\d = Utf8 \"LLoadableDescriptors02;\";.*"), + matchesPattern(".*LoadableDescriptors #\\d, #\\d; // \"LLoadableDescriptors01;\", \"LLoadableDescriptors02;\".*") + ) + ), + (Consumer) (text) -> + Assertions.assertEquals(10, funcSubStrCount.apply(text, "LoadableDescriptors")) + ) + ), + Arguments.of("LoadableDescriptorsAttributeTest$X.jasm", EToolArguments.JDIS, List.of( + (Consumer) (text) -> + Assertions.assertEquals(1, funcSubStrCount.apply(text, "LoadableDescriptors ")), + (Consumer) (text) -> + Assertions.assertEquals(3, funcSubStrCount.apply(text, "strict ")) + ) + ), + Arguments.of("LoadableDescriptorsAttributeTest$X.g.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> + Assertions.assertEquals(1, funcSubStrCount.apply(text, "LoadableDescriptors ")), + (Consumer) (text) -> + Assertions.assertEquals(3, funcSubStrCount.apply(text, "strict ")) + ) + ), + Arguments.of("LoadableDescriptorsAttributeTest$X.g.t.jasm", EToolArguments.JDIS_G, List.of( + (Consumer) (text) -> + Assertions.assertEquals(1, funcSubStrCount.apply(text, "LoadableDescriptors ")), + (Consumer) (text) -> + Assertions.assertEquals(3, funcSubStrCount.apply(text, "strict ")) + ) + ) + ); + } + + private static Stream getJcodParameters() { + return Stream.of( + Arguments.of("LoadableDescriptorsAttributeTest$X.jcod", EToolArguments.JDEC_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*Attr\\(#\\d\\d, \\d\\) \\{ // LoadableDescriptors at.*"), + matchesPattern(".*descriptor: LLoadableDescriptorsAttributeTest\\$V3.*"), + matchesPattern(".*descriptor: LLoadableDescriptorsAttributeTest\\$V7.*"), + matchesPattern(".*descriptor: LLoadableDescriptorsAttributeTest\\$V2.*") + ) + )) + ), + Arguments.of("LoadableDescriptorsAttributeTest$X.g.jcod", EToolArguments.JDEC, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*Attr\\(#\\d\\d\\) \\{ // LoadableDescriptors.*"))), + (Consumer) (text) -> + Assertions.assertEquals(26, funcSubStrCount.apply(text, "LoadableDescriptors")) + ) + ) + ); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(Objects.requireNonNull(this.getClass(). + getResource("Test01.jasm")).getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getJasmParameters") + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + // jasm to class in memory + // jasm.setDebug(true); + LogAndBinResults binResult = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertTrue(binResult.log.toString().isEmpty()); + Assertions.assertEquals(0, binResult.result); + + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + + Assertions.assertEquals(0, textResult.result); + String jasmText = textResult.getResultAsString(Function.identity()); + String normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // jasm to class + binResult = jasm.compile(new StringInput(jasmText)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jasm + textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + jasmText = textResult.getResultAsString(Function.identity()); + normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // class to jcod + textResult = new Jdec().setArgs(EToolArguments.JDEC_G).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + // jcod to class + binResult = jcoder.compile(new StringInput(textResult.getResultAsString(Function.identity()))); + Assertions.assertEquals(0, binResult.result); + } + + @ParameterizedTest + @MethodSource("getJcodParameters") + public void jcoderTest(String resourceName, EToolArguments args, List> tests) { + // jcod to class in memory + LogAndBinResults binResult = jcoder.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jcod + LogAndTextResults textResult = new Jdec().setArgs(args).decode(binResult.getAsByteInput()); + String jcoderText = textResult.getResultAsString(funcNormalizeText); + Assertions.assertEquals(0, textResult.result); + for (Consumer testConsumer : tests) { + testConsumer.accept(jcoderText); + } + // class to jasm twice + textResult = new Jdis().setArgs(EToolArguments.JDIS_G_T_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + textResult = new Jdis().setArgs(EToolArguments.JDIS_GG_NC_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestHost/NestHostTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestHost/NestHostTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestHost/NestHostTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestHost/NestHostTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.NestHost; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; +import org.openjdk.asmtools.lib.script.TestScript; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.core.AllOf.allOf; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcNormalizeText; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class NestHostTests extends TestScript { + + private Jasm jasm = new Jasm(); + private Jcoder jcoder = new Jcoder(); + private File resourceDir; + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("Test01.jasm", EToolArguments.JDIS_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*const #\\d = class #\\d; // NestHost01.*"), + matchesPattern(".*NestHost #\\d; // org/openjdk/asmtools/attribute/NestHost/NestHost01.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(11, funcSubStrCount.apply(text, "NestHost")) + ) + ), + Arguments.of("Test01.jasm", EToolArguments.JDIS, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*NestHost org/openjdk/asmtools/attribute/NestHost/NestHost01;.*") + )) + ) + ), + Arguments.of("Test01.g.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*const #\\d = Class #\\d; // NestHost01.*"), + matchesPattern(".*NestHost #\\d; // org/openjdk/asmtools/attribute/NestHost/NestHost01.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(11, funcSubStrCount.apply(text, "NestHost")) + ) + ), + Arguments.of("Test02.jasm", EToolArguments.JDIS_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*const #\\d = class #\\d; // NestHost02.*"), + matchesPattern(".*NestHost #\\d; // org/openjdk/asmtools/attribute/NestHost/NestHost02.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(11, funcSubStrCount.apply(text, "NestHost")) + ) + ), + Arguments.of("Test02.jasm", EToolArguments.JDIS, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*NestHost org/openjdk/asmtools/attribute/NestHost/NestHost02;.*") + )) + ) + ) + ); + } + + private static Stream getJcodParameters() { + return Stream.of( + Arguments.of("Test01.jcod", EToolArguments.JDEC_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*#\\d; // class: org/openjdk/asmtools/attribute/NestHost/NestHost01.*"), + matchesPattern(".*Attr.#\\d, 2. \\{ // NestHost.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(11, funcSubStrCount.apply(text, "NestHost")) + ) + ) + ); + } + + @BeforeAll + public void init() throws IOException { + // initialize resource directory + super.init("Test01.jasm"); + } + + @ParameterizedTest + @MethodSource("getJasmParameters") + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + super.jasmTest(resourceName, args, tests); + } + + @ParameterizedTest + @MethodSource("getJcodParameters") + public void jcoderTest(String resourceName, EToolArguments args, List> tests) { + super.jcoderTest(resourceName, args, tests); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestMembers/NestMembersTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestMembers/NestMembersTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestMembers/NestMembersTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/NestMembers/NestMembersTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.NestMembers; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.core.AllOf.allOf; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcNormalizeText; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class NestMembersTests { + + private Jasm jasm = new Jasm(); + private Jcoder jcoder = new Jcoder(); + private File resourceDir; + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("Test01.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*const #\\d = Class #\\d; // NestMember01.*"), + matchesPattern(".*NestMembers #\\d; // NestMember01.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(6, funcSubStrCount.apply(text, "NestMembers")) + ) + ), + Arguments.of("Test01.g.t.jasm", EToolArguments.JDIS, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*NestMembers NestMember01.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(6, funcSubStrCount.apply(text, "NestMember")) + ) + ), + Arguments.of("Test02.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*NestMembers #\\d\\d, // Test02\\$ClassInsideRecord2.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "NestMembers")) + ) + ) + ); + } + + private static Stream getJcodParameters() { + return Stream.of( + Arguments.of("Test01.jcod", EToolArguments.JDEC_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*#\\d; // class: org/openjdk/asmtools/attribute/NestMembers/Test01/NestMember01 at.*"), + matchesPattern(".*Attr.#\\d, 4. \\{ // NestMembers.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(8, funcSubStrCount.apply(text, "NestMembers")) + ) + ) + ); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(Objects.requireNonNull(this.getClass().getResource("Test01.jasm")).getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getJasmParameters") + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + // jasm to class in memory + // jasm.setDebug(true); + LogAndBinResults binResult = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertTrue(binResult.log.toString().isEmpty()); + Assertions.assertEquals(0, binResult.result); + + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + + Assertions.assertEquals(0, textResult.result); + String jasmText = textResult.getResultAsString(Function.identity()); + String normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // jasm to class + binResult = jasm.compile(new StringInput(jasmText)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jasm + textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + jasmText = textResult.getResultAsString(Function.identity()); + normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // class to jcod + textResult = new Jdec().setArgs(EToolArguments.JDEC_G).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + // jcod to class + binResult = jcoder.compile(new StringInput(textResult.getResultAsString(Function.identity()))); + Assertions.assertEquals(0, binResult.result); + } + + @ParameterizedTest + @MethodSource("getJcodParameters") + public void jcoderTest(String resourceName, EToolArguments args, List> tests) { + // jcod to class in memory + LogAndBinResults binResult = jcoder.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jcod + LogAndTextResults textResult = new Jdec().setArgs(args).decode(binResult.getAsByteInput()); + String jcoderText = textResult.getResultAsString(funcNormalizeText); + Assertions.assertEquals(0, textResult.result); + for (Consumer testConsumer : tests) { + testConsumer.accept(jcoderText); + } + // class to jasm twice + textResult = new Jdis().setArgs(EToolArguments.JDIS_G_T_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + textResult = new Jdis().setArgs(EToolArguments.JDIS_GG_NC_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/PermittedSubclasses/PermittedSubclassesTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/PermittedSubclasses/PermittedSubclassesTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/PermittedSubclasses/PermittedSubclassesTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/PermittedSubclasses/PermittedSubclassesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.PermittedSubclasses; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.core.AllOf.allOf; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcNormalizeText; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class PermittedSubclassesTests { + + private Jasm jasm = new Jasm(); + private Jcoder jcoder = new Jcoder(); + private File resourceDir; + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("Test01.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // SubClass01.*"), + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // SubClass02.*"), + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // SubClass03.*"), + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // SubClass04.*"), + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // NestMember01.*"), + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // NestMember02.*"), + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // NestMember03.*"), + matchesPattern(".*const #\\d\\d = Class #\\d\\d; // NestMember04.*"), + matchesPattern(".*NestMembers #\\d\\d, // NestMember0\\d.*"), + matchesPattern(".*PermittedSubclasses #\\d\\d, // SubClass0\\d.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "NestMembers")), + (Consumer) (text) -> + Assertions.assertEquals(5, funcSubStrCount.apply(text, "PermittedSubclasses")) + ) + ), + Arguments.of("Test01.g.t.jasm", EToolArguments.JDIS, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*NestMembers NestMember0\\d,.*"), + matchesPattern(".*PermittedSubclasses SubClass0\\d,.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(12, funcSubStrCount.apply(text, "NestMember0")), + (Consumer) (text) -> + Assertions.assertEquals(4, funcSubStrCount.apply(text, "SubClass0")) + ) + ), + Arguments.of("Test02.jasm", EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*PermittedSubclasses #\\d\\d, // Test02\\$ClassInsideRecord2.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "PermittedSubclasses")) + ) + ) + ); + } + + private static Stream getJcodParameters() { + return Stream.of( + Arguments.of("Test01.jcod", EToolArguments.JDEC_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + matchesPattern(".*#\\d\\d; // subclass: org/openjdk/asmtools/attribute/PermittedSubclasses/atr/SubClass01 at.*"), + matchesPattern(".*Attr\\(#\\d\\d, \\d\\) \\{ // PermittedSubclasses at.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(8, funcSubStrCount.apply(text, "PermittedSubclasses")) + ) + ) + ); + } + @BeforeAll + public void init() throws IOException { + resourceDir = new File(Objects.requireNonNull(this.getClass().getResource("Test01.jasm")).getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getJasmParameters") + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + // jasm to class in memory + // jasm.setDebug(true); + LogAndBinResults binResult = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertTrue(binResult.log.toString().isEmpty()); + Assertions.assertEquals(0, binResult.result); + + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + + Assertions.assertEquals(0, textResult.result); + String jasmText = textResult.getResultAsString(Function.identity()); + String normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // jasm to class + binResult = jasm.compile(new StringInput(jasmText)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jasm + textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + jasmText = textResult.getResultAsString(Function.identity()); + normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // class to jcod + textResult = new Jdec().setArgs(EToolArguments.JDEC_G).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + // jcod to class + binResult = jcoder.compile(new StringInput(textResult.getResultAsString(Function.identity()))); + Assertions.assertEquals(0, binResult.result); + } + + @ParameterizedTest + @MethodSource("getJcodParameters") + public void jcoderTest(String resourceName, EToolArguments args, List> tests) { + // jcod to class in memory + LogAndBinResults binResult = jcoder.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jcod + LogAndTextResults textResult = new Jdec().setArgs(args).decode(binResult.getAsByteInput()); + String jcoderText = textResult.getResultAsString(funcNormalizeText); + Assertions.assertEquals(0, textResult.result); + for (Consumer testConsumer : tests) { + testConsumer.accept(jcoderText); + } + // class to jasm twice + textResult = new Jdis().setArgs(EToolArguments.JDIS_G_T_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + textResult = new Jdis().setArgs(EToolArguments.JDIS_GG_NC_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExtensionTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExtensionTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExtensionTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExtensionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.SourceDebugExtension; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.lib.action.EToolArguments; +import org.openjdk.asmtools.lib.script.TestScript; + +import java.io.IOException; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.core.AllOf.allOf; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class SourceDebugExtensionTests extends TestScript { + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("SourceDebugExt01.jasm", + EToolArguments.JDIS_G, List.of( + (Consumer) (text) -> assertThat(text, allOf( + containsString("\"SMAP\\nSourceDebugExt01.java\\nJava\\n*S Java\\n*F\\n+ 1 SourceDebugExt01.java\\n\";"), + containsString("\"SourceDebugExt01.java\\n*L\\n1#1,5:1\\n*E\";"), + matchesPattern(".*const #\\d\\d = Utf8 \"SourceDebugExtension\";.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "SourceDebugExtension")) + ) + ), + Arguments.of("SourceDebugExt02.jasm", + EToolArguments.JDIS_G_T, List.of( + (Consumer) (text) -> assertThat(text, allOf( + containsString("SourceDebugExtension { }"), + matchesPattern(".*const #\\d\\d = Utf8 \"SourceDebugExtension\";.*") + )), + (Consumer) (text) -> + Assertions.assertEquals(2, funcSubStrCount.apply(text, "SourceDebugExtension")) + ) + ), + Arguments.of("SourceDebugExt03.jasm", + EToolArguments.JDIS, List.of( + (Consumer) (text) -> assertThat(text, allOf( + containsString("SourceDebugExtension { 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x00 0x0B 0x0C; 0x0D 0x0E 0x0F; }") + )), + (Consumer) (text) -> + Assertions.assertEquals(1, funcSubStrCount.apply(text, "SourceDebugExtension")) + ) + ) + ); + } + + @BeforeAll + public void init() throws IOException { + // initialize resource directory + super.init("SourceDebugExt01.jasm"); + // enable warnings for Jasm tests + super.enableToolsWarnings(); + } + + @ParameterizedTest + @MethodSource("getJasmParameters") + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + super.jasmTest(resourceName, args, tests); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/StackMapTableTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/StackMapTableTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/StackMapTableTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/StackMapTableTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.StackMapTable; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class StackMapTableTests { + private Jasm jasm = new Jasm(); + private Jcoder jcoder = new Jcoder(); + private File resourceDir; + + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("StackMapData.g.jasm", EToolArguments.JDIS_G, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "unset_fields") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "stack_map") == 6) + ), + Arguments.of("StackMapData.g.t.jasm", EToolArguments.JDIS_G_T, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "number_of_entries") == 4, + (Function) (text) -> funcSubStrCount.apply(text, "offset_delta") == 15) + ), + Arguments.of("StackMapData.jasm", EToolArguments.JDIS, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "unset_fields;") == 4) + ), + Arguments.of("StackMapData.t.jasm", EToolArguments.JDIS_T, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "frame_type") == 54) + ), + Arguments.of("StackMapData01.g.jasm", EToolArguments.JDIS_G, List.of( + (Function) (text) -> + funcSubStrCount.apply(text, "The ConstantPool[15] must be a CONSTANT_NameAndType_info") == 1) + ), + Arguments.of("StackMapData02.g.jasm", EToolArguments.JDIS_T, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval") == 13, + (Function) (text) -> funcSubStrCount.apply(text, "frame_type") == 39) + ) + + ); + } + + private static Stream getJcodParameters() { + return Stream.of( + Arguments.of("StackMapData.g.jcod", EToolArguments.JDEC, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval_frame") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "246b,") == 14 + )), + Arguments.of("StackMapData.jcod", EToolArguments.JDEC_G, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval_frame") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "246b,") == 14, + (Function) (text) -> funcSubStrCount.apply(text, "[25]") == 1 + )), + Arguments.of("StackMapData02.g.jcod", EToolArguments.JDEC_G, List.of( + (Function) (text) -> funcSubStrCount.apply(text, "early_larval_frame") == 13, + (Function) (text) -> funcSubStrCount.apply(text, "246b,") == 13, + (Function) (text) -> funcSubStrCount.apply(text, "[11]") == 1 + )) + ); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(Objects.requireNonNull(this.getClass().getResource("StackMapData.g.jasm")).getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getJasmParameters") + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + // jasm to class in memory + LogAndBinResults binResult = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertTrue(binResult.log.toString().isEmpty()); + Assertions.assertEquals(0, binResult.result); + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + String jasmText = textResult.getResultAsString(Function.identity()); + for (Function testFunction : tests) { + Assertions.assertTrue(testFunction.apply(jasmText)); + } + // jasm to class + binResult = jasm.compile(new StringInput(jasmText)); + // class produced correctly + Assertions.assertTrue(binResult.log.toString().isEmpty()); + Assertions.assertEquals(0, binResult.result); + // class to jasm + textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + jasmText = textResult.getResultAsString(Function.identity()); + for (Function testFunction : tests) { + Assertions.assertTrue(testFunction.apply(jasmText)); + } + // class to jcod + textResult = new Jdec().setArgs(EToolArguments.JDEC_G).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + // jcod to class + binResult = jcoder.compile(new StringInput(textResult.getResultAsString(Function.identity()))); + Assertions.assertEquals(0, binResult.result); + } + + @ParameterizedTest + @MethodSource("getJcodParameters") + public void jcoderTest(String resourceName, EToolArguments args, List> tests) { + // jcod to class in memory + LogAndBinResults binResult = jcoder.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jcod + LogAndTextResults textResult = new Jdec().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + for (Function testFunction : tests) { + Assertions.assertTrue(testFunction.apply(textResult.getResultAsString(Function.identity()))); + } + // class to jasm twice + textResult = new Jdis().setArgs(EToolArguments.JDIS_G_T_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + textResult = new Jdis().setArgs(EToolArguments.JDIS_GG_NC_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.attribute.StackMapTable.data; + +import static java.lang.Math.round; + +public class StackMapData { + static final int fldI = 0; + static long fldL = 1; + + protected String fldS = "string"; + public final String fldFS = "string"; + + public void generateFrames(int y) { + int x = 0; + Object obj = null; + + try { + x = 1 / x; + } catch (ArithmeticException e) { + obj = new Object(); + } finally { + obj.toString(); + } + + if (x == 0) { + obj = null; + } + + switch (x) { + case 1: + obj = new Object(); + break; + case 2: + break; + } + + if (y == 0) { + System.out.println("frame"); + } + + if (y == 1) { + int temp = 42; + System.out.println("item_frame" + (int) (temp * round(100))); + } + + if (y == 2) { + int a = 0; + for (int i = 0; i < 3000; i++) { + float temp = 3.14f; + a += (int) (temp * round(100)); + } + System.out.println("item_frame_" + a); + } + int d = round(10); + if (y == 3) { + int a = round(110f); + long b = round(100d); + System.out.println("_frame: " + (a + b) * d); + } + + if (y == 4) { + int c = 50 * d; + double dd = 99.99 * d; + System.out.println("Before chop_frame: " + (c + dd)); + } else { + System.out.println("chop_frame"); + } + + if (y == 5) { + int n = 0; + for (int i = 0; i < 2500; i++) { + float temp = 3.14f; + n += (int) (temp * round(i)); + } + if (n > 100) { + System.out.println("_frame_"); + } else if (n < 50) { + int c = 50 * d; + double dd = 99.99 * d; + System.out.println(c + dd); + } + } + + if (y == 6) { + String str = "n_frame"; + char ch = 'F'; + int num = 100; + System.out.println(str + ": " + ch + num); + } + + int z = 0; + Object obj1 = null; + + try { + z = 1 / z; + } catch (ArithmeticException e) { + obj1 = new Object(); + } finally { + obj1.toString(); + } + + if (z == 0) { + obj1 = null; + } + + switch (x) { + case 1: + obj1 = new Object(); + break; + case 2: + break; + } + } + + public int complexMethod(int x, Object o) { + int a = 0; + int b = 1; + Object c = null; + + try { + if (x > 0) { + a = x + 1; + if (o instanceof String) { + c = (String) o; + b = c.hashCode(); + return b; // Stack has one item (return value) + } + b = a * 2; + } else if (x == -1) { + a = -x; + b = a + 3; + throw new RuntimeException("Test exception"); // Jumps to catch + } else { + for (int i = 0; i < 2; i++) { + a += i; + if (a > 1) { + b = a - i; + break; // Early exit from loop + } + } + } + } catch (RuntimeException e) { + c = e; // New local variable (exception) + b = a + 5; + } + + return a + b; // Final return + } + + public int generateFullFrame(int x) { + int result; + Object temp; + boolean flag; + + try { + if (x > 0) { + // Path 1: Push something onto the stack and set locals + temp = "positive"; + flag = true; + result = temp.hashCode(); // Pushes an int onto the stack + } else { + // Path 2: Different stack state and locals + result = x * 2; // Simple computation, stack briefly has an int + throw new RuntimeException("non-positive"); + } + } catch (RuntimeException e) { + // Path 3: Exception path with different locals + temp = e; + flag = false; + result = -x; + } + // Merge point after try-catch + if (flag) { + return result + 1; // Stack has one item from Path 1 or 3 + } + // Simulate a different stack state by adding a method call + System.out.println("Computing result"); + return result; // Stack is empty after println + } + + public static void main(String[] args) { + StackMapData data = new StackMapData(); + for (int i = 0; i <= 6; i++) { + data.generateFrames(i); + } + data.complexMethod(fldI, "test"); + data.generateFullFrame(fldI + 23); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/InputOutputTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/InputOutputTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/InputOutputTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/InputOutputTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,146 @@ +package org.openjdk.asmtools.common; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.openjdk.asmtools.common.data.TestedHelloWorld; +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.TextOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; +import org.openjdk.asmtools.jdis.Options; +import org.openjdk.asmtools.lib.helper.ClassPathClassWork; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import static org.junit.jupiter.api.Assertions.fail; + +public class InputOutputTests extends ClassPathClassWork { + + @AfterAll + public static void unsetDetailedOutputOptions() { + Options.setDefaultOutputOptions(); + } + + public LogAndTextResults jdec(boolean g, byte[]... clazz) { + ToolInput[] originalFiles = new ToolInput[clazz.length]; + for (int i = 0; i < clazz.length; i++) { + originalFiles[i] = new ByteInput(clazz[i]); + } + TextOutput decodedFiles = new TextOutput(); + StringLog decodeLog = new StringLog(); + org.openjdk.asmtools.jdec.Main jdec = new org.openjdk.asmtools.jdec.Main(decodedFiles, decodeLog, originalFiles); + jdec.setVerboseFlag(true); + jdec.setTraceFlag(true); + if (g) { + jdec.setPrintDetails(true); + } else { + jdec.setPrintDetails(false); + } + int r = jdec.decode(); + return new LogAndTextResults(decodedFiles, decodeLog, r); + } + + public LogAndBinResults jcod(String... clazz) { + ToolInput[] originalFiles = new ToolInput[clazz.length]; + for (int i = 0; i < clazz.length; i++) { + originalFiles[i] = new StringInput(clazz[i]); + } + ByteOutput encodedFiles = new ByteOutput(); + StringLog encodeLog = new StringLog(); + org.openjdk.asmtools.jcoder.Main jcod = new org.openjdk.asmtools.jcoder.Main(encodedFiles, encodeLog, originalFiles); + jcod.setVerboseFlag(true); + jcod.setTraceFlag(true); + int r = jcod.compile(); + return new LogAndBinResults(encodedFiles, encodeLog, r); + } + + public LogAndTextResults jdis(boolean g, byte[]... clazz) { + ToolInput[] originalFiles = new ToolInput[clazz.length]; + for (int i = 0; i < clazz.length; i++) { + originalFiles[i] = new ByteInput(clazz[i]); + } + TextOutput decodedFiles = new TextOutput(); + StringLog decodeLog = new StringLog(); + org.openjdk.asmtools.jdis.Main jdis = new org.openjdk.asmtools.jdis.Main(decodedFiles, decodeLog, originalFiles); + jdis.setVerboseFlag(true); + jdis.setTraceFlag(true); + if (g) { + Options.setDetailedOutputOptions(); + } else { + Options.setDefaultOutputOptions(); + } + int r = jdis.disasm(); + return new LogAndTextResults(decodedFiles, decodeLog, r); + } + + public LogAndBinResults jasm(String... clazz) { + ToolInput[] originalFiles = new ToolInput[clazz.length]; + for (int i = 0; i < clazz.length; i++) { + originalFiles[i] = new StringInput(clazz[i]); + } + ByteOutput encodedFiles = new ByteOutput(); + StringLog encodeLog = new StringLog(); + org.openjdk.asmtools.jasm.Main jasm = new org.openjdk.asmtools.jasm.Main(encodedFiles, encodeLog, originalFiles); + jasm.setVerboseFlag(true); + jasm.setTraceFlag(true); + int r = jasm.compile(); + return new LogAndBinResults(encodedFiles, encodeLog, r); + } + + @Test + public void inMemoryDecCodDecCod() throws IOException { + initTestClassData(TestedHelloWorld.class); + byte[] data = Files.readAllBytes(new File(classFile).toPath()); + LogAndTextResults o1 = jdec(false, data); + LogAndBinResults o2 = jcod(o1.output.getOutputs().get(0).getBody()); + LogAndTextResults o3 = jdec(false, o2.output.getOutputs().get(0).getBody()); + LogAndBinResults o4 = jcod(o3.output.getOutputs().get(0).getBody()); + Assertions.assertArrayEquals(new int[]{0, 0, 0, 0}, new int[]{o1.result, o2.result, o3.result, o4.result}); + } + + @Test + public void inMemoryDisasmAsmDisasmAsm() throws IOException { + initTestClassData(TestedHelloWorld.class); + byte[] data = Files.readAllBytes(new File(classFile).toPath()); + LogAndTextResults o1 = jdis(false, data); + LogAndBinResults o2 = jasm(o1.output.getOutputs().get(0).getBody()); + LogAndTextResults o3 = jdis(false, o2.output.getOutputs().get(0).getBody()); + LogAndBinResults o4 = jasm(o3.output.getOutputs().get(0).getBody()); + Assertions.assertArrayEquals(new int[]{0, 0, 0, 0}, new int[]{o1.result, o2.result, o3.result, o4.result}); + } + + + @Test + public void inMemoryDecCodDecCodG() throws IOException { + initTestClassData(TestedHelloWorld.class); + byte[] data = Files.readAllBytes(new File(classFile).toPath()); + LogAndTextResults o1 = jdec(true, data); + if ( o1.result != 0 ) { + fail("jdec TestedHelloWorld.class failed.\n%s".formatted(o1.log)); + } + LogAndBinResults o2 = jcod(o1.output.getOutputs().get(0).getBody()); + LogAndTextResults o3 = jdec(true, o2.output.getOutputs().get(0).getBody()); + LogAndBinResults o4 = jcod(o3.output.getOutputs().get(0).getBody()); + Assertions.assertArrayEquals(new int[]{0, 0, 0, 0}, new int[]{o1.result, o2.result, o3.result, o4.result}); + } + + @Test + public void inMemoryDisasmAsmDisasmAsmG() throws IOException { + initTestClassData(TestedHelloWorld.class); + byte[] data = Files.readAllBytes(new File(classFile).toPath()); + LogAndTextResults o1 = jdis(true, data); + LogAndBinResults o2 = jasm(o1.output.getOutputs().get(0).getBody()); + LogAndTextResults o3 = jdis(true, o2.output.getOutputs().get(0).getBody()); + LogAndBinResults o4 = jasm(o3.output.getOutputs().get(0).getBody()); + Assertions.assertArrayEquals(new int[]{0, 0, 0, 0}, new int[]{o1.result, o2.result, o3.result, o4.result}); + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/SequenceCallsTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/SequenceCallsTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/SequenceCallsTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/SequenceCallsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.common; + + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.action.Jcoder; +import org.openjdk.asmtools.lib.ext.CaptureSystemOutput; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.opentest4j.MultipleFailuresError; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.ERROR; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class SequenceCallsTests { + final String TEST_RESOURCE_FOLDER = "sequence" + File.separator; + + private final List errors = Collections.synchronizedList(new ArrayList<>()); + private final List intResults = Collections.synchronizedList(new ArrayList<>()); + private final List boolResults = Collections.synchronizedList(new ArrayList<>()); + + private final Jasm jasmCompiler = new Jasm(); + private final Jcoder jcodCompiler = new Jcoder(); + private final Function, LogAndBinResults> jasm = files -> jasmCompiler.compile(files); + private final Function, LogAndBinResults> jcoder = files -> jcodCompiler.compile(files); + private final Function, Boolean> reflectiveJasm = files -> jasmCompiler.reflectiveCompile(files); + private final Function, Boolean> reflectiveJcoder = files -> jcodCompiler.reflectiveCompile(files); + + File resourceDir; + HashMap>> cases = new HashMap<>() {{ + put("jasm", + List.of( + List.of("EnclMethTest.jcod"), + List.of("ConstantPoolTestDummy.jasm"), + List.of("Not_Found_1.jasm"), + List.of("nonvoidinit.jasm", "nonvoidinit.jasm"), + List.of("Not_Found_2.jasm"), + List.of("TestInterface01n01.jasm") + ) + ); + put("jcoder", + List.of( + List.of("EnclMethTest.jcod"), + List.of("ConstantPoolTestDummy.jasm"), + List.of("Not_Found_I.jcod"), + List.of("module-info.jcod"), + List.of("atrcod00402m1n.jcod", "stackmap00601m1n.jcod"), + List.of("Not_Found_II.jcod") + ) + ); + }}; + + @BeforeAll + public void init() throws IOException { + String resName = TEST_RESOURCE_FOLDER + "EnclMethTest.jcod"; // must exist to get a correct path to files + File file = new File(this.getClass().getResource(resName).getFile()); + resourceDir = file.getParentFile(); + + } + + public class CaseExecutor01 implements Runnable { + private AtomicInteger counter = new AtomicInteger(0); + + public void run() throws MultipleFailuresError { + int index = counter.getAndIncrement(); + List jasmFiles = cases.get("jasm").get(index).stream(). + map(f -> resourceDir + File.separator + f).collect(Collectors.toList()); + List jcodFiles = cases.get("jcoder").get(index).stream(). + map(f -> resourceDir + File.separator + f).collect(Collectors.toList()); + if (index % 2 == 0) { + assertAll(() -> { + LogAndBinResults l = jasm.apply(jasmFiles); +// if( l.result != 0) { +// System.out.println("%d] Jasm failed with result: %s".formatted(index, l.log.toString() )); +// } + intResults.add(l.result); + }, + () -> { + LogAndBinResults l = jcoder.apply(jcodFiles); +// if( l.result != 0) { +// System.out.println("%d] Jcoder failed with result: %s".formatted(index, l.log.toString() )); +// } + intResults.add(l.result); + } + ); + } else { + assertAll(() -> { + LogAndBinResults l = jcoder.apply(jcodFiles); +// if( l.result != 0) { +// System.out.println("%d] Jcoder failed with result: %s".formatted(index, l.log.toString() )); +// } + intResults.add(l.result); + }, + () -> { + LogAndBinResults l = jasm.apply(jasmFiles); +// if( l.result != 0) { +// System.out.println("%d] Jasm failed with result: %s".formatted(index, l.log.toString() )); +// } + intResults.add(l.result); + } + ); + } + } + } + + public class CaseExecutor02 implements Runnable { + private AtomicInteger counter = new AtomicInteger(0); + + public void run() throws MultipleFailuresError { + int index = counter.getAndIncrement(); + List jasmFiles = cases.get("jasm").get(index).stream(). + map(f -> resourceDir + File.separator + f).collect(Collectors.toList()); + List jcodFiles = cases.get("jcoder").get(index).stream(). + map(f -> resourceDir + File.separator + f).collect(Collectors.toList()); + if (index % 2 == 0) { + assertAll(() -> { + var l = reflectiveJasm.apply(jasmFiles); + boolResults.add(l); + }, + () -> { + var l = reflectiveJcoder.apply(jcodFiles); + boolResults.add(l); + } + ); + } else { + assertAll(() -> { + var l = reflectiveJcoder.apply(jcodFiles); + boolResults.add(l); + }, + () -> { + var l = reflectiveJasm.apply(jasmFiles); + boolResults.add(l); + } + ); + } + } + } + + /** + * This is the test for CODETOOLS-7903401 (https://bugs.openjdk.org/browse/CODETOOLS-7903401) + * jtreg fails if set of jdk tests process jasm,jdis files with defects + *

+ * jib make -- test TEST=test/hotspot/jtreg/runtime + * Passed: runtime/classFileParserBug/BadInitMethod.java + * nonvoidinit.jasm (29:20) Warning: method cannot be an interface method + * public abstract Method "":"()I"; + * ^ + * Passed: runtime/cds/SharedBaseAddress.java#id1 + * Passed: runtime/classFileParserBug/FakeMethodAcc.java + * switch from jcoder to jcoder + * 1 warning(s) + * jcoder- ERROR: (I18NResourceBundle) The warning message 'warn.init.in_int' not found + * 1 error(s) + * -------------------------------------------------- + * TEST: runtime/classFileParserBug/InitInInterface.java + * TEST JDK: /Users/lkuskov/dev/openjdk/build/macosx-x64/images/jdk + *

+ * ACTION: compile -- Failed. jasm failed + * REASON: User specified action: run compile nonvoidinit.jasm voidinit.jasm + * TIME: 0.257 seconds + * messages: + * command: compile /Users/lkuskov/dev/openjdk/test/hotspot/jtreg/runtime/classFileParserBug/nonvoidinit.jasm + * /Users/lkuskov/dev/openjdk/test/hotspot/jtreg/runtime/classFileParserBug/voidinit.jasm + * reason: User specified action: run compile nonvoidinit.jasm voidinit.jasm + *

+ * The jtreg uses a single instance of asmtool during a test run that leads to error in switching between jasm + * and jcoder environment. I.e. the environment is set to Jcod while jasm is processing sources + * and therefore jasm can't find jasm-specific message in Jcoder environment. + */ + @Test + public void testCompilersWithConcurrency01() throws InterruptedException { + int numberOfThreads = cases.get("jasm").size(); + ExecutorService service = Executors.newFixedThreadPool(numberOfThreads); + CountDownLatch latch = new CountDownLatch(numberOfThreads); + CaseExecutor01 caseExecutor01 = new CaseExecutor01(); + for (int i = 0; i < numberOfThreads; i++) { + service.execute(() -> { + try { + caseExecutor01.run(); + } catch (MultipleFailuresError error) { + errors.add(error); + } + latch.countDown(); + } + ); + } + latch.await(); + // check OK's results + //"Expected 4 miss plus 2 wrong format files."); + assertEquals(12, intResults.size()); + Collections.sort(intResults); + assertEquals(0, intResults.get(0)); + assertEquals(0, intResults.get(1)); + assertEquals(0, intResults.get(2)); + assertEquals(0, intResults.get(3)); + assertEquals(0, intResults.get(4)); + assertEquals(0, intResults.get(5)); + assertEquals(1, intResults.get(6)); + assertEquals(1, intResults.get(7)); + assertEquals(1, intResults.get(8)); + assertEquals(2, intResults.get(9)); + assertEquals(2, intResults.get(10)); + assertEquals(8, intResults.get(11)); + } + + @Test + @CaptureSystemOutput(value = ERROR, mute = true) + public void testCompilersWithConcurrency02() throws InterruptedException { + int numberOfThreads = cases.get("jasm").size(); + jasmCompiler.setDestDir(); + jcodCompiler.setDestDir(); + ExecutorService service = Executors.newFixedThreadPool(numberOfThreads); + CountDownLatch latch = new CountDownLatch(numberOfThreads); + CaseExecutor02 caseExecutor02 = new CaseExecutor02(); + for (int i = 0; i < numberOfThreads; i++) { + service.execute(() -> { + try { + caseExecutor02.run(); + } catch (MultipleFailuresError error) { + errors.add(error); + } + latch.countDown(); + } + ); + } + latch.await(); + assertEquals(12, boolResults.size()); + assertEquals(6, boolResults.stream().filter(res -> res).count()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/data/TestedHelloWorld.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/data/TestedHelloWorld.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/data/TestedHelloWorld.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/common/data/TestedHelloWorld.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +package org.openjdk.asmtools.common.data; + +public class TestedHelloWorld { + + private static final int SOME_PRIMTIVE_CONSTANT=666; + private static int somePrimtiveField = 999; + + private static final TestedHelloWorld SOME_OBJECT_CONSTANT=new TestedHelloWorld(); + private static TestedHelloWorld someObjectField = new TestedHelloWorld(); + + private String privateMethod() { + return "hello1"; + } + + protected String protectedMethod() { + return "hello2"; + } + + public String publicMethod() { + return "hello3"; + } + + private static String privateUtilityMethod() { + return "hello4"; + } + + public static String publicUtilityMethod() { + return "hello5"; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/MultipleFilesInSingleJasmTest.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/MultipleFilesInSingleJasmTest.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/MultipleFilesInSingleJasmTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/MultipleFilesInSingleJasmTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; +import org.openjdk.asmtools.lib.ext.CaptureSystemOutput; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import static org.hamcrest.Matchers.containsString; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.ERROR; + +public class MultipleFilesInSingleJasmTest { + + @Test + @CaptureSystemOutput(value = ERROR, mute = true) + public void clfacc00610m10pTest(CaptureSystemOutput.OutputCapture outputCapture) throws IOException { + byte[] jasmFile = getJasmFile("clfacc00610m10p.jasm"); + ToolInput file = new ByteInput(jasmFile); + ByteOutput output = new ByteOutput(); + DualStreamToolOutput log = new StderrLog(); + org.openjdk.asmtools.jasm.Main jasm = new org.openjdk.asmtools.jasm.Main(output, log, file, "-v"); + int i = jasm.compile(); + outputCapture.expect(containsString("Class file version not specified in file or by -cv parameter")); + Assertions.assertEquals(0, i); + Assertions.assertEquals(2, output.getOutputs().size()); + } + + private byte[] getJasmFile(String s) throws IOException { + InputStream is = this.getClass().getResourceAsStream(s); + byte[] bytes; + try (is) { + bytes = is.readAllBytes(); + } + Assertions.assertNotNull(bytes); + String jasm = new String(bytes, StandardCharsets.UTF_8); + Assertions.assertNotNull(jasm); + return bytes; + } + + @Test + public void spinum00101m10pTest() throws IOException { + byte[] jasmFile = getJasmFile("spinum00101m10p.jasm"); + ToolInput file = new ByteInput(jasmFile); + ByteOutput output = new ByteOutput(); + DualStreamToolOutput log = new StderrLog(); //todo hide to ToolOutput.StringLog once done + org.openjdk.asmtools.jasm.Main jasm = new org.openjdk.asmtools.jasm.Main(output, log, file, "-v", "-nowarn"); + int i = jasm.compile(); + Assertions.assertEquals(0, i); + Assertions.assertEquals(258, output.getOutputs().size()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902696/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902696/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902696/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902696/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm.case7902696; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.lib.action.EToolArguments; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.action.Jdis; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import static java.lang.String.format; +import static org.openjdk.asmtools.common.Environment.FAILED; +import static org.openjdk.asmtools.common.Environment.OK; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + + private final Jasm jasm = new Jasm(); + + private File resourceDir; + + private static Stream getJasmParameters() { + return Stream.of( + Arguments.of("CondyNestedResolution.g.jasm"), + Arguments.of("CondyNestedResolution.g.t.jasm")); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(Objects.requireNonNull(this.getClass(). + getResource("CondyNestedResolution.g.jasm")).getFile()).getParentFile(); + } + + /** + * This is the test for the issue: CODETOOLS-7902696 (https://bugs.openjdk.org/browse/CODETOOLS-7902696) + * "jdis doesn't catch circular references in bsm args" + *

+ * public static Method bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object; + * Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + * stack 19 locals 19 + * { + * getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + * ldc String "In bsm4arg"; + * invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/Object;)V"; + * getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + * aload_3; + * invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/Object;)V"; + * getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + * aload 4; + * invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/Object;)V"; + * getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + * aload 5; + * invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/Object;)V"; + * getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + * aload 6; + * invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/Object;)V"; + * aload_3; + * areturn; + * } + * public static Method test_condy:"()V" + * stack 12 locals 12 + * { + * jdis: fatal error in file: CondyNestedResolution.class + */ + @ParameterizedTest + @MethodSource("getJasmParameters") + public void testJdisWarning(String resourceName) { + // jasm to class + final LogAndBinResults binResult = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + Assertions.assertEquals(OK, binResult.result); + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(EToolArguments.JDIS).decode(binResult.getAsByteInput()); + Assertions.assertEquals(FAILED, textResult.result); + List out = textResult.getLogStringsByPrefix("ERROR:"); + Assertions.assertEquals(9, out.size()); + for (String line : out) { + Assertions.assertTrue(line.contains("circular reference to Dynamic #")); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902820/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902820/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902820/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7902820/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm.case7902820; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.openjdk.asmtools.lib.action.EToolArguments; +import org.openjdk.asmtools.lib.action.Jcoder; +import org.openjdk.asmtools.lib.action.Jdec; +import org.openjdk.asmtools.lib.action.Jdis; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import static org.openjdk.asmtools.common.Environment.FAILED; +import static org.openjdk.asmtools.common.Environment.OK; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + + private final Jcoder jcoder = new Jcoder(); + + private File resourceDir; + private String resName = "InvalidSourceDebugExtension.jcod"; + + @BeforeAll + public void init() throws IOException { + File file = new File(this.getClass().getResource(resName).getFile()); + resourceDir = file.getParentFile(); + } + + /** + * This is the test for the issue: CODETOOLS-7902820 (https://bugs.openjdk.org/browse/CODETOOLS-7902820) + * "Asmtools incorrectly uses stdout for output error messages" + *

+ * If InvalidSourceDebugExtension.jcod can't be processed by jcoder due to an error in the jcod then the command + * java -jar asmtools.jar jcoder -w . InvalidSourceDebugExtension.jcod + * hides the error because the error message is outputted to stdout instead of stderr. + */ + @Test + public void testJdisWarning() { + final LogAndBinResults jcodResult = jcoder.compile(List.of(resourceDir + File.separator + resName)); + List out = jcodResult.getLogStringsByPrefix("Warning:"); + Assertions.assertEquals(OK, jcodResult.result); + Assertions.assertEquals(1, out.size()); + String msg = out.get(0); + // expected substring + Assertions.assertTrue( + msg.contains(" Expected attribute length \"2,147,483,647\" does not match the actual length \"0\"; expected length written")); + // + // class to jcod + LogAndTextResults textResult = new Jdec().setArgs(EToolArguments.JDEC_G).decode(jcodResult.getAsByteInput()); + Assertions.assertEquals(FAILED, textResult.result); + out = textResult.getLogStringsByPrefix("ERROR:"); + Assertions.assertEquals(1, out.size()); + msg = out.get(0); + Assertions.assertTrue(msg.contains("Requested array size exceeds VM limit")); + // class to jasm twice + textResult = new Jdis().setArgs(EToolArguments.JDIS_G_T_LNT_LVT).decode(jcodResult.getAsByteInput()); + Assertions.assertEquals(FAILED, textResult.result); + out = textResult.getLogStringsByPrefix("ERROR:"); + Assertions.assertEquals(1, out.size()); + msg = out.get(0); + Assertions.assertTrue(msg.contains("Requested array size exceeds VM limit")); + textResult = new Jdis().setArgs(EToolArguments.JDIS_GG_NC_LNT_LVT).decode(jcodResult.getAsByteInput()); + Assertions.assertEquals(FAILED, textResult.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903031/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903031/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903031/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903031/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023,2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm.case7903031; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.openjdk.asmtools.lib.action.EToolArguments; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.action.Jdis; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * This is the test for the issue CODETOOLS-7903031 (https://bugs.openjdk.org/browse/CODETOOLS-7903031) + * "jasm: Asmtools does not support CP table when it's processing modules" + * Files module-info.class.g.jasm has Constant Pool. + * The test is intended to check that the module-info file with Constant Pool can be compiled without issues. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + + private final String[] jasmFiles = new String[]{"module-info.class.g.jasm", "module-info.class.jasm"}; + + @BeforeAll + public void init() throws IOException { + for (int i = 0; i < jasmFiles.length; i++) { + String fileName = jasmFiles[i]; + File resourceDir = new File(this.getClass().getResource(fileName).getFile()).getParentFile(); + jasmFiles[i] = resourceDir + File.separator + fileName; + } + } + + @Test + public void moduleInfoTest() { + for (int i = 0; i < jasmFiles.length; i++) { + try { + //jasm to class + LogAndBinResults binResult = new Jasm().compile(List.of(jasmFiles[i])); + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(EToolArguments.JDIS_G).decode(binResult.getAsByteInput()); + + // Check that it is a module-info.jasm with removed spaces, tabs and new lines + String jasmOutput = textResult.getResultAsString(s -> s.replaceAll("[ \t\n]*", "")); + assertThat(jasmOutput, Matchers.allOf( + Matchers.startsWith("module#6/*java.base*/version65"), + Matchers.matchesRegex(".*const#100.*"), + Matchers.matchesRegex(".*const.*[Cc]lass.*"), + Matchers.matchesRegex(".*const.*Package.*"), + Matchers.matchesRegex(".*uses.*java.text.spi.DateFormatSymbolsProvider.*"), + Matchers.matchesRegex(".*provides.*java.nio.file.spi.FileSystemProvider.*"))); + } catch (Exception ex) { + fail("Unexpected exception: " + ex); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903405/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903405/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903405/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903405/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm.case7903405; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.log.LogAndReturn; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import static org.openjdk.asmtools.common.Environment.OK; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + + private final Jasm jasm = new Jasm(); + + private File resourceDir; + private String resName = "ifge_overflow.jasm"; + + @BeforeAll + public void init() throws IOException { + File file = new File(this.getClass().getResource(resName).getFile()); + resourceDir = file.getParentFile(); + } + + /** + * This is the test for the issue: CODETOOLS-7903405 (https://bugs.openjdk.org/browse/CODETOOLS-7903405) + * "compiler does not warn about instruction arguments that exceed allowed limits" + *

+ * The attached jasm source has a set of nop instructions between the jfqe instruction and the "SKIP" label that is used by it. + * The length of the set is 0x8FFF which exceeds allowed by JVMS - signed 16-bit value 0x8000. + * The jasm silently produces a class file that is declined by JVM: + *

+ * >java Test + * Error: Unable to initialize main class Test + * Caused by: java.lang.VerifyError: (class: Test, method: test_1 signature: ()V) Illegal target of jump or branch + *

+ * Since jasm allows to generate a "defect" binaries, it would be nice if the jasm assembler warns that already, + * and not just the class file verifier. + *

+ * Expected warning should be like: + *

+ * jasm - WARN: test_1()V - The argument 0x8000 of the 'ifge' instruction is written. + * It is larger than the allowed signed 16-bit value 0x7FFF + * 1 warning(s) + */ + @Test + public void testIfgeOverflow_7903405() { + final LogAndReturn logAndReturn = jasm.compile(List.of(resourceDir + File.separator + resName)); + final List warns = logAndReturn.getLogStringsByPrefix("WARN:"); + Assertions.assertEquals(logAndReturn.result, OK); + Assertions.assertEquals(warns.size(), 1); + String warn = warns.get(0); + // expected substrings + Assertions.assertTrue(warn.contains("test_1()V"), + "Expected method name \'test_1()V\' not found"); + Assertions.assertTrue(warn.contains("signed 16-bit value 0x7FFF"), + "Expected argument length \'signed 16-bit value 0x7FFF\' not found"); + Assertions.assertTrue(warn.contains("0x8000"), + "Expected length of written argument \'0x8000\' not found"); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903558/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903558/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903558/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903558/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm.case7903558; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.action.Jdis; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +import static java.lang.String.format; +import static org.openjdk.asmtools.common.Environment.OK; + +/** + * This is the test for the issue CODETOOLS-7903558 (https://bugs.openjdk.org/browse/CODETOOLS-7903558) + * "jasm: add support this_class, super_class value(s)" + *

+ * asm tool should support the values: + * this_class[:] (#ID | IDENT); // CLASSNAME + * super_class[:] (#ID | IDENT); // SUPERCLASSNAME + *

+ * Then the command `java -jar asmtools.jar jasm -d . FILE.jasm` where the jasm file is as follows: + * class FILENAME.data { + * this_class CLASSNAME; + * super_class SUPERCLASSNAME; + * } + * will produce a binary file `FILENAME.data` which, after decompiling (`java -jar asmtools.jar jdis FILENAME.data`), will be: + *

+ * super class CLASSNAME extends SUPERCLASSNAME version 45:0 {} + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + private Jasm jasm = new Jasm(); + private Jdis jdis = new Jdis(); + private File resourceDir; + private Path resultDir; + + private static Stream getTestParameters() { + return Stream.of( + // Detailed jasm + Arguments.of("JasmFile01.g.jasm", "FileName01.class", "ClassName01 extends java/lang/String"), + Arguments.of("JasmFile02.g.jasm", "FileName02.data", "ClassName02 extends java/lang/String"), + Arguments.of("JasmFile03.g.jasm", "FileName03.class", "ClassName03 extends package/SuperClassName03"), + Arguments.of("JasmFile04.g.jasm", "FileName04.obj", "ClassName04 extends package/SuperClassName04"), + // short version + Arguments.of("JasmFile01.jasm", "FileName01.class", "ClassName01 extends java/lang/String"), + Arguments.of("JasmFile02.jasm", "FileName02.data", "ClassName02 extends java/lang/String"), + Arguments.of("JasmFile03.jasm", "FileName03.class", "ClassName03 extends package/SuperClassName03"), + Arguments.of("JasmFile04.jasm", "FileName04.obj", "ClassName04 version") + ); + } + + @BeforeAll + public void init() throws IOException { + resultDir = Files.createTempDirectory("JdisJasmWorks"); + resultDir.toFile().deleteOnExit(); + resourceDir = new File(this.getClass().getResource("JasmFile01.g.jasm").getFile()).getParentFile(); + jasm.setDestDir(resultDir); + } + + @ParameterizedTest + @MethodSource("getTestParameters") + public void moduleInfoTest(String resourceName, String outputFileName, String jasmSubString) { + // jasm to class on the disk + jasm.compile(List.of(resourceDir + File.separator + resourceName)); + Path resultPath = Path.of(resultDir + File.separator + outputFileName); + Assertions.assertTrue(Files.exists(resultPath), format("Result file not found: %s%n", resultPath)); + // class to jasm + LogAndTextResults textResult = jdis.decode(List.of(resultPath.toString())); + Assertions.assertEquals(textResult.result, OK); + // expected substrings + String str = textResult.output.toString().substring(0, 80); + Assertions.assertTrue(str.contains(jasmSubString), format("'%s' not found in '%s'%n", jasmSubString, str)); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903976/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903976/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903976/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903976/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm.case7903976; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.log.LogAndBinResults; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +/** + * This is the test for the issue CODETOOLS-7903976 (https://bugs.openjdk.org/browse/CODETOOLS-7903976) + * "The jasm parser should permit malformed method signatures for JCK tests" + *

+ */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + private Jasm jasm = new Jasm(); + private File resourceDir; + + private static Stream getTestParameters() { + return Stream.of( + // Detailed jasm + Arguments.of("Test01.jasm", "Warning: Malformed method signature at position 1. \"({JavaTypeSignature})Result\" is missing."), + Arguments.of("Test02.jasm", "Warning: Malformed method signature at position 38. \"({JavaTypeSignature})Result\" is missing."), + Arguments.of("Test03.jasm", "Warning: Malformed method signature at position 3. Unknown token \"X\" in \"({JavaTypeSignature})Result\""), + Arguments.of("Test04.jasm", "Warning: Malformed method signature at position 2. Unknown token \"X\" in \"({JavaTypeSignature})Result\""), + Arguments.of("Test05.jasm", "Warning: Malformed method signature at position 38. \"({JavaTypeSignature})Result\" is missing."), + Arguments.of("Test06.jasm", "Warning: Malformed method signature at position 1. A \"(\" token is expected in \"({JavaTypeSignature})Result\""), + Arguments.of("Test07.jasm", "Warning: Malformed method signature at position 3. Unknown token \"X\" in \"({JavaTypeSignature})Result\""), + Arguments.of("Test08.jasm", "Warning: Malformed method signature at position 3. An array type signature is expected: \"[JavaTypeSignature\""), + Arguments.of("Test09.jasm", "Warning: Malformed method signature at position 39. \"({JavaTypeSignature})Result\" is missing."), + Arguments.of("Test10.jasm", "Warning: Malformed method signature at position 19. ClassTypeSignature is not properly terminated: L{PackageSpecifier/}SimpleClassTypeSignature;") + ); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(this.getClass().getResource("Test01.jasm").getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getTestParameters") + public void methodSignatureTest(String resourceName, String jasmSubString) { + // jasm to class on the disk + LogAndBinResults res = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + String log = res.log.toString(); + Assertions.assertTrue(log.contains(jasmSubString)); + // jasm file was created + Assertions.assertEquals(0, res.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903987/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903987/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903987/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/case7903987/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm.case7903987; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.lib.action.EToolArguments; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.action.Jdis; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.matchesRegex; + +/** + * This is the test for the enhancement CODETOOLS-7903987 https://bugs.openjdk.org/browse/CODETOOLS-7903987) + * "The jasm parser should allow the use of primitive types in Constant Pool." + * const #1=true; + * const #2=192837465; + * const #3=1l; + * const #6=2.1f; + * const #8="utf 8 entry"; + *

+ */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + private Jasm jasm = new Jasm(); + private Jdis jdis = new Jdis().setArgs(EToolArguments.JDIS_G); + private File resourceDir; + + private static Stream getTestParameters() { + return Stream.of( + // Detailed jasm + Arguments.of("Test00.jasm", "") + ); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(this.getClass().getResource("Test00.jasm").getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getTestParameters") + public void test00(String resourceName, String jasmSubString) { + // jasm to class on the disk + LogAndBinResults binResults = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + // jasm file was created + Assertions.assertEquals(0, binResults.result); + LogAndTextResults textResults = jdis.decode(binResults.getAsByteInput()); + Assertions.assertEquals(0, textResults.result); + String buf = textResults.output.toString(); + assertThat(buf, matchesRegex("(?s).*const.*#1.*int.*1;.*")); + assertThat(buf, matchesRegex("(?s).*const.*#2.*int.*192837465;.*")); + assertThat(buf, matchesRegex("(?s).*const.*#3.*long.*1l;.*")); + assertThat(buf, matchesRegex("(?s).*const.*#5.*float.*2.1f;.*")); + assertThat(buf, matchesRegex("(?s).*const.*#6.*double.*2.2d;.*")); + assertThat(buf, matchesRegex("(?s).*const.*#8.*Utf8.*Long utf-8.*")); + assertThat(buf, matchesRegex("(?s).*const.*#9.*int.*0;.*")); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/package-info.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/package-info.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jasm/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * jasm oriented tests + */ +package org.openjdk.asmtools.jasm; diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jcoder/MultipleFilesInSingleJcoderTest.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jcoder/MultipleFilesInSingleJcoderTest.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jcoder/MultipleFilesInSingleJcoderTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jcoder/MultipleFilesInSingleJcoderTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +package org.openjdk.asmtools.jcoder; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +public class MultipleFilesInSingleJcoderTest { + + @Test + public void jcod12Test() throws IOException { + byte[] jcodFile = getJcodFile("12.jcod"); + ToolInput file = new ByteInput(jcodFile); + ByteOutput output = new ByteOutput(); + DualStreamToolOutput log = new StderrLog(); //todo hide to ToolOutput.StringLog once done + org.openjdk.asmtools.jcoder.Main jcod = new org.openjdk.asmtools.jcoder.Main(output, log, file, "-v"); + int i = jcod.compile(); + Assertions.assertEquals(0, i); + Assertions.assertEquals(2, output.getOutputs().size()); + } + + private byte[] getJcodFile(String s) throws IOException { + InputStream is = this.getClass().getResourceAsStream(s); + byte[] bytes = null; + try (is) { + bytes = is.readAllBytes(); + } + Assertions.assertNotNull(bytes); + String jasm = new String(bytes, StandardCharsets.UTF_8); + Assertions.assertNotNull(jasm); + return bytes; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcod.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcod.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcod.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcod.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,74 @@ +package org.openjdk.asmtools.jdec; + +import org.junit.jupiter.api.Assertions; +import org.openjdk.asmtools.lib.helper.BruteForceHelper; +import org.openjdk.asmtools.lib.helper.ThreeStringWriters; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +class JdecJcod { + + private final boolean g; + private final BruteForceHelper worker; + + public JdecJcod(boolean g, BruteForceHelper worker) { + this.g = g; + this.worker = worker; + } + + public void run() throws IOException { + BruteForceHelper.AsmToolsExecutable jdec = new BruteForceHelper.AsmToolsExecutable() { + @Override + public int run(ThreeStringWriters outs, File clazz) throws IOException { + Main decoder; + if (g) { + decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), "-g", clazz.getAbsolutePath()); + } else { + decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), clazz.getAbsolutePath()); + } + return decoder.decode(); + } + + @Override + public void ensure(List all, Map failures) { + String gs = ""; + if (g) { + gs = "with -g "; + } + Assertions.assertEquals(0, failures.size(), "from " + all.size() + "(" + worker.getClassesRoot() + ") failed to decode " + gs + failures.size() + ": " + BruteForceHelper.keySetToString(failures, worker.getClassesRoot())); + } + }; + BruteForceHelper.AsmToolsExecutable jasm = new JasmToolExecutable(worker, g); + worker.work(jdec, jasm); + } + + private static class JasmToolExecutable implements BruteForceHelper.AsmToolsExecutable { + private final BruteForceHelper worker; + private final String g; + + public JasmToolExecutable(BruteForceHelper worker, boolean g) { + this.worker = worker; + if (g) { + this.g = " (from -g decode) "; + } else { + this.g = ""; + } + } + + @Override + public int run(ThreeStringWriters outs, File clazz) throws IOException { + File savedCode = BruteForceHelper.saveDecompiledCode(worker.getDecompiledClass(clazz), "JdecJcodWorks"); + org.openjdk.asmtools.jcoder.Main coder = new org.openjdk.asmtools.jcoder.Main(outs.getLoggers(), savedCode.getAbsolutePath(), "-d", worker.getCompileDir().getAbsolutePath()); + BruteForceHelper.createMetadata(outs, clazz, savedCode, worker.getCompileDir(), worker.getClassesRoot()); + return coder.compile(); + } + + @Override + public void ensure(List all, Map failures) { + Assertions.assertEquals(0, failures.size(), "from " + all.size() + " failed to encode " + g + " to (" + worker.getCompileDir() + ") " + failures.size() + ": " + BruteForceHelper.keySetToString(failures, worker.getClassesRoot())); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcodTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcodTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcodTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/JdecJcodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdec; + +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.lib.helper.BruteForceHelper; + +import java.io.IOException; + +class JdecJcodTests { + + @Test + public void jdecJcodAllDecompileCompileAndLoad() throws IOException { + BruteForceHelper worker = new BruteForceHelper(); + new JdecJcod(false, worker).run(); + } + + @Test + public void jdecGJcodAllDecompileCompileAndLoad() throws IOException { + BruteForceHelper worker = new BruteForceHelper(); + new JdecJcod(true, worker).run(); + + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/MainTest.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/MainTest.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/MainTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/MainTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,110 @@ +package org.openjdk.asmtools.jdec; +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.lib.action.Jcoder; +import org.openjdk.asmtools.lib.helper.ClassPathClassWork; +import org.openjdk.asmtools.lib.helper.ThreeStringWriters; +import org.openjdk.asmtools.lib.log.LogAndBinResults; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +class MainTest extends ClassPathClassWork { + + @BeforeAll + public static void prepareClass() { + initMainClassData(org.openjdk.asmtools.jdec.Main.class); + } + + @Test + public void main3StreamsNoSuchFileError() { + ThreeStringWriters outs = new ThreeStringWriters(); + + String nonExistingFile = "someNonExistingFile"; + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), nonExistingFile); + int i = decoder.decode(); + outs.flush(); + Assertions.assertEquals(1, i); + Assertions.assertTrue(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().contains("No such file")); + Assertions.assertTrue(outs.getErrorBos().contains(nonExistingFile)); + } + + @Test + public void main3StreamsCorruptedFileError() throws IOException { + ThreeStringWriters outs = new ThreeStringWriters(); + String badJcodFile = getFile("/org/openjdk/asmtools/jcoder/bad.jcod"); + // jcod to class + LogAndBinResults compileResult = new Jcoder().compile(List.of(badJcodFile)); + // class to jcod + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), compileResult.getAsByteInput()); + int i = decoder.decode(); + outs.flush(); + Assertions.assertEquals(1, i); + Assertions.assertTrue(outs.getErrorBos().contains("jdec - ERROR: Invalid constant type: 0 for element 1")); + Assertions.assertTrue(outs.getErrorBos().contains("1 error(s) in the file: bytes/bytes")); + Assertions.assertTrue(outs.getToolBos().contains("0xCA 0xFE 0xBA 0x00 0x03 0x00 0x2D 0x00;")); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + } + + @Test + public void main3StreamsFileInCorrectStream() throws IOException { + ThreeStringWriters outs = new ThreeStringWriters(); + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), classFile); + int i = decoder.decode(); + outs.flush(); + Assertions.assertEquals(0, i); + Assertions.assertFalse(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + Assertions.assertTrue(outs.getToolBos().contains("0xCAFEBABE;")); + } + + @Test + public void main3StreamsStdinCorrectStream() throws IOException { + ThreeStringWriters outs = new ThreeStringWriters(); + File in = new File(classFile); + InputStream is = System.in; + try { + System.setIn(new FileInputStream(in)); + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), org.openjdk.asmtools.Main.STDIN_SWITCH); + int i = decoder.decode(); + outs.flush(); + Assertions.assertEquals(0, i); + Assertions.assertFalse(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + Assertions.assertTrue(outs.getToolBos().contains("0xCAFEBABE")); + } finally { + System.setIn(is); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/case7902055/Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/case7902055/Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/case7902055/Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdec/case7902055/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdec.case7902055; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.openjdk.asmtools.common.Environment.OK; + +/** + * This is the test for the issue: CODETOOLS-7902055 (https://bugs.openjdk.org/browse/CODETOOLS-7902055) + * "Preserve module name in jdec output" + * dec output doesn't preserve the name of the module at the start of the + * declaration. + * + * Example: + * ------------------------------- + * $ cat module-info.jcod + * module foo.bar { + * } // end module foo.bar + * + * $ java -jar asmtools.jar jcoder -d out module-info.jcod + * $ java -jar asmtools.jar jdec out/module-info.class > module-info.jcod.after + * $ diff module-info.jcod module-info.jcod.after + * 1c1 + * < module foo.bar { + * --- + * > module { + * ------------------------------- + * + * Note that the module name in the end comment ("end module XXX") is + * preserved. + * + * The name given at the start of the module doesn't seem to have any effect on the .class output, + * but it would be nice to preserve it for readability reasons. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Tests { + private final Jcoder jcoder = new Jcoder(); + + private File resourceDir; + + private static Stream getJCodParameters() { + return Stream.of( + Arguments.of("module-info.g.jcod", "\\s*module\\s+moduleB\\s*\\{"), + Arguments.of("module-info.jcod", "\\s*module\\s+moduleB\\s*\\{")); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(Objects.requireNonNull(this.getClass(). + getResource("module-info.jcod")).getFile()).getParentFile(); + } + + // jcod -> .class -> jcod round trip should preserve the module name + @ParameterizedTest + @MethodSource("getJCodParameters") + public void testJCoderJdecRoundTrip(String resourceName, String jcodRegex) { + // jcod to class + final LogAndBinResults binResult = jcoder.compile(List.of(resourceDir + File.separator + resourceName)); + Assertions.assertEquals(OK, binResult.result); + // class to jcod + for ( EToolArguments arg : List.of(EToolArguments.JDEC, EToolArguments.JDEC_G)) { + LogAndTextResults textResult = new Jdec().setArgs(arg).decode(binResult.getAsByteInput()); + Assertions.assertEquals(OK, textResult.result); + // expected substrings + String jcodOutput = textResult.output.toString(); + jcodOutput = jcodOutput.substring(0, jcodOutput.indexOf("{")+1); + assertThat(jcodOutput, Matchers.matchesRegex(jcodRegex)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasm.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasm.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasm.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasm.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.junit.jupiter.api.Assertions; +import org.openjdk.asmtools.lib.helper.BruteForceHelper; +import org.openjdk.asmtools.lib.helper.ThreeStringWriters; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static org.openjdk.asmtools.common.Environment.OK; +import static org.openjdk.asmtools.lib.utility.StringUtils.addTail; + +class JdisJasm { + + private final String[] jdisArgs; + private String[] jasmArgs = new String[0]; + private final BruteForceHelper worker; + + public JdisJasm(BruteForceHelper worker, String... jdisArgs) { + this.jdisArgs = jdisArgs; + this.worker = worker; + } + + public JdisJasm setJasmArgs(String... jasmArgs) { + this.jasmArgs = jasmArgs; + return this; + } + + public void run() throws IOException { + BruteForceHelper.AsmToolsExecutable jdis = new BruteForceHelper.AsmToolsExecutable() { + @Override + public int run(ThreeStringWriters outs, File clazz) throws IOException { + Main disassem; + if (jdisArgs.length == 0) { + disassem = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), clazz.getAbsolutePath()); + } else { + disassem = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), addTail(jdisArgs, clazz.getAbsolutePath())); + } + return disassem.disasm(); + } + + @Override + public void ensure(List all, Map failures) { + String gs = (jdisArgs.length == 0) ? "" : "with %s ".formatted(String.join(",", jdisArgs)); + Assertions.assertEquals(0, failures.size(), "from " + all.size() + "(" + worker.getClassesRoot() + + ") failed to disassemble " + gs + failures.size() + ": " + + BruteForceHelper.keySetToString(failures, worker.getClassesRoot())); + } + }; + BruteForceHelper.AsmToolsExecutable jasm = new JasmToolExecutable(worker, jasmArgs); + worker.work(jdis, jasm); + } + + private static class JasmToolExecutable implements BruteForceHelper.AsmToolsExecutable { + private final BruteForceHelper worker; + private final String[] arguments; + + public JasmToolExecutable(BruteForceHelper worker, String[] arguments) { + this.worker = worker; + this.arguments = arguments; + } + + @Override + public int run(ThreeStringWriters outs, File clazz) throws IOException { + File savedAsm = BruteForceHelper.saveDecompiledCode(worker.getDecompiledClass(clazz), "JdisJasmWorks"); + org.openjdk.asmtools.jasm.Main asm = new org.openjdk.asmtools.jasm.Main(outs.getLoggers(), + addTail(arguments, savedAsm.getAbsolutePath(), "-d", worker.getCompileDir().getAbsolutePath())); + BruteForceHelper.createMetadata(outs, clazz, savedAsm, worker.getCompileDir(), worker.getClassesRoot()); + int rc = asm.compile(); + if (rc != OK) { + outs.getToolOutput().println("Failed to compile %s".formatted(savedAsm)); + outs.getToolOutput().flush(); + } + return rc; + } + + @Override + public void ensure(List all, Map failures) { + //three classes now fails; they will fail again in an attempt to be loaded on NPE + Assertions.assertEquals(0, failures.size(), + "from " + all.size() + " failed to assemble " + String.join(",", arguments) + " to (" + worker.getCompileDir() + ") " + + failures.size() + ": " + BruteForceHelper.keySetToString(failures, worker.getClassesRoot())); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasmTest.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasmTest.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasmTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/JdisJasmTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.lib.helper.BruteForceHelper; + +import java.io.IOException; + +class JdisJasmTest { + @Test + public void jdisJasmAllDecompileCompileAndLoad() throws IOException { + BruteForceHelper worker = new BruteForceHelper(); + JdisJasm task = new JdisJasm(worker); + task.run(); + } + + @Test + public void jdisTJasmAllDecompileCompileAndLoad() throws IOException { + BruteForceHelper worker = new BruteForceHelper(); + new JdisJasm(worker, "-table").run(); + } + + @Test + public void jdisGJasmAllDecompileCompileAndLoad() throws IOException { + BruteForceHelper worker = new BruteForceHelper(); + new JdisJasm(worker, "-g").run(); + } + + @Test + public void jdisGTJasmAllDecompileCompileAndLoad() throws IOException { + BruteForceHelper worker = new BruteForceHelper(); + new JdisJasm(worker, "-g", "-table").run(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/MainTest.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/MainTest.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/MainTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/jdis/MainTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jdis; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.lib.helper.ClassPathClassWork; +import org.openjdk.asmtools.lib.helper.ThreeStringWriters; +import org.openjdk.asmtools.common.outputs.StdoutOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +class MainTest extends ClassPathClassWork { + + @BeforeAll + public static void prepareClass() { + Options.setDefaultOutputOptions(); + initMainClassData(org.openjdk.asmtools.jdis.Main.class); + } + + @Test + public void main3StreamsNoSuchFileError() { + ThreeStringWriters outs = new ThreeStringWriters(); + String nonExisitngFile = "someNonExistingFile"; + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), nonExisitngFile); + int i = decoder.disasm(); + outs.flush(); + Assertions.assertEquals(1, i); + Assertions.assertTrue(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().contains("No such file")); + Assertions.assertTrue(outs.getErrorBos().contains(nonExisitngFile)); + } + + @Test + public void main3StreamsFileInCorrectStream() throws IOException { + ThreeStringWriters outs = new ThreeStringWriters(); + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), classFile); + int i = decoder.disasm(); + outs.flush(); + Assertions.assertEquals(0, i); + Assertions.assertFalse(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + Assertions.assertTrue(outs.getToolBos().contains("invoke")); + Assertions.assertEquals(1, packageName.matcher(outs.getToolBos()).results().count()); + Assertions.assertEquals(1, className.matcher(outs.getToolBos()).results().count()); + } + + @Test + public void main3StreamsStdinCorrectStream() throws IOException { + ThreeStringWriters outs = new ThreeStringWriters(); + File in = new File(classFile); + InputStream is = System.in; + try { + System.setIn(new FileInputStream(in)); + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), org.openjdk.asmtools.Main.STDIN_SWITCH); + int i = decoder.disasm(); + outs.flush(); + Assertions.assertEquals(0, i); + //pise to do stder:-/ + Assertions.assertFalse(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + Assertions.assertTrue(outs.getToolBos().contains("invoke")); + Assertions.assertEquals(1, packageName.matcher(outs.getToolBos()).results().count()); + Assertions.assertEquals(1, className.matcher(outs.getToolBos()).results().count()); + } finally { + System.setIn(is); + } + } + + @Test + public void superIsNotOmitted() throws IOException { + ThreeStringWriters outs = new ThreeStringWriters(); + String testClazz = clazz.getName().replace('.', '/'); + String name = testClazz.replaceAll(".*/", ""); + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), classFile); + int i = decoder.disasm(); + outs.flush(); + Assertions.assertEquals(0, i); + Assertions.assertFalse(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + String clazz = outs.getToolBos(); + for (String line : clazz.split("\n")) { + if (line.contains("class " + name + " extends JdisTool")) { + Assertions.assertTrue(line.contains("super"), "class declaration had super omitted - " + line); + checkSupperIsOmittedIfNotPresent(clazz, testClazz); + return; + } + } + Assertions.assertTrue(false, "class Main was not found in disassembled output"); + } + + private void checkSupperIsOmittedIfNotPresent(String clazzWithSuper, String fqn) throws IOException { + String name = fqn.replaceAll(".*/", ""); + String classWithoutSuper = clazzWithSuper.replaceFirst(" super ", " "); + File sourceWithoutSuper = File.createTempFile("jasmTest", name + ".jasm"); + sourceWithoutSuper.deleteOnExit(); + Files.write(sourceWithoutSuper.toPath(), classWithoutSuper.getBytes(StandardCharsets.UTF_8)); + File dir = File.createTempFile("asmtools-jasmtest", "tmp.dir"); + dir.delete(); + dir.mkdir(); + dir.deleteOnExit(); + org.openjdk.asmtools.jasm.Main jasmTool = new org.openjdk.asmtools.jasm.Main( + new StdoutOutput(), new StderrLog(), sourceWithoutSuper.getAbsolutePath(), + "-d", dir.getAbsolutePath()); + int ii = jasmTool.compile(); + Assertions.assertEquals(0, ii); + ThreeStringWriters outs = new ThreeStringWriters(); + Main decoder = new Main( + outs.getToolOutputWrapper(), outs.getLoggers(), dir.getAbsolutePath() + "/" + fqn + ".class"); + int i = decoder.disasm(); + outs.flush(); + Assertions.assertEquals(0, i); + Assertions.assertFalse(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + String clazz = outs.getToolBos(); + for (String line : clazz.split("\n")) { + if (line.contains("class " + name + " extends JdisTool")) { + Assertions.assertFalse(line.contains("super"), "class declaration had NOT super omitted - " + line); + return; + } + } + Assertions.assertTrue(false, "class Main was not found in disassembled output"); + } + + @Test + public void mainBothFileAndStreamIsRead() throws IOException { + ThreeStringWriters outs = new ThreeStringWriters(); + File in = new File(classFile); + InputStream is = System.in; + try { + System.setIn(new FileInputStream(in)); + Main decoder = new Main(outs.getToolOutputWrapper(), outs.getLoggers(), classFile, org.openjdk.asmtools.Main.STDIN_SWITCH, classFile, org.openjdk.asmtools.Main.STDIN_SWITCH); + int i = decoder.disasm(); + outs.flush(); + Assertions.assertEquals(0, i); + Assertions.assertFalse(outs.getToolBos().isEmpty()); + Assertions.assertTrue(outs.getErrorBos().isEmpty()); + Assertions.assertTrue(outs.getLoggerBos().isEmpty()); + Assertions.assertTrue(outs.getToolBos().contains("invoke")); + //3, both files, but stream only once, despite two are sets + Assertions.assertEquals(3, packageName.matcher(outs.getToolBos()).results().count()); + Assertions.assertEquals(3, className.matcher(outs.getToolBos()).results().count()); + } finally { + System.setIn(is); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Action.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Action.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Action.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Action.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import java.io.File; +import java.nio.file.Path; +import java.util.List; +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.fail; + +public class Action { + + private final EAsmTool tool; + protected final String toolName; + private FSAction fsAction = new FSAction(); + + protected EToolArguments currentToolArgs; + + public Action(EAsmTool tool) { + this.tool = tool; + toolName = tool.getName(); + currentToolArgs = EToolArguments.getArgumentsByPriority(tool, 0); + } + + public Action(EAsmTool tool, Path destDir) { + this(tool); + this.fsAction = new FSAction().setupDestDir(destDir); + } + + public Action setArgs(EToolArguments args) { + if (args.tool != this.tool) { + fail("Arguments mismatch for the tool " + args.tool); + } + currentToolArgs = args; + return this; + } + + public final List getListOfToolArgs() { + return EToolArguments.ofTool(tool); + } + + /** + * Sets up the output directory. + * + * @param destDir the directory to be used for output + * @return the instance + */ + public Action setDestDir(Path destDir) { + fsAction.setupDestDir(destDir); + return this; + } + + /** + * Sets the type of output, either to the file system or a memory buffer. + * + * @param value true if the output destination is the file system; otherwise, it is a memory buffer. + * @return the instance + */ + public Action FSOtput(boolean value) { + if (value) { + fsAction.setupDestDir(null); + } else { + fsAction.createDestDir(); + } + return this; + } + + public boolean isFSOutput() { + return fsAction.getDestDir() != null; + } + + /** + * Sets up the temporary output directory that will be created + * + * @return the instance + */ + public Action setDestDir() { + fsAction.createDestDir(); + return this; + } + + public List getDestDirParams() { + return fsAction.getDestDirParams(); + } + + + public String getDestDir() { + return fsAction.getDestDir().toString(); + } + + public Action setDebug(boolean value) { + DebugHelper.setDebug(value); + return this; + } + + public void trace(Supplier info) { + DebugHelper.trace(info); + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/CompileActor.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/CompileActor.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/CompileActor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/CompileActor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import org.openjdk.asmtools.common.Compiler; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.TriFunction; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndReturn; + +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.fail; +import static org.openjdk.asmtools.asmutils.StringUtils.ListToString; + +public abstract sealed class CompileActor, + R extends LogAndReturn> extends Action permits Jasm, Jcoder { + + protected TriFunction inputsCompiler; + protected TriFunction filesCompiler; + + protected CompileActor(EAsmTool tool) { + super(tool); + } + + protected CompileActor(EAsmTool tool, Path destDir) { + super(tool, destDir); + } + + /** + * Moderator method based on reflection API to call compiler + */ + public boolean reflectiveCompile(List files) { + boolean result = false; + if (files.isEmpty()) + fail(toolName + ": no files"); + ArrayList args = new ArrayList<>(Arrays.asList(currentToolArgs.getArgs())); + args.addAll(getDestDirParams()); + args.addAll(files); + try { + String toolClassName = "org.openjdk.asmtools." + toolName + ".Main"; + Class toolClass = Class.forName(toolClassName); + Constructor constr = toolClass.getConstructor(PrintStream.class, String.class); + PrintStream ps = new PrintStream(System.out); + Object tool = constr.newInstance(ps, toolName); + Method m = toolClass.getMethod("compile", String[].class); + Object r = m.invoke(tool, new Object[]{args.toArray(String[]::new)}); + if (r instanceof Boolean) { + result = (Boolean) r; + } else { + fail("unexpected result from " + toolName + ": " + r.toString()); + } + } catch (ClassNotFoundException e) { + fail("can't find " + toolName); + } catch (ReflectiveOperationException t) { + fail("error invoking " + toolName + ": " + t); + } + return result; + } + + public R compile(List files) { + if (files.size() == 0) + fail("%s: tool inputs are missing".formatted(toolName)); + ArrayList args = new ArrayList<>(Arrays.asList(currentToolArgs.getArgs())); + args.addAll(getDestDirParams()); + args.addAll(files); + super.trace(()->"%s.compile%s".formatted(toolName, ListToString(args))); + ByteOutput encodedFiles = new ByteOutput(); + StringLog encodeLog = new StringLog(); + C compiler = filesCompiler.apply(encodedFiles, encodeLog, args.toArray(String[]::new)); + int rc = compiler.compile(); + return (R) new LogAndBinResults(encodedFiles, encodeLog, rc); + } + + public R compile(ToolInput... toolInputs) { + if (toolInputs.length == 0) + fail("%s: tool inputs are missing".formatted(toolName)); + ArrayList args = new ArrayList<>(Arrays.asList(currentToolArgs.getArgs())); + args.addAll(getDestDirParams()); + super.trace(()->"%s.compile%s".formatted(toolName, ListToString(args))); + ByteOutput encodedFiles = new ByteOutput(); + StringLog encodeLog = new StringLog(); + C compiler = inputsCompiler.apply(encodedFiles, encodeLog, toolInputs); + int rc = compiler.compile(args.toArray(String[]::new)) ? Environment.OK : Environment.FAILED; + return (R) new LogAndBinResults(encodedFiles, encodeLog, rc); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DebugHelper.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DebugHelper.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DebugHelper.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DebugHelper.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import java.util.function.Supplier; + +public class DebugHelper { + + protected static boolean Debug = false; + + public static void setDebug(boolean debug) { + Debug = debug; + } + + public static boolean isDebug() { + return Debug; + } + + + public static void trace(Supplier info) { + if (Debug) { + System.out.format("TRACE: %s%n".formatted(info.get())); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DecodeActor.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DecodeActor.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DecodeActor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/DecodeActor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import org.openjdk.asmtools.common.Decoder; +import org.openjdk.asmtools.common.Environment; +import org.openjdk.asmtools.common.TriFunction; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.StdoutOutput; +import org.openjdk.asmtools.common.outputs.TextOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; +import org.openjdk.asmtools.lib.log.LogAndReturn; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.fail; +import static org.openjdk.asmtools.asmutils.StringUtils.ListToString; +import static org.openjdk.asmtools.common.Environment.OK; + +public abstract sealed class DecodeActor, + R extends LogAndReturn> extends Action permits Jdis, Jdec { + + protected TriFunction inputsDecoder; + protected TriFunction filesDecoder; + + protected DecodeActor(EAsmTool tool) { + super(tool); + } + + protected DecodeActor(EAsmTool tool, Path destDir) { + super(tool, destDir); + } + + /** + * Moderator method based on reflection API to call tools + */ + public boolean reflectiveCompile(List files) { + boolean result = false; + if (files.isEmpty()) + fail(toolName + ": no files"); + ArrayList args = new ArrayList<>(Arrays.asList(currentToolArgs.getArgs())); + args.addAll(getDestDirParams()); + args.addAll(files); + try { + String toolClassName = "org.openjdk.asmtools." + toolName + ".Main"; + Class toolClass = Class.forName(toolClassName); + Constructor constr = toolClass.getConstructor(ToolOutput.class, String[].class); + Object tool = constr.newInstance(new StdoutOutput(), args.toArray(String[]::new)); + Method m = toolClass.getMethod("decode"); + int r = (int) m.invoke(tool); + return r == OK; + } catch (ClassNotFoundException e) { + fail("can't find " + toolName); + } catch (ReflectiveOperationException t) { + fail("error invoking " + toolName + ": " + t); + } + return result; + } + + public R decode(List files) { + if (files.size() == 0) + fail("%s: tool inputs are missing".formatted(toolName)); + ArrayList args = new ArrayList<>(Arrays.asList(currentToolArgs.getArgs())); + args.addAll(getDestDirParams()); + args.addAll(files); + super.trace(()->"%s.decode%s".formatted(toolName, ListToString(args))); + TextOutput encodedFiles = new TextOutput(); + StringLog encodeLog = new StringLog(); + D decoder = filesDecoder.apply(encodedFiles, encodeLog, args.toArray(String[]::new)); + int rc = decoder.decode(); + return (R) new LogAndTextResults(encodedFiles, encodeLog, rc); + } + + public R decode(ToolInput... toolInputs) { + if (toolInputs.length == 0) + fail("%s: tool inputs are missing".formatted(toolName)); + ArrayList args = new ArrayList<>(Arrays.asList(currentToolArgs.getArgs())); + args.addAll(getDestDirParams()); + super.trace(()->"%s.decode%s".formatted(toolName, ListToString(args))); + TextOutput encodedFiles = new TextOutput(); + StringLog encodeLog = new StringLog(); + D decoder = inputsDecoder.apply(encodedFiles, encodeLog, toolInputs); + int rc = decoder.decode(args.toArray(String[]::new)) ? OK : Environment.FAILED; + return (R) new LogAndTextResults(encodedFiles, encodeLog, rc); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EAsmTool.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EAsmTool.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EAsmTool.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EAsmTool.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023, 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.lib.log.LogAndReturn; + +import java.util.List; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.fail; + +public enum EAsmTool { + UNDEF("", null, null), + JASM(".jasm", + (files) -> new Jasm().compile(files), + (inputs) -> new Jasm().compile(inputs)), + JCODER(".jcod", + (files) -> new Jcoder().compile(files), + (inputs) -> new Jcoder().compile(inputs)), + JDEC(".class", + (files) -> new Jdec().decode(files), + (inputs) -> new Jdec().decode(inputs)), + JDIS(".class", + (files) -> new Jdis().decode(files), + (inputs) -> new Jdis().decode(inputs)); + private final String fileExtension; + private final Function, LogAndReturn> filesTool; + private final Function inputsTool; + + EAsmTool(String fileExtension, Function, LogAndReturn> filesTool, + Function inputsTool) { + this.fileExtension = fileExtension; + this.filesTool = filesTool; + this.inputsTool = inputsTool; + } + + public LogAndReturn call(List files) { + return filesTool.apply(files); + } + + public LogAndReturn call(ToolInput[] inputs) { + return inputsTool.apply(inputs); + } + + public String getName() { + return this.name().toLowerCase(); + } + + public String getFileExtension() { + return fileExtension; + } + + public static EAsmTool getToolBy(String toolName) { + for (EAsmTool t : values()) { + if (toolName.compareToIgnoreCase(t.name()) == 0) + return t; + } + fail("The tool %s isn't yet supported.".formatted(toolName)); + return null; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EToolArguments.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EToolArguments.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EToolArguments.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/EToolArguments.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public enum EToolArguments { + NONE(new String[0], EAsmTool.UNDEF, 0), + JDIS(new String[0], EAsmTool.JDIS, 0), + JDIS_T(new String[]{"-table"}, EAsmTool.JDIS, 1), + JDIS_G(new String[]{"-g"}, EAsmTool.JDIS, 2), + JDIS_GG(new String[]{"-gg"}, EAsmTool.JDIS, 3), + JDIS_G_T(new String[]{"-g", "-table"}, EAsmTool.JDIS, 4), + JDIS_GG_T_NC(new String[]{"-gg", "-table", "-nc"}, EAsmTool.JDIS, 5), + JDIS_G_T_LNT_LVT(new String[]{"-g", "-table", "-lnt", "-lvt"}, EAsmTool.JDIS, 6), + JDIS_GG_NC_LNT_LVT(new String[]{"-gg", "-table", "-lnt", "-lvt", "-nc"}, EAsmTool.JDIS, 7), + + JDEC(new String[0], EAsmTool.JDEC, 1), + JDEC_G(new String[]{"-g"}, EAsmTool.JDEC, 2), + + JASM(new String[0], EAsmTool.JASM, 0), + JASM_STRICT(new String[]{"-strict"}, EAsmTool.JASM, 1), + JASM_NOWARN(new String[]{"-nowarn"}, EAsmTool.JASM, 2); + + final String[] args; + final EAsmTool tool; + final int priority; + + EToolArguments(String[] args, EAsmTool tool, int priority) { + this.args = args; + this.tool = tool; + this.priority = priority; + } + + public String getPostfix() { + String str = Arrays.stream(args).map(s -> s.replace("-", "")). + collect(Collectors.joining(".")); + return (!str.isEmpty()) ? "." + str : ""; + } + + public String[] getArgs() { + return args; + } + + public static List ofTool(EAsmTool eAsmTool) { + return Arrays.stream(values()). + filter(v -> v.tool == eAsmTool). + collect(Collectors.toCollection(ArrayList::new)); + } + + public static EToolArguments getArgumentsByPriority(EAsmTool tool, int priority) { + return Arrays.stream(values()).filter(v -> v.tool == tool && v.priority == priority). + findFirst().orElse(NONE); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/FSAction.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/FSAction.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/FSAction.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/FSAction.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.fail; + +public class FSAction { + + public static Function getTmpPath = subDir -> + Path.of(System.getProperty("user.home"), "tmp", subDir); + + // -d Specify where to place generated class files, otherwise + // -w Specify where to place generated class files, without considering the classpath, otherwise + private boolean ignorePackage = false; + private Path destDir = null; + private boolean deleteOnExit = false; + + + /** + * @param destDir + * @return this class instance + */ + public FSAction setupDestDir(Path destDir) { + if (destDir != null) { + if (this.destDir == null) { + this.destDir = createDestDir(destDir); + } else if (!this.destDir.equals(destDir)) { + if (!deleteOnExit) { + delDestDir(); + this.destDir = createDestDir(destDir); + } else { + this.destDir = createDestDir(destDir); + this.destDir.toFile().deleteOnExit(); + } + } + } else { + // Deletes the previously set destDir and deactivates it. + if (this.destDir != null && !deleteOnExit) { + delDestDir(); + } + this.destDir = null; + } + return this; + } + + public FSAction setupDestDir() { + this.destDir = createDestDir(); + return this; + } + + public Path createDestDir() { + if (this.destDir == null) { + try { + this.destDir = Files.createTempDirectory("asmtools-tests").toAbsolutePath(); + this.destDir.toFile().deleteOnExit(); + deleteOnExit = true; + } catch (IOException e) { + fail("Unable to create temporary directory"); + } + } + return this.destDir; + } + + private Path createDestDir(Path destDir) { + if (!Files.exists(destDir)) { + try { + Files.createDirectories(destDir); + } catch (IOException e) { + fail("Unable to create destination directory %s".formatted(destDir.toString())); + } + } + return destDir; + } + + private FSAction delDestDir() { + if (this.destDir != null && Files.exists(this.destDir)) { + // Cleanup: Delete temporary directory and its contents + try { + Files.walk(this.destDir) + .map(Path::toFile) + .forEach(file -> { + System.out.println("Deleting: " + file); + file.delete(); + }); + } catch (IOException e) { + throw new RuntimeException("Can't clean up the dest dir: %s".formatted(destDir)); + } + } + return this; + } + + public FSAction setDeleteOnExit(boolean deleteOnExit) { + this.deleteOnExit = deleteOnExit; + return this; + } + + public Path getDestDir() { + return destDir; + } + + public FSAction setIgnorePackage(boolean value) { + this.ignorePackage = value; + return this; + } + + public List getDestDirParams() { + return (this.destDir == null) ? + List.of() : + List.of( + (this.ignorePackage ? "-w" : "-d"), + this.destDir.toString()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jasm.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jasm.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jasm.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jasm.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import org.openjdk.asmtools.jasm.Main; +import org.openjdk.asmtools.lib.log.LogAndBinResults; + +import java.nio.file.Path; + +import static org.openjdk.asmtools.lib.action.EAsmTool.JASM; + +public final class Jasm extends CompileActor { + public Jasm() { + super(JASM); + inputsCompiler = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesCompiler = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } + + public Jasm(Path destDir) { + super(JASM, destDir); + inputsCompiler = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesCompiler = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jcoder.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jcoder.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jcoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jcoder.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import org.openjdk.asmtools.jcoder.Main; +import org.openjdk.asmtools.lib.log.LogAndBinResults; + +import java.nio.file.Path; + +import static org.openjdk.asmtools.lib.action.EAsmTool.JCODER; + +public final class Jcoder extends CompileActor { + + public Jcoder() { + super(JCODER); + inputsCompiler = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesCompiler = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } + + public Jcoder(Path destDir) { + super(JCODER, destDir); + inputsCompiler = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesCompiler = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdec.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdec.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdec.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdec.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import org.openjdk.asmtools.jdec.Main; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.nio.file.Path; + +import static org.openjdk.asmtools.lib.action.EAsmTool.JDEC; + +public final class Jdec extends DecodeActor { + public Jdec() { + super(JDEC); + inputsDecoder = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesDecoder = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } + + public Jdec(Path destDir) { + super(JDEC, destDir); + inputsDecoder = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesDecoder = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } + + @Override + public Jdec setArgs(EToolArguments args) { + super.setArgs(args); + return this; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdis.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdis.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdis.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/action/Jdis.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.action; + +import org.openjdk.asmtools.jdis.Main; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.nio.file.Path; + +import static org.openjdk.asmtools.lib.action.EAsmTool.JDIS; + +public final class Jdis extends DecodeActor { + public Jdis() { + super(JDIS); + inputsDecoder = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesDecoder = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } + + public Jdis(Path destDir) { + super(JDIS, destDir); + inputsDecoder = (encodedFiles, encodeLog, inputs) -> + new Main(encodedFiles, encodeLog, inputs); + filesDecoder = (encodedFiles, encodeLog, args) -> + new Main(encodedFiles, encodeLog, args); + } + + public Jdis setArgs(EToolArguments args) { + super.setArgs(args); + return this; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/attributes/Attribute.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/attributes/Attribute.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/attributes/Attribute.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/attributes/Attribute.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.attributes; + +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.lib.action.Jasm; + +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.fail; + +public class Attribute { + + static MethodHandles.Lookup lookup = MethodHandles.lookup(); + + Jasm jasm = null; + + private final Attribute.Kind kind; + private final int expectedRc; + private String[] classParams = new String[0]; + + private String attributeName; + private String className; + private String resourceName; + private String outputFileName; + + public Attribute(Attribute.Kind kind, String className, int expectedRc) { + this.kind = kind; + this.className = className; + this.resourceName = "/".concat(className.replace('.', '/')).concat(".class"); + this.expectedRc = expectedRc; + this.attributeName = this.getClass().getSimpleName(); + int ind = attributeName.lastIndexOf("Attribute"); + if (ind != -1) { + attributeName = attributeName.substring(0, ind); + } + } + + public String getSimpleClassName() { + int ind = className.lastIndexOf("."); + return (ind != -1) ? className.substring(ind + 1) : className; + } + + public String getClassName() { + return className; + } + + public int getExpectedRc() { + return expectedRc; + } + + public ToolInput getContent() { + byte[] bytes = null; + try { + bytes = getClass().getResourceAsStream(resourceName).readAllBytes(); + } catch (IOException e) { + fail("Can't read the class %s\ndue to %s".formatted(className, + e.toString())); + } + return new ByteInput(bytes); + } + + public int run() { + int returnCode = -1; + try { + Class clazz = Class.forName(className); + MethodHandle methodHandle; + if (kind == Attribute.Kind.CLASS_MAIN || kind == Attribute.Kind.CLASS_RUN) { + methodHandle = Attribute.lookup.findStatic(clazz, kind.methodName, kind.methodType); + returnCode = (Integer) methodHandle.invoke(this.classParams); + } else { + methodHandle = Attribute.lookup.findVirtual(clazz, kind.methodName, kind.methodType); + // Create an instance of the class + Object instance = clazz.getDeclaredConstructor().newInstance(); + // Invoke the method (non-static, so pass the instance) + returnCode = (Integer) methodHandle.invoke(instance, this.classParams); + } + } catch (Throwable e) { + fail("Can't run %s::%s\ndue to %s".formatted(className, + kind.toString(), + e.toString())); + } + return returnCode; + } + + public enum Kind { + CLASS_MAIN("main", MethodType.methodType(int.class, String[].class)), + CLASS_RUN("run", MethodType.methodType(int.class, String[].class)), + INSTANCE_RUN("run", MethodType.methodType(int.class, String[].class)); + final String methodName; + final MethodType methodType; + + Kind(String methodName, MethodType methodType) { + this.methodName = methodName; + this.methodType = methodType; + } + + @Override + public String toString() { + return "%s %s(%s)".formatted(methodType.returnType().getCanonicalName(), + methodName, + Arrays.stream(methodType.parameterArray()). + map(clazz -> clazz.getCanonicalName()).collect(Collectors.joining(", "))); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutput.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutput.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.ext; + +import org.hamcrest.Matcher; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.*; +import java.util.function.Function; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +@Documented +@ExtendWith(CaptureSystemOutputExtension.class) +public @interface CaptureSystemOutput { + Kind value() default Kind.OUTPUT; + + boolean mute() default false; + + enum Kind {OUTPUT, ERROR, BOTH} + + class OutputCapture { + List> strMatchers = new ArrayList<>(); + List>> listMatchers = new ArrayList<>(); + Optional> transformer = Optional.empty(); + Optional>> listTransformer = Optional.empty(); + private CaptureOutputStream captureOut; + private CaptureOutputStream captureErr; + private OutputStream log; + private OutputStream err; + + CaptureSystemOutput.OutputCapture capture(Kind kind, boolean muted) { + if (kind == Kind.OUTPUT || kind == Kind.BOTH) { + log = new ByteArrayOutputStream(); + this.captureOut = new CaptureOutputStream(System.out, log, muted); + System.setOut(new PrintStream(this.captureOut)); + } + if (kind == Kind.ERROR || kind == Kind.BOTH) { + err = new ByteArrayOutputStream(); + this.captureErr = new CaptureOutputStream(System.err, err, muted); + System.setErr(new PrintStream(this.captureErr)); + } + return this; + } + + public CaptureSystemOutput.OutputCapture release() { + flush(); + if (this.captureOut != null) + System.setOut(this.captureOut.getOriginalStream()); + if (this.captureErr != null) + System.setErr(this.captureErr.getOriginalStream()); + strMatchers = new ArrayList<>(); + try { + if (log != null) + log.close(); + if (err != null) + err.close(); + } catch (IOException ex) { /* no-op */ } + return this; + } + + CaptureSystemOutput.OutputCapture flush() { + try { + if (this.captureOut != null) + this.captureOut.flush(); + } catch (IOException ex) { /* no-op */ } + try { + if (this.captureErr != null) + this.captureErr.flush(); + } catch (IOException ex) { /* no-op */ } + return this; + } + + public OutputCapture expect(Matcher... matchers) { + for (Matcher m : matchers) { + this.strMatchers.add(m); + } + return this; + } + + public void expectForList(Matcher> matcher) { + this.listMatchers.add(matcher); + } + + public OutputCapture useStringTransformer(Function transformer) { + this.transformer = Optional.of(transformer); + return this; + } + + public OutputCapture useListTransformer(Function> transformer) { + this.listTransformer = Optional.of(transformer); + return this; + } + + public String getLogAsString(Kind kind) { + return this.transformer.orElse(s -> s).apply(getCapture(kind).toString()); + } + + public List getLogAsList(Kind kind) { + return this.listTransformer. + orElse(s -> Arrays.stream(s.split(System.lineSeparator())).toList()). + apply(getCapture(kind).toString()); + } + + public String[] getLogAsArray(Kind kind) { + return getLogAsList(kind).toArray(String[]::new); + } + + private String getCapture(Kind kind) { + return switch (kind) { + case OUTPUT -> (log != null) ? log.toString() : ""; + case ERROR -> (err != null) ? err.toString() : ""; + case BOTH -> ((log != null) ? log.toString() : "").concat((err != null) ? err.toString() : ""); + }; + } + + private static class CaptureOutputStream extends OutputStream { + private final PrintStream originalStream; + private final OutputStream log; + private final boolean muted; + + CaptureOutputStream(PrintStream originalStream, OutputStream log, boolean muted) { + this.originalStream = originalStream; + this.log = log; + this.muted = muted; + } + + PrintStream getOriginalStream() { + return this.originalStream; + } + + @Override + public void write(int b) throws IOException { + if (!muted) + originalStream.write(b); + log.write(b); + } + + @Override + public void flush() throws IOException { + this.originalStream.flush(); + } + + @Override + public void close() { + this.originalStream.flush(); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutputExtension.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutputExtension.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutputExtension.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/ext/CaptureSystemOutputExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.ext; + +import org.junit.jupiter.api.extension.*; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; +import org.openjdk.asmtools.lib.ext.CaptureSystemOutput.OutputCapture; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; + +class CaptureSystemOutputExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { + + private CaptureSystemOutput.Kind kind; + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + Optional method = context.getTestMethod(); + if (method.isPresent()) { + CaptureSystemOutput ann = method.get().getAnnotation(CaptureSystemOutput.class); + if (ann != null) { + kind = ann.value(); + getOutputCapture(context).capture(ann.value(), ann.mute()); + } + } + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + OutputCapture outputCapture = getOutputCapture(context); + try { + CaptureSystemOutput.Kind k = this.kind == null ? CaptureSystemOutput.Kind.BOTH : this.kind; + // expect is used + if (!outputCapture.strMatchers.isEmpty()) { + String string = outputCapture.getLogAsString(kind); + assertThat(string, allOf(outputCapture.strMatchers)); + } + // array is used + if (!outputCapture.listMatchers.isEmpty()) { + List list = outputCapture.getLogAsList(kind); + assertThat(list, allOf(outputCapture.listMatchers)); + } + } finally { + outputCapture.release(); + } + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + boolean isTestMethodLevel = extensionContext.getTestMethod().isPresent(); + boolean isOutputCapture = parameterContext.getParameter().getType() == OutputCapture.class; + return isTestMethodLevel && isOutputCapture; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return getOutputCapture(extensionContext); + } + + private OutputCapture getOutputCapture(ExtensionContext context) { + return getStore(context).getOrComputeIfAbsent(OutputCapture.class); + } + + private Store getStore(ExtensionContext context) { + return context.getStore(Namespace.create(getClass(), context.getRequiredTestMethod())); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/BruteForceHelper.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/BruteForceHelper.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/BruteForceHelper.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/BruteForceHelper.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.helper; + +import org.junit.jupiter.api.Assertions; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; +import java.util.stream.Collectors; + +public class BruteForceHelper { + + public static HashSet excludeSet = new HashSet<>() {{ + add("SourceDebugExtensionNegative01.class"); + add("SourceDebugExtensionNegative02.class"); + add("SourceDebugExtensionNegative03.class"); + add("LoadableDescriptorsAttributeTest$X.class"); + add("InvalidSourceDebugExtension.class"); + add("CondyNestedResolution.class"); + }}; + + public static final String FRESHLY_BUILT_ASMTOOLS = "target/classes"; + + private final ClassProvider classProvider; + + private final Map failedJdis = new HashMap<>(); + private final Map passedJdis = new HashMap<>(); + private final Map failedJasm = new HashMap<>(); + private final Map passedJasm = new HashMap<>(); + private final Map failedLoad = new HashMap<>(); + private final Map passedLoad = new HashMap<>(); + private final File compileDir; + + public BruteForceHelper() throws IOException { + this(FRESHLY_BUILT_ASMTOOLS); + } + + public BruteForceHelper(String dir) throws IOException { + this(new SearchingClassProvider(new File(dir))); + } + + public BruteForceHelper(ClassProvider cp) throws IOException { + compileDir = Files.createTempDirectory("JdisJasmWorks").toFile(); + compileDir.deleteOnExit(); + classProvider = cp; + } + + public void work(AsmToolsExecutable diasm, AsmToolsExecutable asm) throws IOException { + List classes = classProvider.getClasses(); + tryAll(classes, failedJdis, passedJdis, diasm); + diasm.ensure(classes, failedJdis); + + tryAll(classes, failedJasm, passedJasm, asm); + asm.ensure(classes, failedJasm); + + AsmToolsExecutable loadClass = new AsmToolsExecutable() { + @Override + public int run(ThreeStringWriters outs, File clazz) throws IOException { + try { + URL url = compileDir.toURI().toURL(); + URL[] urls = new URL[]{url}; + URLClassLoader cl = new URLClassLoader(urls); + String origFile = clazz.toString(); + String fqn = origFile.substring(origFile.indexOf("org/openjdk")). + replaceFirst("\\.class$", ""). + replaceAll("/", "."); + cl.loadClass(fqn); + return 0; + } catch (Exception e) { + e.printStackTrace(outs.getToolOutput()); + return 1; + } + } + + @Override + public void ensure(List all, Map failures) { + Assertions.assertEquals(0, failedLoad.size(), "from " + classes.size() + + " failed to produce valid bytecode " + failedLoad.size() + ": " + keySetToString(failedLoad, getClassesRoot())); + } + }; + tryAll(classes, failedLoad, passedLoad, loadClass); + } + + public static String keySetToString(Map failedJdis, File classesRoot) { + return failedJdis.keySet().stream().map(f -> f.getAbsolutePath().replaceFirst(classesRoot.getAbsolutePath(), "")).collect(Collectors.joining(", ")); + } + + private void tryAll(List classes, Map failed, Map passed, AsmToolsExecutable ex) throws IOException { + for (File clazz : classes) { + ThreeStringWriters outs = new ThreeStringWriters(); + int i = ex.run(outs, clazz); + outs.flush(); + if (i != 0) { + Object o = failed.put(clazz, outs); + Assertions.assertNull(o, " duplicated class - " + o); + System.out.printf("File %s failed\n", clazz); + continue; + } + Object o = passed.put(clazz, outs); + Assertions.assertNull(o, " duplicated class - " + o); + } + for (Map.Entry failure : failed.entrySet().stream().sorted(new Comparator>() { + @Override + public int compare(Map.Entry t0, Map.Entry t1) { + return t0.getKey().compareTo(t1.getKey()); + } + }).collect(Collectors.toList())) { + System.err.println(failure.getKey()); + System.err.println(failure.getValue().getErrorBos()); + System.err.println(failure.getValue().getLoggerBos()); + System.err.println(failure.getValue().getToolBos()); + } + } + + private static List findClasses(File classesRoot) throws IOException { + List classes = new ArrayList<>(); + Files.walkFileTree(classesRoot.toPath(), new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException { + if (path.toString().endsWith(".class") && !excludeSet.contains(path.toFile().getName())) { + classes.add(path.toFile().getAbsoluteFile()); + } + return FileVisitResult.CONTINUE; + } + }); + Assertions.assertNotEquals(0, classes.size(), "There must be more then 0 class compiled in " + classesRoot + " before running this tests!"); + Collections.sort(classes); + return classes; + } + + public String getDecompiledClass(File clazz) { + return passedJdis.get(clazz).getToolBos(); + } + + public File getCompileDir() { + return compileDir; + } + + public File getClassesRoot() { + return classProvider.getClassesRoot(); + } + + public static void createMetadata(ThreeStringWriters outs, File clazz, File savedAsm, File compileDir, File classesRoot) { + outs.getToolOutput().println("Orig: " + clazz.getAbsolutePath()); + outs.getToolOutput().println("To: " + compileDir.getAbsolutePath()); + outs.getToolOutput().println("Base: " + classesRoot.getAbsolutePath()); + outs.getToolOutput().println("From: " + savedAsm.getAbsolutePath()); + } + + public static File saveDecompiledCode(String body, String tmpPRefix) throws IOException { + File savedFresh = File.createTempFile(tmpPRefix, ".java"); + Files.writeString(savedFresh.toPath(), body); + savedFresh.deleteOnExit(); + return savedFresh; + } + + public static class SearchingClassProvider implements ClassProvider { + private final File root; + + public SearchingClassProvider(File root) { + this.root = root.getAbsoluteFile(); + } + + @Override + public File getClassesRoot() { + return root; + } + + @Override + public List getClasses() throws IOException { + return findClasses(root); + } + } + + public interface ClassProvider { + + File getClassesRoot(); + + List getClasses() throws IOException; + } + + public interface AsmToolsExecutable { + + int run(ThreeStringWriters out, File clazz) throws IOException; + + void ensure(List all, Map failures); + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ClassPathClassWork.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ClassPathClassWork.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ClassPathClassWork.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ClassPathClassWork.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +package org.openjdk.asmtools.lib.helper; + +import org.junit.jupiter.api.Assertions; + +import java.io.File; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.regex.Pattern; + +public class ClassPathClassWork { + + protected static Class clazz; + protected static String classFile; + protected static Pattern className; + protected static Pattern packageName; + + public static void initMainClassData(Class testsClass) { + initGenericClassData(testsClass,"classes"); + } + + public static void initTestClassData(Class testsClass) { + initGenericClassData(testsClass,"test-classes"); + } + + private static void initGenericClassData(Class testsClass, String subdir) { + clazz = testsClass; + classFile = "./target/"+subdir+"/" + clazz.getName().replace('.', '/') + ".class"; + Assertions.assertTrue(new File(classFile).exists(), "\"%s\" not found".formatted(Paths.get(classFile).toFile().getAbsolutePath())); + className = Pattern.compile("public .*class .*" + clazz.getSimpleName() + " extends .*"); + packageName = Pattern.compile("package "+clazz.getPackageName() + ";"); + } + + protected String getFile(String fileResource) { + File resourceDir = new File(Objects.requireNonNull(this.getClass().getResource(fileResource)).getFile()).getParentFile(); + return resourceDir + File.separator + new File(fileResource).getName(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ThreeStringWriters.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ThreeStringWriters.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ThreeStringWriters.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/helper/ThreeStringWriters.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +package org.openjdk.asmtools.lib.helper; + +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.PrintWriterOutput; +import org.openjdk.asmtools.common.outputs.log.SingleDualOutputStreamOutput; +import org.openjdk.asmtools.common.outputs.ToolOutput; + +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; + +public class ThreeStringWriters { + private final ByteArrayOutputStream toolBos = new ByteArrayOutputStream(); + private final ByteArrayOutputStream errorBos = new ByteArrayOutputStream(); + private final ByteArrayOutputStream loggerBos = new ByteArrayOutputStream(); + private final PrintWriter toolOutput = new PrintWriter(toolBos); + private final PrintWriter errorOutput = new PrintWriter(errorBos); + private final PrintWriter loggerOutput = new PrintWriter(loggerBos); + + public void flush(){ + toolOutput.flush(); + errorOutput.flush(); + loggerOutput.flush(); + } + + public ToolOutput getToolOutputWrapper() { + return new PrintWriterOutput(toolOutput); + } + public PrintWriter getToolOutput() { + return toolOutput; + } + + public PrintWriter getErrorOutput() { + return errorOutput; + } + + public PrintWriter getLoggerOutput() { + return loggerOutput; + } + + public String getLoggerBos() { + return loggerBos.toString(); + } + + public String getErrorBos() { + return errorBos.toString(); + } + + public String getToolBos() { + return toolBos.toString(); + } + + public DualStreamToolOutput getLoggers() { + return new SingleDualOutputStreamOutput(getErrorOutput()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndBinResults.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndBinResults.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndBinResults.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndBinResults.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.log; + +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; + +public class LogAndBinResults extends LogAndReturn { + + public final ByteOutput output; + + public ByteInput[] getAsByteInput() { + return output.getOutputs().stream().map(out->new ByteInput(out.getBody())).toArray(ByteInput[]::new); + } + + public LogAndBinResults(ByteOutput output, StringLog log, int result) { + super(log, result); + this.output = output; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndReturn.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndReturn.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndReturn.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndReturn.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.log; + +import org.openjdk.asmtools.lib.utility.StringUtils; +import org.openjdk.asmtools.common.outputs.log.StringLog; + +import java.util.List; + +public class LogAndReturn { + + public final StringLog log; + public final int result; + + + public LogAndReturn(StringLog log, int result) { + this.log = log; + this.result = result; + } + + public List getLogStringsByPrefix(String prefix) { + return StringUtils.substrBetween(log.toString(), prefix, System.lineSeparator()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndTextResults.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndTextResults.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndTextResults.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/log/LogAndTextResults.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.log; + +import org.openjdk.asmtools.common.outputs.TextOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; + +import java.util.function.Function; +import java.util.stream.Collectors; + +public class LogAndTextResults extends LogAndReturn { + + public final TextOutput output; + + public LogAndTextResults(TextOutput output, StringLog log, int result) { + super(log, result); + this.output = output; + } + + public String getResultAsString(Function stringTransform) { + return stringTransform.apply(this.output.getOutputs().stream().map(out->out.getBody()).collect(Collectors.joining())); + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/package-info.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/package-info.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Helper frameworks, utilities, base classes designed to support JUnit testing of ASM tools. + */ +package org.openjdk.asmtools.lib; diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/script/TestScript.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/script/TestScript.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/script/TestScript.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/script/TestScript.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,105 @@ +package org.openjdk.asmtools.lib.script; + +import org.junit.jupiter.api.Assertions; +import org.openjdk.asmtools.common.inputs.StringInput; +import org.openjdk.asmtools.lib.action.*; +import org.openjdk.asmtools.lib.log.LogAndBinResults; +import org.openjdk.asmtools.lib.log.LogAndTextResults; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.fail; +import static org.openjdk.asmtools.lib.utility.StringUtils.funcNormalizeText; + +public class TestScript { + protected Jasm jasm = new Jasm(); + private Jcoder jcoder = new Jcoder(); + protected File resourceDir; + protected boolean warningsEnabled = false; + + public void init(String resource) throws IOException { + if (resource == null) { + throw new IOException("Resource not declared"); + } + URL url = this.getClass().getResource(resource); + if (url == null) { + fail("Resource \"%s\" not found.".formatted(resource)); + } + this.resourceDir = new File(url.getFile()).getParentFile(); + if (!this.resourceDir.exists() || !this.resourceDir.isDirectory()) { + fail("Resource directory does not exist or is not a directory: " + this.resourceDir); + } else if (DebugHelper.isDebug()) { + fail("Resource directory initialized: " + this.resourceDir.getAbsolutePath()); + } + } + + public void jasmTest(String resourceName, EToolArguments args, List> tests) { + // jasm to class in memory + // jasm.setDebug(true); + LogAndBinResults binResult = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + if( !warningsEnabled ) + Assertions.assertTrue(binResult.log.toString().isEmpty()); + Assertions.assertEquals(0, binResult.result); + + // class to jasm + LogAndTextResults textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + + Assertions.assertEquals(0, textResult.result); + String jasmText = textResult.getResultAsString(Function.identity()); + String normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // jasm to class + binResult = jasm.compile(new StringInput(jasmText)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + if( !warningsEnabled ) + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jasm + textResult = new Jdis().setArgs(args).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + jasmText = textResult.getResultAsString(Function.identity()); + normJasmText = funcNormalizeText.apply(jasmText); + for (Consumer testConsumer : tests) { + testConsumer.accept(normJasmText); + } + // class to jcod + textResult = new Jdec().setArgs(EToolArguments.JDEC_G).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + // jcod to class + binResult = jcoder.compile(new StringInput(textResult.getResultAsString(Function.identity()))); + Assertions.assertEquals(0, binResult.result); + } + + public void jcoderTest(String resourceName, EToolArguments args, List> tests) { + // jcod to class in memory + LogAndBinResults binResult = jcoder.compile(List.of(resourceDir + File.separator + resourceName)); + // class produced correctly + Assertions.assertEquals(0, binResult.result); + if( !warningsEnabled ) + Assertions.assertTrue(binResult.log.toString().isEmpty()); + // class to jcod + LogAndTextResults textResult = new Jdec().setArgs(args).decode(binResult.getAsByteInput()); + String jcoderText = textResult.getResultAsString(funcNormalizeText); + Assertions.assertEquals(0, textResult.result); + for (Consumer testConsumer : tests) { + testConsumer.accept(jcoderText); + } + // class to jasm twice + textResult = new Jdis().setArgs(EToolArguments.JDIS_G_T_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + textResult = new Jdis().setArgs(EToolArguments.JDIS_GG_NC_LNT_LVT).decode(binResult.getAsByteInput()); + Assertions.assertEquals(0, textResult.result); + } + + protected void enableToolsWarnings() { + this.warningsEnabled = true; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ITestRunner.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ITestRunner.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ITestRunner.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ITestRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform; + +public interface ITestRunner { + void run(); +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ResultChecker.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ResultChecker.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ResultChecker.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/ResultChecker.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform; + + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ResultChecker { + + public static String[] OUT_LINE_PREFIXES_TO_IGNORE = new String[]{ + ":TransformerLoader: " + }; + + // Filter to ignore Logged output lines + static Function filterOut = + s -> Arrays.stream(OUT_LINE_PREFIXES_TO_IGNORE).anyMatch(p -> s.startsWith(p)); + + Class trClass; + + public Optional load() { + try { + Object obj = trClass.getDeclaredConstructor().newInstance(); + return Optional.of(obj); + } catch (InstantiationException | IllegalAccessException | + InvocationTargetException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public void run() { + try { + Object obj = trClass.getDeclaredConstructor().newInstance(); + //default void run() + obj.getClass().getMethod("run").invoke(obj); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | + NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public ResultChecker setTestRunClass(Class trClass) { + this.trClass = trClass; + return this; + } + + /** + * Filters out all trace/debug lines from str using Function filterOut + * + * @param str line that will be split into list by System.lineSeparator() + * @return list of strings + */ + protected List getFilteredList(String str) { + return Arrays.stream(str.split(System.lineSeparator())).filter(s -> !filterOut.apply(s)).toList(); + } + + /** + * Filters out all trace/debug lines from str using Function filterOut + * + * @param str line that will be split into list by System.lineSeparator() + * @return string without lines filtered out + */ + protected String getFilteredString(String str) { + return Arrays.stream(str.split(System.lineSeparator())).filter(s -> !filterOut.apply(s)). + collect(Collectors.joining(System.lineSeparator())); + } + + protected String getPurifiedString(String str) { + for (String s : OUT_LINE_PREFIXES_TO_IGNORE) { + str = str.replaceAll(s, ""); + } + return str; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/TransformLoader.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/TransformLoader.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/TransformLoader.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/TransformLoader.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform; + +import org.junit.jupiter.api.Assertions; +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.inputs.ToolInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput; +import org.openjdk.asmtools.common.outputs.log.StderrLog; +import org.openjdk.asmtools.lib.action.EAsmTool; +import org.openjdk.asmtools.lib.utility.FileUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.function.Function; + +import static java.nio.file.StandardOpenOption.*; +import static org.openjdk.asmtools.lib.action.EAsmTool.*; +import static org.openjdk.asmtools.lib.utility.FileUtils.findFile; + +public class TransformLoader extends ClassLoader { + + public enum TransformRules { + CLASS_LOAD, + JASM_TO_CLASS_LOAD, + JCOD_TO_CLASS_LOAD, + // 2 rules are tightened by the restriction - + // a class, jasm and jcov files are placed in the same directory. + CLASS_TO_JASM_TO_CLASS_LOAD, + CLASS_TO_JCOD_TO_CLASS_LOAD + } + + private static boolean debug; + + static { + registerAsParallelCapable(); + // might affect a test result - Must be false once a development is done + String str = System.getenv("DEBUG"); + str = str == null ? "false" : str; + debug = List.of("true", "on", "yes").stream().anyMatch(str::equalsIgnoreCase); + } + + public static void debugOn() { + debug = true; + } + + public static void debugOff() { + debug = false; + } + + public TransformLoader setToolsOptions(EAsmTool tool, String... options) { + if (options != null && options.length > 0) { + toolsOptions.putIfAbsent(tool, options); + } + return this; + } + + public TransformLoader clearOptions() { + toolsOptions = new HashMap<>(); + return this; + } + + Map toolsOptions = new HashMap<>(); + + static String MSG_PREFIX = ResultChecker.OUT_LINE_PREFIXES_TO_IGNORE[0]; + private TransformRules transformRule = TransformRules.CLASS_LOAD; + + // List of class names that should be loaded in a general way without transformation + private final List excludeList = new ArrayList<>(); + + // Directory for dumping "problem" files created while transforming + private String dumpDir; + + /** + * Specifies whether to delete an interim jcod/jasm file for rules CLASS_TO_JCOD_TO_CLASS_LOAD, + * CLASS_TO_JASM_TO_CLASS_LOAD + */ + boolean deleteInterimFile = false; + + // Should a class be loaded by a custom-ruled loader ? + // Accept a class name and returns true if the class should be dedicated loaded. + private Function transformFilter = name -> name.contains("org.openjdk.asmtools.transform.case"); + + public TransformLoader setTransformFilter(Function transformFilter) { + this.transformFilter = transformFilter; + return this; + } + + // Fill up the exclude list of class names that should be loaded in a general way without transformation + public TransformLoader addToExcludeList(String... fileNames) { + Collections.addAll(excludeList, fileNames); + return this; + } + + public TransformLoader clearExcludeList() { + excludeList.clear(); + return this; + } + + public TransformLoader setTransformRule(TransformRules transformRule) { + this.transformRule = transformRule; + return this; + } + + public TransformLoader setDeleteInterimFile(boolean deleteInterimFile) { + this.deleteInterimFile = deleteInterimFile; + return this; + } + + // Directory where class files for loading classes are placed + private String classDir; + + // Parent class loader for delegation class loading + protected ClassLoader parentCL; + + public TransformLoader() { + super(); + parentCL = getSystemClassLoader(); + setClassDir(""); + } + + public TransformLoader(ClassLoader cl) { + super(cl); + parentCL = cl; + setClassDir(""); + } + + @Override + public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class loadedCode; + println("Trying to load class: " + name + " using rule " + transformRule); + try { + // Simple criteria to define what classes should be loaded according to specified transform rule + if (transformFilter.apply(name)) { + synchronized (getClassLoadingLock(name)) { + loadedCode = findLoadedClass(name); + if (loadedCode == null) { + String fileName = name.replace('.', File.separatorChar); + if (excludeList.contains(name)) { + loadedCode = loadClassFromClassFile(name, checkFile(fileName + ".class")); + } else { + loadedCode = switch (transformRule) { + case JCOD_TO_CLASS_LOAD -> loadClassFromResourceJcodFile(name); + case JASM_TO_CLASS_LOAD -> loadClassFromResourceJasmFile(name); + case CLASS_TO_JASM_TO_CLASS_LOAD -> + loadClassFromGeneratedJasmFile(name, checkFile(fileName + ".class")); + case CLASS_TO_JCOD_TO_CLASS_LOAD -> + loadClassFromGeneratedJcodFile(name, checkFile(fileName + ".class")); + case CLASS_LOAD -> loadClassFromClassFile(name, checkFile(fileName + ".class")); + }; + } + } else { + println("Object of the Class " + name + " found"); + } + if (resolve) { + resolveClass(loadedCode); + } + } + } else { + println("[Delegate " + name + " to default parent.]"); + loadedCode = parentCL.loadClass(name); + } + } catch (Exception d) { + d.printStackTrace(); + throw new ClassNotFoundException(); + } + + if (loadedCode != null) { + return loadedCode; + } else { + throw new ClassNotFoundException(); + } + } + + /** + * Loads a class from a byte buffer and optionally instantiates it. + * + * @param name The name of the class. + * @param buffer The byte buffer containing the class definition. + * @param instantiate Whether to instantiate the class. + * @param The type of the class. + * @return An Optional containing the class or an instance of the class. + */ + public Optional loadClassFromBuffer(String name, byte[] buffer, boolean instantiate) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + if (name == null || buffer == null) { + throw new IllegalArgumentException("Name and buffer must not be null"); + } + + try { + long byteCount = buffer.length; + Class clazz = defineClass(name, buffer); + println("[Loaded {%s} from buffer ({%d} bytes)]".formatted(name, byteCount)); + + if (instantiate) { + T instance = (T) clazz.getDeclaredConstructor().newInstance(); + return Optional.of(instance); + } else { + return Optional.of((T) clazz); + } + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + throw e; + } + } + + public TransformLoader setClassDir(String classDir) { + this.classDir = Paths.get(classDir).toAbsolutePath().toString(); + return this; + } + + public TransformLoader setDumpDir(String dumpDir) { + if (TransformLoader.debug) { + this.dumpDir = dumpDir; + } + return this; + } + + + /** + * Transition: class file -> jcod file -> class file as byte array in memory -> load + */ + protected Class loadClassFromGeneratedJcodFile(String className, File classFile) throws ClassNotFoundException, IOException { + File jcodFile = checkOrCreate(classFile, new File(classFile.toString().concat(JCODER.getFileExtension()))); + byte[] jcodFileBuf = FileUtils.getBinaryFile(jcodFile); + Class cl = loadJcodBytes(className, jcodFileBuf); + if (deleteInterimFile && transformRule == TransformRules.CLASS_TO_JCOD_TO_CLASS_LOAD) { + Files.delete(jcodFile.toPath()); + } + println("[Loaded " + className + " from file " + jcodFile + " (" + jcodFileBuf.length + " bytes)]"); + return cl; + } + + /** + * Transition: Resources jcod file -> class file as byte array in memory -> load + */ + private Class loadClassFromResourceJcodFile(String className) throws IOException { + String resourceName = String.format("/%s.class%s", className.replaceAll("\\.", "/"), JCODER.getFileExtension()); + byte[] jcodFileBuf = FileUtils.getResourceFile(resourceName); + Class cl = loadJcodBytes(className, jcodFileBuf); + println("[Loaded " + className + " from resource " + resourceName + " (" + jcodFileBuf.length + " bytes)]"); + return cl; + } + + /** + * Transition: class file -> jasm file -> class file as byte array in memory -> load + */ + protected Class loadClassFromGeneratedJasmFile(String className, File classFile) throws ClassNotFoundException, IOException { + File jasmFile = checkOrCreate(classFile, new File(classFile.toString().concat(JASM.getFileExtension()))); + byte[] jasmFileBuf = FileUtils.getBinaryFile(jasmFile); + Class cl = loadJasmBytes(className, jasmFileBuf); + if (deleteInterimFile && transformRule == TransformRules.CLASS_TO_JASM_TO_CLASS_LOAD) { + Files.delete(jasmFile.toPath()); + } + println("[Loaded " + className + " from file " + jasmFile + " (" + jasmFileBuf.length + " bytes)]"); + return cl; + } + + /** + * Transition: Resources jasm file -> class file as byte array in memory -> load + */ + private Class loadClassFromResourceJasmFile(String className) throws IOException { + String resourceName = String.format("/%s.class%s", className.replaceAll("\\.", "/"), JASM.getFileExtension()); + byte[] jasmFileBuf = FileUtils.getResourceFile(resourceName); + Class cl = loadJasmBytes(className, jasmFileBuf); + println("[Loaded " + className + " from resource " + resourceName + " (" + jasmFileBuf.length + " bytes)]"); + return cl; + } + + private Class loadJcodBytes(String className, byte[] jcodFileBuf) { + ToolInput toolInput = new ByteInput(jcodFileBuf); + ByteOutput output = new ByteOutput(); + DualStreamToolOutput log = new StderrLog(); + org.openjdk.asmtools.jcoder.Main jcod = toolsOptions.containsKey(JCODER) + ? new org.openjdk.asmtools.jcoder.Main(output, log, toolInput, toolsOptions.get(JCODER)) + : new org.openjdk.asmtools.jcoder.Main(output, log, toolInput); + int i = jcod.compile(); + Assertions.assertEquals(0, i); + Assertions.assertEquals(1, output.getOutputs().size()); + byte[] buffer = output.getOutputs().get(0).getBody(); + Class c = defineClass(className, buffer); + return c; + } + + private Class loadJasmBytes(String className, byte[] jasmFileBuf) { + ToolInput toolInput = new ByteInput(jasmFileBuf); + ByteOutput output = new ByteOutput(); + DualStreamToolOutput log = new StderrLog(); + org.openjdk.asmtools.jasm.Main jasm = toolsOptions.containsKey(JASM) + ? new org.openjdk.asmtools.jasm.Main(output, log, toolInput, toolsOptions.get(JASM)) + : new org.openjdk.asmtools.jasm.Main(output, log, toolInput); + int i = jasm.compile(); + Assertions.assertEquals(0, i); + Assertions.assertEquals(1, output.getOutputs().size()); + byte[] buffer = output.getOutputs().get(0).getBody(); + Class c = defineClass(className, buffer); + return c; + + } + + private void createJcodFile(File classFile, File jcodFile) throws ClassNotFoundException, IOException { + final ToolInput toolInput = new ByteInput(FileUtils.getBinaryFile(classFile)); + ByteOutput output = new ByteOutput(); + org.openjdk.asmtools.jdec.Main decoder = toolsOptions.containsKey(JDEC) + ? new org.openjdk.asmtools.jdec.Main(output, new StderrLog(), toolInput, toolsOptions.get(JDEC)) + : new org.openjdk.asmtools.jdec.Main(output, new StderrLog(), toolInput); + decoder.decode(); + byte[] buffer = output.getOutputs().get(0).getBody(); + Files.write(jcodFile.toPath(), buffer, WRITE, CREATE, TRUNCATE_EXISTING); + } + + private void createJasmFile(File classFile, File jasmFile) throws ClassNotFoundException, IOException { + final ToolInput toolInput = new ByteInput(FileUtils.getBinaryFile(classFile)); + ByteOutput output = new ByteOutput(); + org.openjdk.asmtools.jdis.Main compiler = toolsOptions.containsKey(JDIS) + ? new org.openjdk.asmtools.jdis.Main(output, new StderrLog(), toolInput, toolsOptions.get(JDIS)) + : new org.openjdk.asmtools.jdis.Main(output, new StderrLog(), toolInput); + compiler.disasm(); + byte[] buffer = output.getOutputs().get(0).getBody(); + Files.write(jasmFile.toPath(), buffer, WRITE, CREATE, TRUNCATE_EXISTING); + } + + + protected Class loadClassFromClassFile(String name, File file) throws ClassNotFoundException { + byte[] buffer = FileUtils.getBinaryFile(file); + long byteCount = buffer.length; + Class c = defineClass(name, buffer); + println("[Loaded " + name + " from " + file + " (" + byteCount + " bytes)]"); + return c; + } + + private Class defineClass(String name, byte[] buffer) { + Class c; + long byteCount = buffer.length; + try { + c = defineClass(name, buffer, 0, (int) byteCount); + } catch (ClassFormatError cfe) { + if (TransformLoader.debug) + printError("ClassFormatError: " + cfe.getMessage()); + throw cfe; + } catch (ClassCircularityError e) { + printError("ClassCircularityError is caught!"); + throw e; + } catch (LinkageError e) { + println("Linkage error during defining class \"" + name + "\": "); + printError(e.getClass().getName() + ": " + e.getMessage()); + // dump binaries + if (TransformLoader.debug) { + int idx = name.lastIndexOf('.'); + Path dumpFile = Path.of(dumpDir, name.substring(idx == -1 ? 0 : idx + 1) + ".class.dump"); + try { + Files.write(dumpFile, buffer, CREATE, WRITE, TRUNCATE_EXISTING); + } catch (IOException ex) { + printError("Cannot write ato dump file \"" + dumpFile + "\": " + ex.getMessage()); + } + } + throw e; + } + return c; + } + + private File checkFile(String fileName) throws FileNotFoundException { + File file = new File(classDir + File.separator + fileName); + if (file.exists()) { + return file; + } + Optional filePath = findFile(classDir, fileName, this::println); + if (filePath.isEmpty()) { + printError("Can't find file: " + file); + throw new java.io.FileNotFoundException(); + } + return filePath.get().toFile(); + } + + private File checkOrCreate(File classFile, File toolFile) throws ClassNotFoundException, IOException { + if (!toolFile.exists() || deleteInterimFile) { + if (toolFile.getName().endsWith(JCODER.getFileExtension())) + createJcodFile(classFile, toolFile); + else if (toolFile.getName().endsWith(JASM.getFileExtension())) + createJasmFile(classFile, toolFile); + else + throw new RuntimeException("A tool is not defined to create the file " + toolFile); + } + return toolFile; + } + + /** + * Print error message with the prefix to filter out while analysing System error log + */ + private void printError(String s) { + System.err.println((TransformLoader.debug ? MSG_PREFIX : "") + s); + System.err.flush(); + } + + /** + * Print debug message with the prefix to filter out while analysing System output log + */ + private void println(String s) { + if (TransformLoader.debug) { + System.out.printf("%s %s: %s%n", MSG_PREFIX, Thread.currentThread().getName(), s); + System.out.flush(); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/AsmtoolsType.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/AsmtoolsType.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/AsmtoolsType.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/AsmtoolsType.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +public class AsmtoolsType { + private final FileType type; + private final boolean isFirstInput; + private Pipeline.Status status; + + public AsmtoolsType(Pipeline.Status status, FileType type, boolean isFirstInput) { + this.status = status; + this.type = type; + this.isFirstInput = isFirstInput; + } + + public AsmtoolsType(Pipeline.Status status, FileType type) { + this(status, type, false); + } + + public boolean firstInput() { + return isFirstInput; + } + + public void setRecord(Pipeline.Status status) { + this.status = status; + } + + public Pipeline.Status record() { + return status; + } + + @Override + public String toString() { + return type + "{" + + "status=" + status + + ", isFirstInput=" + isFirstInput + + '}'; + } + + enum FileType { + JCOD(".jcod"), JASM(".jasm"), JAVA(".java"), CLAZZ(".class"); + private final String ext; + + FileType(String ext) { + this.ext = ext; + } + + public String extension() { + return ext; + } + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJasmConverter.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJasmConverter.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJasmConverter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJasmConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.asmtools.lib.transform.pipeline; + +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; +import org.openjdk.asmtools.jdis.Main; +import org.openjdk.asmtools.lib.utility.FileUtils; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Function; + +import static org.openjdk.asmtools.lib.transform.pipeline.AsmtoolsType.FileType.JASM; +import static org.openjdk.asmtools.lib.transform.pipeline.Pipeline.*; + +public class ClassToJasmConverter extends Converter implements Function { + private static final String DEFAULT_STAGE_NAME = "ClassToJasm"; + private static final String JDIS_DETAILED_OUTPUT = "-g"; + + public ClassToJasmConverter(String stageName) { + super(Objects.requireNonNullElse(stageName, DEFAULT_STAGE_NAME)); + } + + public ClassToJasmConverter() { + this(null); + } + + + @Override + public Jasm apply(Clazz incoming) { + + logInfo("Generating: class -> jasm"); + Objects.requireNonNull(incoming, "Incoming Clazz cannot be null"); + + logDebug(stageName(), incoming.firstInput() ? "Received first input: " + incoming : "Received from previous stage: " + incoming); + + if (!incoming.firstInput() && incoming.record().toolReturn() != SUCCESS) { + return handleError("Previous stage failed", incoming, incoming.record().log(), incoming.record().toolReturn()); + } + + if (incoming.record().file() == null) { + return handleError("Incoming Clazz file is null", incoming, null, -1); + } + + try { + byte[] clazzBytes = FileUtils.readBytesFromFile(incoming.record().file()); + ByteOutput output = new ByteOutput(); + StringLog log = new StringLog(); + Main compiler = new Main(output, log, new ByteInput(clazzBytes), JDIS_DETAILED_OUTPUT); + int result = compiler.disasm(); + + if (result != SUCCESS) { + return handleError(stageName() + " failed.", incoming, log, result); + } + + if (output.getOutputs() == null || output.getOutputs().isEmpty() || output.getOutputs().get(0) == null) { + return handleError("jdis ToolOutput not available", incoming, null, result); + } + + logDebug(stageName(), "jdis succeeded."); + Path classFilePath = FileUtils.writeBytesToFile("temp", JASM.extension(), output.getOutputs().get(0).getBody()); + Jasm r = handleOutput(incoming, classFilePath, log, result, output); + logDebug(stageName(), "Sending next stage: " + r); + return r; + } catch (IOException e) { + throw new RuntimeException("Failed to convert JASM to CLASS", e); + } + } + + protected Jasm handleError(String errorMessage, Clazz type, StringLog log, int result) { + logWarn(errorMessage); + Pipeline.Status status = new Pipeline.Status(stageName(), type.record().file(), log, result, null); + setRecord(status); + return new Jasm(status); + } + + protected Jasm handleOutput(Clazz type, Path classFilePath, StringLog log, int result, ByteOutput output) { + Pipeline.Status status = new Pipeline.Status(stageName(), classFilePath, log, result, output); + setRecord(status); + return new Jasm(status); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJcodConverter.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJcodConverter.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJcodConverter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/ClassToJcodConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.asmtools.lib.transform.pipeline; + +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; +import org.openjdk.asmtools.jdec.Main; +import org.openjdk.asmtools.lib.utility.FileUtils; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Function; + +import static org.openjdk.asmtools.lib.transform.pipeline.AsmtoolsType.FileType.JCOD; +import static org.openjdk.asmtools.lib.transform.pipeline.Pipeline.*; + +public class ClassToJcodConverter extends Converter implements Function { + private static final String DEFAULT_STAGE_NAME = "ClassToJcod"; + + public ClassToJcodConverter(String stageName) { + super(Objects.requireNonNullElse(stageName, DEFAULT_STAGE_NAME)); + } + + public ClassToJcodConverter() { + this(null); + } + + @Override + public Jcod apply(Clazz incoming) { + logInfo("Generating: class -> jcod"); + Objects.requireNonNull(incoming, "Incoming Jcod cannot be null"); + + if (incoming.firstInput()) { + logDebug(stageName(), "Received first input: " + incoming); + } else { + logDebug(stageName(), "Received from previous stage: " + incoming); + } + + if (!incoming.firstInput() && incoming.record().toolReturn() != SUCCESS) { + logWarn(stageName(), "Previous stage failed. Delegating..."); + return handleError("Previous stage failed", incoming, incoming.record().log(), incoming.record().toolReturn()); + } + + if (incoming.record().file() == null) { + return handleError("Incoming Clazz file is null", incoming, null, -1); + } + + try { + byte[] classBytes = FileUtils.readBytesFromFile(incoming.record().file()); + ByteOutput output = new ByteOutput(); + StringLog log = new StringLog(); + Main compiler = new Main(output, log, new ByteInput(classBytes)); + int result = compiler.decode(); + if (result != SUCCESS) { + return handleError(stageName() + " failed.", incoming, log, result); + } + if (output.getOutputs() == null || output.getOutputs().isEmpty() || output.getOutputs().get(0) == null) { + return handleError("jdec ToolOutput not available", incoming, log, result); + } else { + logDebug(stageName(), "jdec succeeded."); + } + Path jcodFilePath = FileUtils.writeBytesToFile("temp", JCOD.extension(), output.getOutputs().get(0).getBody()); + Jcod r = new Jcod(new Pipeline.Status(stageName(), jcodFilePath, log, result, output)); + logDebug(stageName(), "Sending next stage: " + r); + return r; + } catch (IOException e) { + throw new RuntimeException("Failed to convert CLASS to JCOD", e); + } + } + + protected Jcod handleError(String errorMessage, Clazz type, StringLog log, int result) { + logWarn(errorMessage); + Pipeline.Status status = new Pipeline.Status(stageName(), type.record().file(), log, result, null); + setRecord(status); + return new Jcod(status); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Clazz.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Clazz.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Clazz.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Clazz.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +public class Clazz extends AsmtoolsType { + + public Clazz(Pipeline.Status status) { + super(status, FileType.CLAZZ); + } + + public Clazz(Pipeline.Status status, boolean isInput) { + super(status, FileType.CLAZZ, isInput); + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Converter.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Converter.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Converter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Converter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +import org.openjdk.asmtools.common.outputs.log.StringLog; + +public class Converter { + + private Pipeline.Status record; + private final String stageName; + private StringLog log; + + public Converter(String stageName) { + this.stageName = stageName; + this.log = new StringLog(); + } + + public StringLog log() { + return log; + } + + public Converter setLog(StringLog log) { + this.log = log; + return this; + } + + public String stageName() { + return stageName; + } + + public Pipeline.Status record() { + return record; + } + + public Converter setRecord(Pipeline.Status record) { + this.record = record; + return this; + } + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jasm.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jasm.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jasm.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jasm.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +public class Jasm extends AsmtoolsType { + + public Jasm(Pipeline.Status status) { + super(status, FileType.JASM); + } + + public Jasm(Pipeline.Status status, boolean isInput) { + super(status, FileType.JASM, isInput); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JasmToClassConverter.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JasmToClassConverter.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JasmToClassConverter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JasmToClassConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; +import org.openjdk.asmtools.jasm.Main; +import org.openjdk.asmtools.lib.utility.FileUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Function; + +import static org.openjdk.asmtools.lib.transform.pipeline.AsmtoolsType.FileType.CLAZZ; +import static org.openjdk.asmtools.lib.transform.pipeline.Pipeline.*; + +public class JasmToClassConverter extends Converter implements Function { + private static final String DEFAULT_STAGE_NAME = "JcodToClass"; + + public JasmToClassConverter(String stageName) { + super(Objects.requireNonNullElse(stageName, DEFAULT_STAGE_NAME)); + } + + public JasmToClassConverter() { + this(null); + } + + @Override + public Clazz apply(Jasm incoming) { + logInfo("Compiling: jasm -> class"); + Objects.requireNonNull(incoming, "Incoming Jcod cannot be null"); + + if (incoming.firstInput()) { + logDebug(stageName(), "Received first input: " + incoming); + } else { + logDebug(stageName(), "Received from previous stage: " + incoming); + } + + if (!incoming.firstInput() && incoming.record().toolReturn() != SUCCESS) { + logWarn(stageName(), "Previous stage failed. Delegating..."); + return handleError("Previous stage failed", incoming, incoming.record().log(), incoming.record().toolReturn()); + } + + if (incoming.record().file() == null || !Files.exists(incoming.record().file()) || !Files.isRegularFile(incoming.record().file())) { + return handleError("Incoming Jasm file is null", incoming, null, -1); + } + try { + byte[] jasmBytes = FileUtils.readBytesFromFile(incoming.record().file()); + ByteOutput output = new ByteOutput(); + StringLog log = new StringLog(); + Main compiler = new Main(output, log, new ByteInput(jasmBytes)); + int result = compiler.compile(); + if (result != SUCCESS) { + return handleError(stageName() + " failed.", incoming, log, result); + } + if (output.getOutputs() == null || output.getOutputs().isEmpty() || output.getOutputs().get(0) == null) { + return handleError("jasm ToolOutput not available", incoming, log, result); + + } + logDebug(stageName(), "jasm succeeded."); + Path classFilePath = FileUtils.writeBytesToFile("temp", CLAZZ.extension(), output.getOutputs().get(0).getBody()); + Clazz r = new Clazz(new Pipeline.Status(stageName(), classFilePath, log, result, output)); + logDebug(stageName(), "Sending next stage: " + r); + return r; + } catch (IOException e) { + throw new RuntimeException("Failed to convert JASM to CLASS", e); + } + } + + protected Clazz handleError(String errorMessage, Jasm type, StringLog log, int result) { + logWarn(errorMessage); + Pipeline.Status status = new Pipeline.Status(stageName(), type.record().file(), log, result, null); + setRecord(status); + return new Clazz(status); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jcod.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jcod.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jcod.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Jcod.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +public class Jcod extends AsmtoolsType { + + public Jcod(Pipeline.Status status) { + super(status, FileType.JCOD); + } + + public Jcod(Pipeline.Status status, boolean isInput) { + super(status, FileType.JCOD, isInput); + } +} + diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JcodToClassConverter.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JcodToClassConverter.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JcodToClassConverter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/JcodToClassConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +import org.openjdk.asmtools.common.inputs.ByteInput; +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; +import org.openjdk.asmtools.jcoder.Main; +import org.openjdk.asmtools.lib.utility.FileUtils; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Function; + +import static org.openjdk.asmtools.lib.transform.pipeline.AsmtoolsType.FileType.CLAZZ; +import static org.openjdk.asmtools.lib.transform.pipeline.Pipeline.*; + +public class JcodToClassConverter extends Converter implements Function { + private static final String DEFAULT_STAGE_NAME = "JcodToClass"; + + public JcodToClassConverter(String stageName) { + super(Objects.requireNonNullElse(stageName, DEFAULT_STAGE_NAME)); + } + + public JcodToClassConverter() { + this(null); + } + + @Override + public Clazz apply(Jcod incoming) { + logInfo("Compiling: jcod -> class"); + Objects.requireNonNull(incoming, "Incoming Jcod cannot be null"); + + if (incoming.firstInput()) { + logDebug(stageName(), "Received first input: " + incoming); + } else { + logDebug(stageName(), "Received from previous stage: " + incoming); + } + + if (!incoming.firstInput() && incoming.record().toolReturn() != SUCCESS) { + logWarn(stageName(), "Previous stage failed. Delegating..."); + return handleError("Previous stage failed", incoming, null, -1); + } + + if (incoming.record().file() == null) { + return handleError("Incoming JCod file is null", incoming, null, -1); + } + try { + byte[] jcodBytes = FileUtils.readBytesFromFile(incoming.record().file()); + ByteOutput output = new ByteOutput(); + StringLog log = new StringLog(); + Main compiler = new Main(output, log, new ByteInput(jcodBytes)); + int result = compiler.compile(); + if (result != SUCCESS) { + return handleError(stageName() + " failed.", incoming, log, result); + } + if (output.getOutputs() == null || output.getOutputs().isEmpty() || output.getOutputs().get(0) == null) { + return handleError("jcoder ToolOutput not available", incoming, null, result); + + } + logDebug(stageName(), "jcoder succeeded."); + Path classFilePath = FileUtils.writeBytesToFile("temp", CLAZZ.extension(), output.getOutputs().get(0).getBody()); + Clazz r = new Clazz(new Status(stageName(), classFilePath, log, result, output)); + logDebug(stageName(), "Sending next stage: " + r); + return r; + } catch (IOException e) { + throw new RuntimeException("Failed to convert JCOD to CLASS", e); + } + } + + protected Clazz handleError(String errorMessage, Jcod type, StringLog log, int result) { + logWarn(errorMessage); + Pipeline.Status status = new Pipeline.Status(stageName(), type.record().file(), log, result, null); + setRecord(status); + return new Clazz(status); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Pipeline.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Pipeline.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Pipeline.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/Pipeline.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +import org.openjdk.asmtools.common.outputs.ByteOutput; +import org.openjdk.asmtools.common.outputs.log.StringLog; + +import java.nio.file.Path; +import java.util.function.Function; + +public class Pipeline { + static final int SUCCESS = 0; + static final int INIT_STAGE = 65_535; + static final String CLASS_EXT = ".class"; + static final String JASM_EXT = ".jasm"; + static final String JCOD_EXT = ".jcod"; + static final String JAVA_EXT = ".java"; + private static final boolean DEBUG = false; + private static final boolean WARN = false; + private final Function currentStage; + + public Pipeline(Function initialStage) { + this.currentStage = initialStage; + } + + static void logDebug(String context, String msg) { + if (DEBUG) + System.out.printf("DEBUG: <%s> [%s]%n", context, msg); + } + + static void logWarn(String context, String msg) { + if (WARN) + System.out.printf("WARN : <%s> [%s]%n", context, msg); + } + + static void logWarn(String msg) { + if (WARN) + System.out.printf("WARN : [%s]%n", msg); + } + + static void logInfo(String msg) { + if (WARN) + System.out.printf("INFO : [%s]%n", msg); + } + + + public Pipeline addStage(Function nextStage) { + return new Pipeline<>(input -> nextStage.apply(currentStage.apply(input))); + } + + public R execute(T input) { + return currentStage.apply(input); + } + + public record Status(String stage, Path file, StringLog log, int toolReturn, ByteOutput byteOutput) { + public Status(Path file) { + this(null, file, null, -1, null); + } + + public Status(StringLog log) { + this(null, null, log, -1, null); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/TestPipeline.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/TestPipeline.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/TestPipeline.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/transform/pipeline/TestPipeline.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.transform.pipeline; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.*; +import static org.openjdk.asmtools.lib.transform.pipeline.Pipeline.SUCCESS; +import static org.openjdk.asmtools.lib.transform.pipeline.Pipeline.logInfo; + +/** + * Class to play around pipeline implementation + */ +public class TestPipeline { + JcodToClassConverter jcodToClass = new JcodToClassConverter("jcodToClass"); + ClassToJasmConverter classToJasm = new ClassToJasmConverter("classToJasm"); + JasmToClassConverter jasmToClass = new JasmToClassConverter("jasmToClass"); + ClassToJcodConverter classToJcod = new ClassToJcodConverter("classToJcod"); + JcodToClassConverter jcodToClass2 = new JcodToClassConverter("jcodToClass_2"); + + private static String getInputFile(String fileName) { + String resourceName = String.format("/jcod-files/%s", fileName); + File resourceDir = new File(Objects.requireNonNull(TestPipeline.class.getResource(resourceName)).getFile()).getParentFile(); + return resourceDir + File.separator + fileName; + } + + @Test + public void testJcodClass01() { + Pipeline pipeline = new Pipeline<>(jcodToClass); + + // Input file + String jcodFileName = "atrcvl00101m10p.jcod"; + Jcod jcodInput = new Jcod(new Pipeline.Status(Path.of(getInputFile(jcodFileName))), true); + + // Execute the pipeline + Clazz finalOutput = pipeline.execute(jcodInput); + + // Output the result + logInfo("Final output file: " + finalOutput); + assertTrue(finalOutput.record().log().toString().isEmpty()); + assertEquals(SUCCESS, finalOutput.record().toolReturn()); + assertTrue(jcodToClass.log().toString().isEmpty()); + } + + @Test + public void testJcodClass02() { + Pipeline pipeline = new Pipeline<>(jcodToClass); + + // Input file + String jcodFileName = "atrcvl00101m10p.jcod"; + + // Execute the pipeline + assertThrows(NullPointerException.class, () -> pipeline.execute(null)); + } + + @Test + public void testJcodClass03() { + JcodToClassConverter j2c = new JcodToClassConverter(); + Pipeline pipeline = new Pipeline<>(jcodToClass); + + // Input file + String jcodFileName = "abc.txt"; + Jcod jcodInput = new Jcod(new Pipeline.Status(Path.of(getInputFile(jcodFileName))), true); + + // Execute the pipeline + Clazz finalOutput = pipeline.execute(jcodInput); + + // Output the result + assertFalse(finalOutput.record().log().toString().isEmpty()); + assertNotEquals(SUCCESS, finalOutput.record().toolReturn()); + assertFalse(jcodToClass.record().log().toString().isEmpty()); + } + + @Test + public void testJasmClass01() { + Pipeline pipeline = new Pipeline<>(jasmToClass); + + // Input file + String jasmFileName = "atrcvl00101m10p.jasm"; + + // Execute the pipeline + Clazz finalOutput = pipeline.execute(new Jasm(new Pipeline.Status(Path.of(getInputFile(jasmFileName))), true)); + + // Output the result + logInfo("Final output file: " + finalOutput.record().file()); + assertTrue(jasmToClass.log().toString().isEmpty()); + assertEquals(SUCCESS, finalOutput.record().toolReturn()); + } + + @Test + public void testJasmClassJcod() { + Pipeline pipeline = new Pipeline<>(jasmToClass).addStage(classToJcod); + + // Input file + String jasmFileName = "atrcvl00101m10p.jasm"; + jasmFileName = "abc.txt"; + Jasm input = new Jasm(new Pipeline.Status(Path.of(getInputFile(jasmFileName)))); + + // Execute the pipeline + Jcod finalOutput = pipeline.execute(input); + + // Output the result + logInfo("Final output file: " + finalOutput); + } + + @Test + public void testJcodClassJasmClassJcodClass() { + JcodToClassConverter jcodToClass = new JcodToClassConverter(); + ClassToJasmConverter classToJasm = new ClassToJasmConverter(); + JasmToClassConverter jasmToClass = new JasmToClassConverter(); + ClassToJcodConverter classToJcod = new ClassToJcodConverter(); + JcodToClassConverter jcodToClass2 = new JcodToClassConverter(); + + // Define the pipeline + Pipeline pipeline = new Pipeline<>(jcodToClass) + .addStage(classToJasm) + .addStage(jasmToClass) + .addStage(classToJcod) + .addStage(jcodToClass2); + + // Input file + String jcodFileName = "atrcvl00101m10p.jcod"; + + Path jcodFilePath = Path.of(getInputFile(jcodFileName)); + Jcod jcodInput = new Jcod(new Pipeline.Status(jcodFilePath)); + + // Execute the pipeline + Clazz finalOutput = pipeline.execute(jcodInput); + + // Output the result + logInfo("Final output file: " + finalOutput.record().file()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/FileUtils.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/FileUtils.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/FileUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/FileUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.utility; + +import org.junit.jupiter.api.Assertions; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.Stream; + +public class FileUtils { + + public static byte[] readBytesFromFile(Path filePath) throws IOException { + return Files.readAllBytes(filePath); + } + + public static Path writeBytesToFile(String prefix, String suffix, byte[] bytes) throws IOException { + Path tempFile = Files.createTempFile(prefix, suffix); + Files.write(tempFile, bytes, StandardOpenOption.WRITE); + return tempFile; + } + + public static File getResourceFilePath(Class cls, String relativePath) { + return new File(cls.getResource(relativePath).getFile()); + } + + public static byte[] getResourceFile(String s) throws IOException { + byte[] bytes; + try (InputStream is = FileUtils.class.getResourceAsStream(s)) { + bytes = is.readAllBytes(); + Assertions.assertNotNull(bytes); + } catch (Exception ex) { + System.err.println("Can't get resource file " + s); + throw ex; + } + return bytes; + } + + public static byte[] getBinaryFile(File file) throws ClassNotFoundException { + long byteCount = file.length(); + byte[] bytes = new byte[(int) byteCount]; + try { + FileInputStream f = new FileInputStream(file); + f.read(bytes); + f.close(); + } catch (Exception e) { + throw new ClassNotFoundException(); + } + Assertions.assertNotNull(bytes); + return bytes; + } + + public static String getStringFile(File file) throws ClassNotFoundException { + byte[] bytes = getBinaryFile(file); + String str = new String(bytes, StandardCharsets.UTF_8); + Assertions.assertNotNull(str); + return str; + } + + public static Optional findFile(String root, String fileName, Consumer printer) { + try ( + Stream stream = Files.find(Paths.get(root), 20, + (path, attr) -> path.toString().endsWith(fileName))) { + return stream.findAny(); + } catch (IOException e) { + printer.accept(e.getMessage()); + } + return Optional.empty(); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/StringUtils.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/StringUtils.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/StringUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/lib/utility/StringUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.lib.utility; + +import org.openjdk.asmtools.lib.action.DebugHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.IntStream; + +public class StringUtils { + + + + public static BiFunction funcSubStrCount = (text, subStr) -> { + Long count =IntStream.range(0, text.length() - subStr.length() + 1) + .filter(i -> text.substring(i, i + subStr.length()).equals(subStr)) + .count(); + if(DebugHelper.isDebug()) { + System.out.println("count(\"%s\") = %d".formatted(subStr, count)); + } + return count; + }; + + public static Function funcNormalizeText = s -> s.replaceAll("[\\r\\n]+", "") + .replaceAll("\\t", " ").replaceAll(" {2,}", " "); + + public static List substrBetween(final String str, final String startStr, final String endStr) { + if (isEmpty(str) || isEmpty(startStr) || isEmpty(endStr)) { + return new ArrayList<>(); + } + final int strLen = str.length(); + final int startLen = endStr.length(); + final int endLen = startStr.length(); + final List list = new ArrayList<>(); + int pos = 0; + while (pos < strLen - startLen) { + int start = str.indexOf(startStr, pos); + if (start < 0) + break; + start += endLen; + final int end = str.indexOf(endStr, start); + if (end < 0) + break; + list.add(str.substring(start, end)); + pos = end + startLen; + } + return list; + } + + public static boolean isEmpty(String s) { + return s == null || s.isEmpty(); + } + + public static String[] addTail(String[] elements, String... extras) { + int length = extras.length; + if (length == 0) { + return elements; + } + String[] result = new String[elements.length + length]; + System.arraycopy(elements, 0, result, 0, elements.length); + System.arraycopy(extras, 0, result, elements.length, length); + return result; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/structure/ClassFile/ClassFileTests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/structure/ClassFile/ClassFileTests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/structure/ClassFile/ClassFileTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/structure/ClassFile/ClassFileTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.structure.ClassFile; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openjdk.asmtools.common.structure.CFVersion; +import org.openjdk.asmtools.lib.action.Jasm; +import org.openjdk.asmtools.lib.log.LogAndBinResults; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.stream.Stream; + +import static org.openjdk.asmtools.lib.utility.StringUtils.funcSubStrCount; + +/** + * This is the test for class/interface/field modifiers. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class ClassFileTests { + private Jasm jasm = new Jasm(); + private File resourceDir; + + private static Stream getTestParameters() { + return Stream.of( + // jasm + Arguments.of("ClassFile00.jasm", + List.of("\"ACC_VALUE, ACC_PUBLIC\": If the ACC_INTERFACE flag is not set a value class must have at least one of its ACC_FINAL, ACC_IDENTITY, or ACC_ABSTRACT flags set", + "Class file version 69:0 does not conform to the new kind of objects; expected version")), + Arguments.of("ClassFile01.jasm", + List.of("Class file version 69:0 does not conform to the new kind of objects; expected version")), + + Arguments.of("ClassFile02.jasm", + List.of("Class file version not specified in file or by -cv parameter. Defaulting to version \"%s\"". + formatted(CFVersion.ValueObjectsVersion().asString()))), + Arguments.of("ClassFile03.jasm", + List.of( + "\"ACC_VALUE, ACC_PUBLIC\": If the ACC_INTERFACE flag is not set a value class must have at least one of its ACC_FINAL, ACC_IDENTITY, or ACC_ABSTRACT flags set", + "Class file version not specified in file or by -cv parameter. Defaulting to version \"%s\"". + formatted(CFVersion.ValueObjectsVersion().asString()))), + Arguments.of("ClassFile04.jasm", + List.of("Ambiguous use of similar modifiers")), + Arguments.of("ClassFile05.jasm", + List.of("Ambiguous use of similar modifiers")), + Arguments.of("ClassFile06.jasm", + List.of( + "\"ACC_PUBLIC, ACC_IDENTITY, ACC_INTERFACE, ACC_ENUM\": If the ACC_INTERFACE flag is set, the ACC_ABSTRACT flag must also be set", + "\"ACC_PUBLIC, ACC_IDENTITY, ACC_INTERFACE, ACC_ENUM\": If the ACC_INTERFACE flag is set, the ACC_FINAL, ACC_IDENTITY, ACC_ENUM, and ACC_MODULE flags must not be set", + "\"ACC_PRIVATE, ACC_STRICT\": Interface field must be ACC_PUBLIC, ACC_STATIC, and ACC_FINAL only and may have ACC_STRICT_INIT or ACC_SYNTHETIC flag set", + " method cannot be an interface method" + )), + Arguments.of("ClassFile07.jasm", + List.of( + "\"ACC_PUBLIC, ACC_ANNOTATION\": If the ACC_INTERFACE flag is not set ACC_ANNOTATION, and ACC_MODULE flags must not be set." + )), + Arguments.of("ClassFile08.jasm", + List.of( + "\"ACC_INTERFACE, ACC_ENUM\": If the ACC_INTERFACE flag is set, the ACC_ABSTRACT flag must also be set", + "\"ACC_INTERFACE, ACC_ENUM\": If the ACC_INTERFACE flag is set, the ACC_FINAL, ACC_SUPER, ACC_ENUM, and ACC_MODULE flags must not be set." + )), + Arguments.of("ClassFile09.jasm", + List.of( + "\"ACC_VALUE\": If the ACC_INTERFACE flag is not set a value class must have at least one of its ACC_FINAL, ACC_IDENTITY, or ACC_ABSTRACT flags set", + "\"ACC_PUBLIC\": Each field of a value class must have at least one of its ACC_STATIC or ACC_STRICT_INIT flags set" + )), + Arguments.of("ClassFile10.jasm", + List.of( + "\"ACC_FINAL, ACC_ABSTRACT\": Class cannot be both abstract and final" + )), + Arguments.of("ClassFile11.jasm", + List.of()), + Arguments.of("ClassFile12.jasm", + List.of()), + Arguments.of("ClassFile13.jasm", + List.of()), + Arguments.of("ClassFile14.jasm", + List.of("Warning: Invalid modifier(s) for a field 0x0800")), + Arguments.of("ClassFile15.jasm", + List.of()), + Arguments.of("ClassField00.jasm", + List.of( + "\"ACC_PUBLIC, ACC_PROTECTED, ACC_STATIC\": Interface field must be ACC_PUBLIC, ACC_STATIC, and ACC_FINAL only and may have ACC_STRICT_INIT or ACC_SYNTHETIC flag set", + "\"ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_TRANSIENT\": Interface field must be ACC_PUBLIC, ACC_STATIC, and ACC_FINAL only and may have ACC_STRICT_INIT or ACC_SYNTHETIC flag set" + )), + Arguments.of("ClassField01.jasm", + List.of( + "\"ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_VOLATILE\": Each field of a class must not have both its ACC_FINAL and ACC_VOLATILE flags set")), + Arguments.of("ClassField02.jasm", + List.of( + "\"ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC, ACC_ENUM\": Interface field must be ACC_PUBLIC, ACC_STATIC, and ACC_FINAL only and may have ACC_STRICT_INIT or ACC_SYNTHETIC flag set", + "\"ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_TRANSIENT\": Interface field must be ACC_PUBLIC, ACC_STATIC, and ACC_FINAL only and may have ACC_STRICT_INIT or ACC_SYNTHETIC flag set", + "\"ACC_STATIC, ACC_FINAL, ACC_STRICT\": Interface field must be ACC_PUBLIC, ACC_STATIC, and ACC_FINAL only and may have ACC_STRICT_INIT or ACC_SYNTHETIC flag set")), + Arguments.of("ClassField03.jasm", + List.of()), + Arguments.of("ClassField04.jasm", + List.of("\"ACC_PUBLIC, ACC_FINAL\": Each field of a value class must have at least one of its ACC_STATIC or ACC_STRICT_INIT flags set", + "\"\": Each field of a value class must have at least one of its ACC_STATIC or ACC_STRICT_INIT flags set")) + ); + } + + @BeforeAll + public void init() throws IOException { + resourceDir = new File(this.getClass().getResource("ClassFile00.jasm").getFile()).getParentFile(); + } + + @ParameterizedTest + @MethodSource("getTestParameters") + public void methodSignatureTest(String resourceName, List jasmSubStrings) { + // jasm to class on the disk + LogAndBinResults res = jasm.compile(List.of(resourceDir + File.separator + resourceName)); + String log = res.log.toString(); + for (String jasmSubString : jasmSubStrings) { + Assertions.assertTrue(log.contains(jasmSubString)); + } + // exact number of warnings + Assertions.assertEquals(jasmSubStrings.size(), funcSubStrCount.apply(log, "Warning:")); + // jasm file was created + Assertions.assertEquals(0, res.result); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerNegative.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerNegative.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerNegative.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerNegative.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case7902820; + +import org.openjdk.asmtools.lib.transform.ITestRunner; + +import java.util.List; + +public class TestRunnerNegative implements ITestRunner { + + private final List classNames = List.of("SourceDebugExtensionNegative01", "SourceDebugExtensionNegative02"); + + final String dataPackage = TestRunnerNegative.class.getPackageName() + ".data."; + + @Override + public void run() { + for (String name : classNames) { + try { + this.getClass().getClassLoader().loadClass(dataPackage + name).getDeclaredConstructor().newInstance(); + } catch (Throwable ignored) { + /* ignore to be able to analyze stderr */ + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerPositive.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerPositive.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerPositive.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/TestRunnerPositive.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case7902820; + +import org.openjdk.asmtools.lib.transform.ITestRunner; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +public class TestRunnerPositive implements ITestRunner { + + private List classNames = List.of(".SourceDebugExtensionPositive01", ".SourceDebugExtensionPositive02"); + + final String dataPackage = TestRunnerPositive.class.getPackageName() + ".data"; + + @Override + public void run() { + for (String name : classNames) { + try { + Class cl = this.getClass().getClassLoader().loadClass(dataPackage + name); + Object obj = cl.getDeclaredConstructor().newInstance(); + Method meth = obj.getClass().getMethod("calculate"); + // + System.out.print("test "); + int rc = (int) meth.invoke(obj); + System.out.println(" " + rc); + } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + throw new RuntimeException(e); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtension_source.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtension_source.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtension_source.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtension_source.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +// Java source to generate InvalidSourceDebugExtension.class.jcod & SourceDebugExtension.class.jcod +// +package org.openjdk.asmtools.transform.case7902820.data; + +public class SourceDebugExtension_source { + + public int calculate() { + int a1 = 1; + int a2 = 1; + int a3 = 1; + try { + for (int i = a1 / (a2 - a3); i < 5; i++) { + a1 += 1; + } + a2 = 2; + } catch (ArithmeticException e) { + a3 = 2; + } + if (a1 != 1 || a2 != 1 || a3 != 2) { + System.out.print("failed"); + return 2; + } + System.out.print("passed"); + return 0; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7902820Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.lib.ext.CaptureSystemOutput; +import org.openjdk.asmtools.lib.transform.ResultChecker; +import org.openjdk.asmtools.lib.transform.TransformLoader; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.fail; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.ERROR; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.OUTPUT; +import static org.openjdk.asmtools.lib.transform.TransformLoader.TransformRules.JCOD_TO_CLASS_LOAD; + +/** + * Tests stdout for error messages + * CODETOOLS-7902820 Asmtools incorrectly uses stdout for output error messages + */ +public class case7902820Tests extends ResultChecker { + + private TransformLoader transformLoader; + + @BeforeEach + public void setClassLoader() { + transformLoader = new TransformLoader(case7902820Tests.class.getClassLoader()). + setTransformFilter(className -> className.contains("org.openjdk.asmtools.transform.case7902820")). + addToExcludeList("org.openjdk.asmtools.transform.case7902820.TestRunnerPositive", + "org.openjdk.asmtools.transform.case7902820.TestRunnerNegative" + ); + } + + @Test + @CaptureSystemOutput(value = OUTPUT, mute = true) + void systemOutputCheck_JCOD_TO_CLASS_LOAD_Positive(CaptureSystemOutput.OutputCapture outputCapture) { + outputCapture.expect(containsString("test SourceDebugExtensionPositive01 passed 0")); + outputCapture.expect(containsString("test SourceDebugExtensionPositive02 passed 0")); + transformLoader.setTransformRule(JCOD_TO_CLASS_LOAD); + try { + Class cl = + transformLoader.loadClass("org.openjdk.asmtools.transform.case7902820.TestRunnerPositive", true); + setTestRunClass(cl); + run(); + } catch (Exception ex) { + String msg = outputCapture.release().useStringTransformer(this::getPurifiedString).getLogAsString(ERROR); + System.err.println(msg); + fail(ex); + } + } + + @Test + @CaptureSystemOutput(value = ERROR, mute = true) + void systemOutputCheck_JCOD_TO_CLASS_LOAD_Negative(CaptureSystemOutput.OutputCapture errorCapture) { + transformLoader.setTransformRule(JCOD_TO_CLASS_LOAD); + errorCapture.expect( + containsString("Warning: Expected attribute length \"2,147,483,647\" does not match the actual length \"6\"; expected length written")); + errorCapture.expect( + containsString("Warning: Expected attribute length \"2\" does not match the actual length \"6\"; expected length written")); + errorCapture.expect(containsString("1 warning(s)")); + try { + Class cl = transformLoader. + loadClass("org.openjdk.asmtools.transform.case7902820.TestRunnerNegative", true); + setTestRunClass(cl); + run(); + } catch (Exception ignored) { /* ignore to be able to analyze stderr */ } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259/BuildString.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259/BuildString.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259/BuildString.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259/BuildString.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case7903259; + +/** + * The class for producing files ["jasm", "jcoder", "jdec", "jdis"] in resources/org.openjdk.asmtools.transform.case7903259 + * used by case7903259Tests::NoExtensionTest() + */ +public final class BuildString { + private final String intialString = "Hello"; + public void printDecoratedString() { + System.out.println(intialString.concat(" World !")); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903259Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.openjdk.asmtools.lib.action.EAsmTool; +import org.openjdk.asmtools.lib.log.LogAndReturn; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.openjdk.asmtools.lib.utility.FileUtils.getResourceFilePath; + +/** + * Tests tools against files without extension. + * CODETOOLS-7903259 jasm: file names without extensions causes a tool crash + */ +@TestInstance(PER_CLASS) +public class case7903259Tests { + + List assemblers = List.of("jasm", "jcoder"); + List disassemblers = List.of("jdec", "jdis"); + List files = Stream.concat(assemblers.stream(), disassemblers.stream()).collect(Collectors.toList()); + + File resourceDir; + + @BeforeAll + public void init() throws IOException { + resourceDir = getResourceFilePath(this.getClass(), + "case7903259" + File.separator + assemblers.get(0)). + getParentFile(); + } + + @Test + void NoExtensionTest() { + EAsmTool tool; + int testedToolsCount = 0; + for (String fileName : files) { + tool = EAsmTool.getToolBy(fileName); + if (tool != null) { + LogAndReturn ret = tool.call(List.of(resourceDir + File.separator + appendBin(fileName))); + assertTrue(ret.log.toString().isEmpty()); + assertEquals(0, ret.result); + testedToolsCount++; + } + } + assertEquals(4, testedToolsCount); + } + + private String appendBin(String fileName) { + if (disassemblers.contains(fileName)) { + return fileName.concat(".bin"); + } else { + return fileName; + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/TestRunner.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/TestRunner.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/TestRunner.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/TestRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case7903454; + +import org.openjdk.asmtools.lib.transform.ITestRunner; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +public class TestRunner implements ITestRunner { + + private List classNames = List.of(".Utf8Code", ".Utf8CodeBroken01"); + + final String dataPackage = TestRunner.class.getPackageName() + ".data"; + + @Override + public void run() { + for (String name : classNames) { + try { + Class cl = this.getClass().getClassLoader().loadClass(dataPackage + name); + Object obj = cl.getDeclaredConstructor().newInstance(); + Method meth = obj.getClass().getMethod("calculate"); + // + System.out.print("test "); + int rc = (int) meth.invoke(obj); + System.out.println(" " + rc); + } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + throw new RuntimeException(e); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/data/Utf8Code_source.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/data/Utf8Code_source.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/data/Utf8Code_source.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454/data/Utf8Code_source.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,68 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +// Java source to generate Utf8Code.class.jasm & Utf8Code.class.jcod +// +package org.openjdk.asmtools.transform.case7903454.data; + +import java.util.stream.Collectors; + +public class Utf8Code_source { + static String ČeštinaAlphabet = + "A Á B C Č D Ď E É Ě F G H Ch I Í J K L M N Ň O Ó P Q R Ř S Š T Ť U Ú Ů V W X Y Ý Z Ž " + + "a á b c č d ď e é ě f g h ch i í j k l m n ň o ó p q r ř s š t ť u ú ů v w x y ý z ž"; + + static String ქართულიენაAlphabet = + "Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ " + + "ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჷ ჸ ჹ ჺ ჻ ჼ ჽ ჾ ჿ"; + + static String ΕλληνικάAlphabet = + "Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ/ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω"; + + String line; + + private String نتیجہ = ""; + + private String вычислитьБольшиеБуквы() { + return line.codePoints().filter(cp -> Character.isUpperCase(cp)).mapToObj(cp->Character.toString(cp)). + collect(Collectors.joining()); + } + + private String вычислитьМаленькиеБуквы() { + return line.codePoints().filter(cp -> Character.isLowerCase(cp)).mapToObj(cp->Character.toString(cp)). + collect(Collectors.joining()); + } + + public int calculate() { + if( نتیجہ.isEmpty() ) + نتیجہ = вычислитьБольшиеБуквы().substring(0, 20) + вычислитьМаленькиеБуквы().substring(90); + int length = نتیجہ.length(); + System.out.println(length + " " + نتیجہ); + return length; + } + + public Utf8Code_source() { + line = ČeštinaAlphabet.replaceAll(" ", "") + + ქართულიენაAlphabet.replaceAll(" ", "") + + ΕλληνικάAlphabet.replaceAll(" ", ""); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case7903454Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.lib.ext.CaptureSystemOutput; +import org.openjdk.asmtools.lib.transform.ResultChecker; +import org.openjdk.asmtools.lib.transform.TransformLoader; + +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.fail; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.ERROR; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.OUTPUT; +import static org.openjdk.asmtools.lib.transform.TransformLoader.TransformRules.JASM_TO_CLASS_LOAD; +import static org.openjdk.asmtools.lib.transform.TransformLoader.TransformRules.JCOD_TO_CLASS_LOAD; + +/** + * Tests UTF-8 support and broken UTF8 content of SourceDebugExtension attribute + * CODETOOLS-7903454 Add Utf8 String and SourceDebugExtension attribute support + */ +public class case7903454Tests extends ResultChecker { + + private TransformLoader transformLoader; + + @BeforeEach + public void setClassLoader() { + transformLoader = new TransformLoader(case7903454Tests.class.getClassLoader()). + setTransformFilter(className -> className.contains("org.openjdk.asmtools.transform.case7903454")). + addToExcludeList("org.openjdk.asmtools.transform.case7903454.TestRunner" + ); + } + + @Test + @CaptureSystemOutput(value = OUTPUT, mute = true) + void systemOutputCheck_JCOD_TO_CLASS_LOAD_Positive(CaptureSystemOutput.OutputCapture outputCapture) { + outputCapture.useStringTransformer(s -> s.replaceAll("[ \t\n]*", "")). + expect(Matchers.allOf( + containsString("test4"), + matchesPattern(".*A.BC.D.E..FGH.*"), + matchesPattern(".*test4.*test4.*") + )); + transformLoader.setTransformRule(JCOD_TO_CLASS_LOAD); + try { + Class cl = transformLoader.loadClass("org.openjdk.asmtools.transform.case7903454.TestRunner", true); + setTestRunClass(cl); + run(); + } catch (Exception ex) { + String msg = outputCapture.release().useStringTransformer(this::getPurifiedString).getLogAsString(ERROR); + System.err.println(msg); + fail(ex); + } + } + + @Test + @CaptureSystemOutput(value = OUTPUT, mute = true) + void systemOutputCheck_JASM_TO_CLASS_LOAD_Positive(CaptureSystemOutput.OutputCapture outputCapture) { + outputCapture.useStringTransformer(s -> s.replaceAll("[ \t\n]*", "")). + expect(Matchers.allOf( + containsString("test4"), + matchesPattern(".*A.BC.D.E..FGH.*"), + matchesPattern(".*test4.*test4.*") + )); + transformLoader.setTransformRule(JASM_TO_CLASS_LOAD); + try { + Class cl = transformLoader.loadClass("org.openjdk.asmtools.transform.case7903454.TestRunner", true); + setTestRunClass(cl); + run(); + } catch (Exception ex) { + String msg = outputCapture.release().useStringTransformer(this::getPurifiedString).getLogAsString(ERROR); + System.err.println(msg); + fail(ex); + } + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/TestRunner.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/TestRunner.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/TestRunner.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/TestRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case8302260; + +import org.openjdk.asmtools.lib.transform.ITestRunner; +import org.openjdk.asmtools.transform.case8302260.data.CTestClass; + +import java.lang.constant.ClassDesc; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; + +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_long; + +public class TestRunner implements ITestRunner { + + final String superPackage = TestRunner.class.getPackageName() + ".data"; + + @Override + public void run() { + VarHandle vh; + // Chapter 5.4.3.2. Field Resolution Otherwise, field lookup is applied recursively + // to the direct superinterfaces of the specified class or interface C. + vh = testFieldRef(CTestClass.class, "stringField", String.class); + testFieldValue(vh, ClassDesc.of(superPackage, "CTestClass"), "stringField", CD_String); + vh = testFieldRef(CTestClass.class, "longField", long.class); + testFieldValue(vh, ClassDesc.of(superPackage, "CTestClass"), "longField", CD_long); + // Otherwise, if C has a superclass S, field lookup is applied recursively to S. + vh = testFieldRef(CTestClass.class, "stringField2", String.class); + testFieldValue(vh, ClassDesc.of(superPackage, "CTestClass"), "stringField2", CD_String); + vh = testFieldRef(CTestClass.class, "longField2", long.class); + testFieldValue(vh, ClassDesc.of(superPackage, "CTestClass"), "longField2", CD_long); + // + vh = testFieldRef(CTestClass.class, "stringField3", String.class); + testFieldValue(vh, ClassDesc.of(superPackage, "CTestClass"), "stringField3", CD_String); + vh = testFieldRef(CTestClass.class, "longField3", long.class); + testFieldValue(vh, ClassDesc.of(superPackage, "CTestClass"), "longField3", CD_long); + } + + void testFieldValue(VarHandle vh, ClassDesc desc, String name, ClassDesc fdesc) { + if (vh != null) { + try { + System.out.print(" 1: " + vh.get()); + } catch (Throwable e) { + System.out.println(" 1: failed"); + e.printStackTrace(System.err); + } + } + try { + VarHandle vh2 = MethodHandles.lookup().findStaticVarHandle((Class) desc.resolveConstantDesc(MethodHandles.lookup()), + name, (Class) fdesc.resolveConstantDesc(MethodHandles.lookup())); + System.out.print(" 2: " + vh2.get()); + } catch (Throwable e) { + System.out.println(" 2: failed"); + e.printStackTrace(System.err); + } + if (vh != null) { + try { + VarHandle.VarHandleDesc vhd = vh.describeConstable().orElseThrow(); + VarHandle obj = vhd.resolveConstantDesc(MethodHandles.lookup()); + System.out.print(" 3: " + obj.get()); + } catch (Throwable e) { + System.out.println(" 3: failed"); + e.printStackTrace(System.err); + } + } + try { + VarHandle.VarHandleDesc vhd = VarHandle.VarHandleDesc.ofStaticField(desc, name, fdesc); + VarHandle obj = vhd.resolveConstantDesc(MethodHandles.lookup()); + System.out.println(" 4: " + obj.get()); + } catch (Throwable t) { + System.out.println(" 4: failed"); + t.printStackTrace(System.out); + } + } + + VarHandle testFieldRef(Class rec, String fname, Class type) { + VarHandle vh = null; + try { + vh = MethodHandles.lookup().findStaticVarHandle(rec, fname, type); + System.out.print("0: " + fname); + } catch (NoSuchFieldException | IllegalAccessException e) { + System.out.println("0: failed"); + e.printStackTrace(System.err); + } + return vh; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/CTestClass.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/CTestClass.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/CTestClass.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/CTestClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case8302260.data; + + +import org.openjdk.asmtools.transform.case8302260.data.pkg.CTestSuperClass; + +public class CTestClass extends CTestSuperClass implements ITestInterfaceA { + public static String ctestString = "CTestClass"; + public static long ctestLong = 1l; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case8302260.data; + +public interface ITestInterfaceA { + String stringField = "ITestInterfaceA"; + long longField = 10l; + + String stringField3 = "ITestInterfaceA3"; + long longField3 = 13L; +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform.case8302260.data.pkg; + +public class CTestSuperClass { + public static String stringField = "CTestSuperClass"; + public static long longField = 100L; + + public static String stringField2 = "CTestSuperClass2"; + public static long longField2 = 102L; + +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260Tests.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260Tests.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260Tests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/case8302260Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.transform; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openjdk.asmtools.lib.ext.CaptureSystemOutput; +import org.openjdk.asmtools.lib.transform.ResultChecker; +import org.openjdk.asmtools.lib.transform.TransformLoader; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.emptyString; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static org.openjdk.asmtools.lib.action.EAsmTool.JDEC; +import static org.openjdk.asmtools.lib.action.EAsmTool.JDIS; +import static org.openjdk.asmtools.lib.ext.CaptureSystemOutput.Kind.*; +import static org.openjdk.asmtools.lib.transform.TransformLoader.TransformRules.*; + +/** + * Tests JDK-8302260 VarHandle.describeConstable() fails to return a nominal descriptor for static public fields + */ +class case8302260Tests extends ResultChecker { + + private final List goldList = List.of( + "0: stringField 1: ITestInterfaceA 2: ITestInterfaceA 3: ITestInterfaceA 4: ITestInterfaceA", + "0: longField 1: 10 2: 10 3: 10 4: 10", + "0: stringField2 1: CTestSuperClass2 2: CTestSuperClass2 3: CTestSuperClass2 4: CTestSuperClass2", + "0: longField2 1: 102 2: 102 3: 102 4: 102", + "0: stringField3 1: ITestInterfaceA3 2: ITestInterfaceA3 3: ITestInterfaceA3 4: ITestInterfaceA3", + "0: longField3 1: 13 2: 13 3: 13 4: 13" + ); + + private TransformLoader transformLoader; + + @BeforeEach + public void setClassLoader() { + transformLoader = new TransformLoader(case8302260Tests.class.getClassLoader()). + setTransformFilter(className -> className.contains("org.openjdk.asmtools.transform.case8302260.")). + clearOptions().setDeleteInterimFile(false); + } + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_JCOD_TO_CLASS_LOAD(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(JCOD_TO_CLASS_LOAD); + commonTestCase(outputCapture, transformLoader); + } + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_JASM_TO_CLASS_LOAD(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(JASM_TO_CLASS_LOAD); + commonTestCase(outputCapture, transformLoader); + } + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_CLASS_LOAD(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(CLASS_LOAD); + commonTestCase(outputCapture, transformLoader); + } + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_CLASS_TO_JCOD_TO_CLASS_LOAD(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(CLASS_TO_JCOD_TO_CLASS_LOAD); + commonTestCase(outputCapture, transformLoader); + } + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_CLASS_TO_JCOD_TO_CLASS_LOAD_DETAILED(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(CLASS_TO_JCOD_TO_CLASS_LOAD).setToolsOptions(JDEC, "-g"); + commonTestCase(outputCapture, transformLoader); + } + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_CLASS_TO_JCOD_TO_CLASS_LOAD_DETAILED_TABLE(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(CLASS_TO_JCOD_TO_CLASS_LOAD).setToolsOptions(JDEC, "-g", "-table"); + commonTestCase(outputCapture, transformLoader); + } + + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_CLASS_TO_JASM_TO_CLASS_LOAD(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(CLASS_TO_JASM_TO_CLASS_LOAD); + commonTestCase(outputCapture, transformLoader); + } + + @Test + @CaptureSystemOutput(value = BOTH, mute = true) + void systemOutputCheck_CLASS_TO_JASM_TO_CLASS_LOAD_DETAILED(CaptureSystemOutput.OutputCapture outputCapture) { + transformLoader.setTransformRule(CLASS_TO_JASM_TO_CLASS_LOAD).setToolsOptions(JDIS, "-g"); + commonTestCase(outputCapture, transformLoader); + } + + private void commonTestCase(final CaptureSystemOutput.OutputCapture capture, final TransformLoader loader) { + try { + Class cl = loader.loadClass("org.openjdk.asmtools.transform.case8302260.TestRunner", true); + setTestRunClass(cl); + run(); + } catch (Exception ex) { + String msg = capture.release().useStringTransformer(this::getPurifiedString).getLogAsString(ERROR); + System.err.println(msg); + fail(ex); + } + assertArrayEquals(goldList.toArray(), capture.useListTransformer(this::getFilteredList).getLogAsArray(OUTPUT)); + assertThat(capture.getLogAsString(ERROR), emptyString()); + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/package-info.java jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/package-info.java --- jtreg8-8.1+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/java/org/openjdk/asmtools/transform/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Facilities for behavioral testing of transitions from a binary to jcod/jasm presentation and vice versa. + * The stdout/stderr should be equal before and after transition as follows: + *

+ * javac class(output1) -> jasm->class(output2) => output1 == output2 + * javac class(output1) -> jcod->class(output2) => output1 == output2 + * (expected output): class(output) => expected output == output + * (expected output): jasm-> class(output) => expected output == output + * (expected output): jcod-> class(output) => expected output == output + */ +package org.openjdk.asmtools.transform; diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/abc.txt jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/abc.txt --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/abc.txt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/abc.txt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +some random text \ No newline at end of file diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcod001/atrcod00101m1/atrcod00101m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #12; // #1 + Class #6; // #2 + Method #1 #4; // #3 + NameAndType #14 #15; // #4 + Utf8 "ConstantValue"; // #5 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcod001/atrcod00101m1/atrcod00101m1n"; // #6 + Utf8 "Exceptions"; // #7 + Utf8 "LineNumberTable"; // #8 + Utf8 "SourceFile"; // #9 + Utf8 "LocalVariables"; // #10 + Utf8 "Code"; // #11 + Utf8 "java/lang/Object"; // #12 + Utf8 "attr003.jcod"; // #13 + Utf8 ""; // #14 + Utf8 "()V"; // #15 + } + + 0x0001; // access + #2; // this_cpx + #1; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #14; // name_index + #15; // descriptor_index + [] { // Attributes + Attr(#11) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + ; + Attr(#11) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcod00101m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,57 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcod001/atrcod00101m1/atrcod00101m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [16] { // Constant Pool + ; // first element is empty + Class #12; // #1 at 0x0A + Class #6; // #2 at 0x0D + Method #1 #4; // #3 at 0x10 + NameAndType #14 #15; // #4 at 0x15 + Utf8 "ConstantValue"; // #5 at 0x1A + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcod001/atrcod00101m1/atrcod00101m1p"; // #6 at 0x2A + Utf8 "Exceptions"; // #7 at 0x76 + Utf8 "LineNumberTable"; // #8 at 0x83 + Utf8 "SourceFile"; // #9 at 0x95 + Utf8 "LocalVariables"; // #10 at 0xA2 + Utf8 "Code"; // #11 at 0xB3 + Utf8 "java/lang/Object"; // #12 at 0xBA + Utf8 "attr003.jcod"; // #13 at 0xCD + Utf8 ""; // #14 at 0xDC + Utf8 "()V"; // #15 at 0xE5 + } // end of Constant Pool + + 0x0001; // access [ ACC_PUBLIC ] + #2; // this_cpx + #1; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [1] { // Methods + { // method at 0xF7 + 0x0001; // access + #14; // name_index : + #15; // descriptor_index : ()V + [1] { // Attributes + Attr(#11, 17) { // Code at 0xFF + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [0] { // Attributes + } // end of Attributes +} // end of class javasoft/sqe/tests/vm/classfmt/atr/atrcod001/atrcod00101m1/atrcod00101m1p diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,287 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1/atrcvl00101m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "atrcvl00101m10p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1/atrcvl00101m1"; // #12 + Utf8 "instantiatePositive"; // #13 + Utf8 "(Ljava/lang/String;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #14 + InvokeDynamic 0s #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "makeConcatWithConstants"; // #17 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #18 + Method #20 #21; // #19 + Class #22; // #20 + NameAndType #23 #24; // #21 + Utf8 "java/lang/Class"; // #22 + Utf8 "forName"; // #23 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #24 + Class #26; // #25 + Utf8 "java/lang/ThreadDeath"; // #26 + Class #28; // #27 + Utf8 "java/lang/Throwable"; // #28 + Method #30 #31; // #29 + Class #32; // #30 + NameAndType #33 #34; // #31 + Utf8 "java/lang/String"; // #32 + Utf8 "valueOf"; // #33 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #34 + InvokeDynamic 1s #16; // #35 + Method #37 #38; // #36 + Class #39; // #37 + NameAndType #40 #41; // #38 + Utf8 "java/io/PrintStream"; // #39 + Utf8 "println"; // #40 + Utf8 "(Ljava/lang/String;)V"; // #41 + Method #20 #43; // #42 + NameAndType #44 #45; // #43 + Utf8 "newInstance"; // #44 + Utf8 "()Ljava/lang/Object;"; // #45 + InvokeDynamic 2s #16; // #46 + Field #48 #49; // #47 + Class #50; // #48 + NameAndType #51 #52; // #49 + Utf8 "java/lang/System"; // #50 + Utf8 "out"; // #51 + Utf8 "Ljava/io/PrintStream;"; // #52 + Method #10 #54; // #53 + NameAndType #55 #56; // #54 + Utf8 "run"; // #55 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #56 + Method #48 #58; // #57 + NameAndType #59 #60; // #58 + Utf8 "exit"; // #59 + Utf8 "(I)V"; // #60 + Utf8 "Code"; // #61 + Utf8 "LineNumberTable"; // #62 + Utf8 "StackMapTable"; // #63 + Class #65; // #64 + Utf8 "[Ljava/lang/String;"; // #65 + Utf8 "main"; // #66 + Utf8 "([Ljava/lang/String;)V"; // #67 + Utf8 "SourceFile"; // #68 + Utf8 "atrcvl00101m1.java"; // #69 + Utf8 "BootstrapMethods"; // #70 + String #72; // #71 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl001.atrcvl00101m1.\u0001"; // #72 + String #74; // #73 + Utf8 "Failed with loading exception: \u0001"; // #74 + String #76; // #75 + Utf8 "Failed with runtime exception: \u0001"; // #76 + MethodHandle 6b #78; // #77 + Method #79 #80; // #78 + Class #81; // #79 + NameAndType #17 #82; // #80 + Utf8 "java/lang/invoke/StringConcatFactory"; // #81 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #82 + Utf8 "InnerClasses"; // #83 + Class #85; // #84 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #85 + Class #87; // #86 + Utf8 "java/lang/invoke/MethodHandles"; // #87 + Utf8 "Lookup"; // #88 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 12; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #55; // name_index + #56; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 3; // max_stack + 2; // max_locals + Bytes[]{ + 0x12 0x07 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x03 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 16; + 10 17; + 12 19; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 12b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x01 0x4E 0x2A 0xBA 0x00 0x0F 0x00 0x00 0xB8 0x00 0x13 0x4E; + 0xA7 0x00 0x1A 0x3A 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19; + 0x04 0xB8 0x00 0x1D 0xBA 0x00 0x23 0x00 0x00 0xB6 0x00 0x24; + 0x05 0xAC 0x2D 0xB6 0x00 0x2A 0x3A 0x04 0xA7 0x00 0x1A 0x3A; + 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19 0x04 0xB8 0x00 0x1D; + 0xBA 0x00 0x2E 0x00 0x00 0xB6 0x00 0x24 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 2 12 15 25; + 2 12 20 27; + 38 44 47 25; + 38 44 52 27; + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 24; + 2 26; + 12 32; + 15 27; + 17 28; + 20 29; + 22 30; + 36 31; + 38 35; + 44 41; + 47 36; + 49 37; + 52 38; + 54 39; + 68 40; + 70 43; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 255b, 15, []{O,#30; O,#64; O,#37; O,#20}, []{O,#25}; // full_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + 72b, []z{O,#25}; // same_locals_1_stack_item_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #66; // name_index + #67; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2F 0xB8 0x00 0x35 0x10 0x5F 0x60 0xB8 0x00; + 0x39 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 47; + 13 48; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#68) { // SourceFile + #69; + } // end of SourceFile + ; + Attr(#70) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #71; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #73; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #75; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#83) { // InnerClasses + [] { // classes + #84 #86 #88 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Ident: @(#)atrcvl00101m10p.jasm generated from: @(#)atrcvl00101m.jmpp 03/11/19 + * + * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +package javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1; + +public class atrcvl00101m10p + version 45:3 +{ + +final Field ifi:"I" = int 200000; + +public Method "":"()V" + throws java/lang/Exception + stack 2 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + aload_0; + getfield Field ifi:"I"; + ifeq OK; + new class java/lang/Exception; + dup; + invokespecial Method java/lang/Exception."":"()V"; + athrow; +OK: + return; +} +} // end Class atrcvl00101m10p diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m10p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1/atrcvl00101m10p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #8; // #1 + Class #15; // #2 + Field #21 #10; // #3 + Method #17 #8; // #4 + Utf8 "atrcvl00101m10p.jasm"; // #5 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1/atrcvl00101m10p"; // #6 + Utf8 "SourceFile"; // #7 + NameAndType #9 #11; // #8 + Utf8 ""; // #9 + NameAndType #20 #13; // #10 + Utf8 "()V"; // #11 + Utf8 "ConstantValue"; // #12 + Utf8 "I"; // #13 + Utf8 "java/lang/Object"; // #14 + Utf8 "java/lang/Exception"; // #15 + Utf8 "Code"; // #16 + Class #14; // #17 + Integer 0x00030D40; // #18 + Utf8 "Exceptions"; // #19 + Utf8 "ifi"; // #20 + Class #6; // #21 + } + + 0x0001; // access + #21; // this_cpx + #17; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0010; // access + #20; // name_index + #13; // descriptor_index + [] { // Attributes + Attr(#12) { // ConstantValue + #18; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #9; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#19) { // Exceptions + [] { // Exceptions + #2; + } + } // end of Exceptions + ; + Attr(#16) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0x2A 0xB4 0x00 0x03 0x99 0x00 0x0B 0xBB; + 0x00 0x02 0x59 0xB7 0x00 0x01 0xBF 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#7) { // SourceFile + #5; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,287 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1t/atrcvl00101m1t { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "atrcvl00101m1t0p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1t/atrcvl00101m1t"; // #12 + Utf8 "instantiatePositive"; // #13 + Utf8 "(Ljava/lang/String;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #14 + InvokeDynamic 0s #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "makeConcatWithConstants"; // #17 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #18 + Method #20 #21; // #19 + Class #22; // #20 + NameAndType #23 #24; // #21 + Utf8 "java/lang/Class"; // #22 + Utf8 "forName"; // #23 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #24 + Class #26; // #25 + Utf8 "java/lang/ThreadDeath"; // #26 + Class #28; // #27 + Utf8 "java/lang/Throwable"; // #28 + Method #30 #31; // #29 + Class #32; // #30 + NameAndType #33 #34; // #31 + Utf8 "java/lang/String"; // #32 + Utf8 "valueOf"; // #33 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #34 + InvokeDynamic 1s #16; // #35 + Method #37 #38; // #36 + Class #39; // #37 + NameAndType #40 #41; // #38 + Utf8 "java/io/PrintStream"; // #39 + Utf8 "println"; // #40 + Utf8 "(Ljava/lang/String;)V"; // #41 + Method #20 #43; // #42 + NameAndType #44 #45; // #43 + Utf8 "newInstance"; // #44 + Utf8 "()Ljava/lang/Object;"; // #45 + InvokeDynamic 2s #16; // #46 + Field #48 #49; // #47 + Class #50; // #48 + NameAndType #51 #52; // #49 + Utf8 "java/lang/System"; // #50 + Utf8 "out"; // #51 + Utf8 "Ljava/io/PrintStream;"; // #52 + Method #10 #54; // #53 + NameAndType #55 #56; // #54 + Utf8 "run"; // #55 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #56 + Method #48 #58; // #57 + NameAndType #59 #60; // #58 + Utf8 "exit"; // #59 + Utf8 "(I)V"; // #60 + Utf8 "Code"; // #61 + Utf8 "LineNumberTable"; // #62 + Utf8 "StackMapTable"; // #63 + Class #65; // #64 + Utf8 "[Ljava/lang/String;"; // #65 + Utf8 "main"; // #66 + Utf8 "([Ljava/lang/String;)V"; // #67 + Utf8 "SourceFile"; // #68 + Utf8 "atrcvl00101m1t.java"; // #69 + Utf8 "BootstrapMethods"; // #70 + String #72; // #71 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl001.atrcvl00101m1t.\u0001"; // #72 + String #74; // #73 + Utf8 "Failed with loading exception: \u0001"; // #74 + String #76; // #75 + Utf8 "Failed with runtime exception: \u0001"; // #76 + MethodHandle 6b #78; // #77 + Method #79 #80; // #78 + Class #81; // #79 + NameAndType #17 #82; // #80 + Utf8 "java/lang/invoke/StringConcatFactory"; // #81 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #82 + Utf8 "InnerClasses"; // #83 + Class #85; // #84 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #85 + Class #87; // #86 + Utf8 "java/lang/invoke/MethodHandles"; // #87 + Utf8 "Lookup"; // #88 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 12; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #55; // name_index + #56; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 3; // max_stack + 2; // max_locals + Bytes[]{ + 0x12 0x07 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x03 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 16; + 10 17; + 12 19; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 12b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x01 0x4E 0x2A 0xBA 0x00 0x0F 0x00 0x00 0xB8 0x00 0x13 0x4E; + 0xA7 0x00 0x1A 0x3A 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19; + 0x04 0xB8 0x00 0x1D 0xBA 0x00 0x23 0x00 0x00 0xB6 0x00 0x24; + 0x05 0xAC 0x2D 0xB6 0x00 0x2A 0x3A 0x04 0xA7 0x00 0x1A 0x3A; + 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19 0x04 0xB8 0x00 0x1D; + 0xBA 0x00 0x2E 0x00 0x00 0xB6 0x00 0x24 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 2 12 15 25; + 2 12 20 27; + 38 44 47 25; + 38 44 52 27; + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 24; + 2 26; + 12 32; + 15 27; + 17 28; + 20 29; + 22 30; + 36 31; + 38 35; + 44 41; + 47 36; + 49 37; + 52 38; + 54 39; + 68 40; + 70 43; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 255b, 15, []{O,#30; O,#64; O,#37; O,#20}, []{O,#25}; // full_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + 72b, []z{O,#25}; // same_locals_1_stack_item_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #66; // name_index + #67; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2F 0xB8 0x00 0x35 0x10 0x5F 0x60 0xB8 0x00; + 0x39 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 47; + 13 48; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#68) { // SourceFile + #69; + } // end of SourceFile + ; + Attr(#70) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #71; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #73; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #75; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#83) { // InnerClasses + [] { // classes + #84 #86 #88 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t0p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t0p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t0p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00101m1t0p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,89 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1t/atrcvl00101m1t0p { + 0xCAFEBABE; + 0; // minor version + 50; // version + [] { // Constant Pool + ; // first element is empty + Field #6 #7; // #1 + Class #17; // #2 + Method #10 #8; // #3 + Method #2 #8; // #4 + Utf8 "atrcvl00101m1t0p.jasm"; // #5 + Class #22; // #6 + NameAndType #21 #14; // #7 + NameAndType #11 #12; // #8 + Integer 0x00030D40; // #9 + Class #16; // #10 + Utf8 ""; // #11 + Utf8 "()V"; // #12 + Utf8 "SourceFile"; // #13 + Utf8 "I"; // #14 + Utf8 "StackMapTable"; // #15 + Utf8 "java/lang/Object"; // #16 + Utf8 "java/lang/Exception"; // #17 + Utf8 "Code"; // #18 + Utf8 "ConstantValue"; // #19 + Utf8 "Exceptions"; // #20 + Utf8 "ifi"; // #21 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00101m1t/atrcvl00101m1t0p"; // #22 + } + + 0x0001; // access + #6; // this_cpx + #10; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0010; // access + #21; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#19) { // ConstantValue + #9; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #11; // name_index + #12; // descriptor_index + [] { // Attributes + Attr(#20) { // Exceptions + [] { // Exceptions + #2; + } + } // end of Exceptions + ; + Attr(#18) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0x2A 0xB4 0x00 0x01 0x99 0x00 0x0B 0xBB; + 0x00 0x02 0x59 0xB7 0x00 0x04 0xBF 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#15) { // StackMapTable + [] { // + 255b, 19, []{O,#6}, []{}; // full_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#13) { // SourceFile + #5; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,287 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1/atrcvl00102m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "atrcvl00102m10p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1/atrcvl00102m1"; // #12 + Utf8 "instantiatePositive"; // #13 + Utf8 "(Ljava/lang/String;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #14 + InvokeDynamic 0s #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "makeConcatWithConstants"; // #17 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #18 + Method #20 #21; // #19 + Class #22; // #20 + NameAndType #23 #24; // #21 + Utf8 "java/lang/Class"; // #22 + Utf8 "forName"; // #23 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #24 + Class #26; // #25 + Utf8 "java/lang/ThreadDeath"; // #26 + Class #28; // #27 + Utf8 "java/lang/Throwable"; // #28 + Method #30 #31; // #29 + Class #32; // #30 + NameAndType #33 #34; // #31 + Utf8 "java/lang/String"; // #32 + Utf8 "valueOf"; // #33 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #34 + InvokeDynamic 1s #16; // #35 + Method #37 #38; // #36 + Class #39; // #37 + NameAndType #40 #41; // #38 + Utf8 "java/io/PrintStream"; // #39 + Utf8 "println"; // #40 + Utf8 "(Ljava/lang/String;)V"; // #41 + Method #20 #43; // #42 + NameAndType #44 #45; // #43 + Utf8 "newInstance"; // #44 + Utf8 "()Ljava/lang/Object;"; // #45 + InvokeDynamic 2s #16; // #46 + Field #48 #49; // #47 + Class #50; // #48 + NameAndType #51 #52; // #49 + Utf8 "java/lang/System"; // #50 + Utf8 "out"; // #51 + Utf8 "Ljava/io/PrintStream;"; // #52 + Method #10 #54; // #53 + NameAndType #55 #56; // #54 + Utf8 "run"; // #55 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #56 + Method #48 #58; // #57 + NameAndType #59 #60; // #58 + Utf8 "exit"; // #59 + Utf8 "(I)V"; // #60 + Utf8 "Code"; // #61 + Utf8 "LineNumberTable"; // #62 + Utf8 "StackMapTable"; // #63 + Class #65; // #64 + Utf8 "[Ljava/lang/String;"; // #65 + Utf8 "main"; // #66 + Utf8 "([Ljava/lang/String;)V"; // #67 + Utf8 "SourceFile"; // #68 + Utf8 "atrcvl00102m1.java"; // #69 + Utf8 "BootstrapMethods"; // #70 + String #72; // #71 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl001.atrcvl00102m1.\u0001"; // #72 + String #74; // #73 + Utf8 "Failed with loading exception: \u0001"; // #74 + String #76; // #75 + Utf8 "Failed with runtime exception: \u0001"; // #76 + MethodHandle 6b #78; // #77 + Method #79 #80; // #78 + Class #81; // #79 + NameAndType #17 #82; // #80 + Utf8 "java/lang/invoke/StringConcatFactory"; // #81 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #82 + Utf8 "InnerClasses"; // #83 + Class #85; // #84 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #85 + Class #87; // #86 + Utf8 "java/lang/invoke/MethodHandles"; // #87 + Utf8 "Lookup"; // #88 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 12; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #55; // name_index + #56; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 3; // max_stack + 2; // max_locals + Bytes[]{ + 0x12 0x07 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x03 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 16; + 10 17; + 12 19; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 12b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x01 0x4E 0x2A 0xBA 0x00 0x0F 0x00 0x00 0xB8 0x00 0x13 0x4E; + 0xA7 0x00 0x1A 0x3A 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19; + 0x04 0xB8 0x00 0x1D 0xBA 0x00 0x23 0x00 0x00 0xB6 0x00 0x24; + 0x05 0xAC 0x2D 0xB6 0x00 0x2A 0x3A 0x04 0xA7 0x00 0x1A 0x3A; + 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19 0x04 0xB8 0x00 0x1D; + 0xBA 0x00 0x2E 0x00 0x00 0xB6 0x00 0x24 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 2 12 15 25; + 2 12 20 27; + 38 44 47 25; + 38 44 52 27; + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 24; + 2 26; + 12 32; + 15 27; + 17 28; + 20 29; + 22 30; + 36 31; + 38 35; + 44 41; + 47 36; + 49 37; + 52 38; + 54 39; + 68 40; + 70 43; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 255b, 15, []{O,#30; O,#64; O,#37; O,#20}, []{O,#25}; // full_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + 72b, []z{O,#25}; // same_locals_1_stack_item_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #66; // name_index + #67; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2F 0xB8 0x00 0x35 0x10 0x5F 0x60 0xB8 0x00; + 0x39 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 47; + 13 48; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#68) { // SourceFile + #69; + } // end of SourceFile + ; + Attr(#70) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #71; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #73; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #75; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#83) { // InnerClasses + [] { // classes + #84 #86 #88 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m10p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m10p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m10p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m10p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1/atrcvl00102m10p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Method #18 #16; // #1 + Method #3 #16; // #2 + Class #12; // #3 + Field #9 #17; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + Utf8 "ConstantValue"; // #7 + Utf8 "SourceFile"; // #8 + Class #20; // #9 + Utf8 "I"; // #10 + Utf8 "java/lang/Object"; // #11 + Utf8 "java/lang/Exception"; // #12 + Utf8 "Code"; // #13 + Utf8 "Exceptions"; // #14 + Utf8 "ifi"; // #15 + NameAndType #5 #6; // #16 + NameAndType #15 #10; // #17 + Class #11; // #18 + Integer 0x00030D40; // #19 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1/atrcvl00102m10p"; // #20 + Utf8 "atrcvl00102m10p.jasm"; // #21 + } + + 0x0001; // access + #9; // this_cpx + #18; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0000; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#7) { // ConstantValue + #19; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#14) { // Exceptions + [] { // Exceptions + #3; + } + } // end of Exceptions + ; + Attr(#13) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0x2A 0xB4 0x00 0x04 0x99 0x00 0x0B 0xBB; + 0x00 0x03 0x59 0xB7 0x00 0x02 0xBF 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#8) { // SourceFile + #21; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,287 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1t/atrcvl00102m1t { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "atrcvl00102m1t0p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1t/atrcvl00102m1t"; // #12 + Utf8 "instantiatePositive"; // #13 + Utf8 "(Ljava/lang/String;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #14 + InvokeDynamic 0s #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "makeConcatWithConstants"; // #17 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #18 + Method #20 #21; // #19 + Class #22; // #20 + NameAndType #23 #24; // #21 + Utf8 "java/lang/Class"; // #22 + Utf8 "forName"; // #23 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #24 + Class #26; // #25 + Utf8 "java/lang/ThreadDeath"; // #26 + Class #28; // #27 + Utf8 "java/lang/Throwable"; // #28 + Method #30 #31; // #29 + Class #32; // #30 + NameAndType #33 #34; // #31 + Utf8 "java/lang/String"; // #32 + Utf8 "valueOf"; // #33 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #34 + InvokeDynamic 1s #16; // #35 + Method #37 #38; // #36 + Class #39; // #37 + NameAndType #40 #41; // #38 + Utf8 "java/io/PrintStream"; // #39 + Utf8 "println"; // #40 + Utf8 "(Ljava/lang/String;)V"; // #41 + Method #20 #43; // #42 + NameAndType #44 #45; // #43 + Utf8 "newInstance"; // #44 + Utf8 "()Ljava/lang/Object;"; // #45 + InvokeDynamic 2s #16; // #46 + Field #48 #49; // #47 + Class #50; // #48 + NameAndType #51 #52; // #49 + Utf8 "java/lang/System"; // #50 + Utf8 "out"; // #51 + Utf8 "Ljava/io/PrintStream;"; // #52 + Method #10 #54; // #53 + NameAndType #55 #56; // #54 + Utf8 "run"; // #55 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #56 + Method #48 #58; // #57 + NameAndType #59 #60; // #58 + Utf8 "exit"; // #59 + Utf8 "(I)V"; // #60 + Utf8 "Code"; // #61 + Utf8 "LineNumberTable"; // #62 + Utf8 "StackMapTable"; // #63 + Class #65; // #64 + Utf8 "[Ljava/lang/String;"; // #65 + Utf8 "main"; // #66 + Utf8 "([Ljava/lang/String;)V"; // #67 + Utf8 "SourceFile"; // #68 + Utf8 "atrcvl00102m1t.java"; // #69 + Utf8 "BootstrapMethods"; // #70 + String #72; // #71 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl001.atrcvl00102m1t.\u0001"; // #72 + String #74; // #73 + Utf8 "Failed with loading exception: \u0001"; // #74 + String #76; // #75 + Utf8 "Failed with runtime exception: \u0001"; // #76 + MethodHandle 6b #78; // #77 + Method #79 #80; // #78 + Class #81; // #79 + NameAndType #17 #82; // #80 + Utf8 "java/lang/invoke/StringConcatFactory"; // #81 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #82 + Utf8 "InnerClasses"; // #83 + Class #85; // #84 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #85 + Class #87; // #86 + Utf8 "java/lang/invoke/MethodHandles"; // #87 + Utf8 "Lookup"; // #88 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 12; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #55; // name_index + #56; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 3; // max_stack + 2; // max_locals + Bytes[]{ + 0x12 0x07 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x03 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 16; + 10 17; + 12 19; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 12b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x01 0x4E 0x2A 0xBA 0x00 0x0F 0x00 0x00 0xB8 0x00 0x13 0x4E; + 0xA7 0x00 0x1A 0x3A 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19; + 0x04 0xB8 0x00 0x1D 0xBA 0x00 0x23 0x00 0x00 0xB6 0x00 0x24; + 0x05 0xAC 0x2D 0xB6 0x00 0x2A 0x3A 0x04 0xA7 0x00 0x1A 0x3A; + 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19 0x04 0xB8 0x00 0x1D; + 0xBA 0x00 0x2E 0x00 0x00 0xB6 0x00 0x24 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 2 12 15 25; + 2 12 20 27; + 38 44 47 25; + 38 44 52 27; + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 24; + 2 26; + 12 32; + 15 27; + 17 28; + 20 29; + 22 30; + 36 31; + 38 35; + 44 41; + 47 36; + 49 37; + 52 38; + 54 39; + 68 40; + 70 43; + } + } // end of LineNumberTable + ; + Attr(#63) { // StackMapTable + [] { // + 255b, 15, []{O,#30; O,#64; O,#37; O,#20}, []{O,#25}; // full_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + 72b, []z{O,#25}; // same_locals_1_stack_item_frame + 68b, []z{O,#27}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #66; // name_index + #67; // descriptor_index + [] { // Attributes + Attr(#61) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2F 0xB8 0x00 0x35 0x10 0x5F 0x60 0xB8 0x00; + 0x39 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#62) { // LineNumberTable + [] { // line_number_table + 0 47; + 13 48; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#68) { // SourceFile + #69; + } // end of SourceFile + ; + Attr(#70) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #71; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #73; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #77; // bootstrap_method_ref + [] { // bootstrap_arguments + #75; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#83) { // InnerClasses + [] { // classes + #84 #86 #88 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t0p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t0p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t0p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00102m1t0p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,89 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1t/atrcvl00102m1t0p { + 0xCAFEBABE; + 0; // minor version + 50; // version + [] { // Constant Pool + ; // first element is empty + Class #22; // #1 + Method #9 #5; // #2 + Field #18 #8; // #3 + Method #1 #5; // #4 + NameAndType #20 #16; // #5 + Utf8 "Code"; // #6 + Utf8 "ConstantValue"; // #7 + NameAndType #12 #19; // #8 + Class #21; // #9 + Utf8 "StackMapTable"; // #10 + Utf8 "Exceptions"; // #11 + Utf8 "ifi"; // #12 + Utf8 "atrcvl00102m1t0p.jasm"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl001/atrcvl00102m1t/atrcvl00102m1t0p"; // #14 + Integer 0x00030D40; // #15 + Utf8 "()V"; // #16 + Utf8 "SourceFile"; // #17 + Class #14; // #18 + Utf8 "I"; // #19 + Utf8 ""; // #20 + Utf8 "java/lang/Object"; // #21 + Utf8 "java/lang/Exception"; // #22 + } + + 0x0001; // access + #18; // this_cpx + #9; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0000; // access + #12; // name_index + #19; // descriptor_index + [] { // Attributes + Attr(#7) { // ConstantValue + #15; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #20; // name_index + #16; // descriptor_index + [] { // Attributes + Attr(#11) { // Exceptions + [] { // Exceptions + #1; + } + } // end of Exceptions + ; + Attr(#6) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x02 0x2A 0xB4 0x00 0x03 0x99 0x00 0x0B 0xBB; + 0x00 0x01 0x59 0xB7 0x00 0x04 0xBF 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#10) { // StackMapTable + [] { // + 255b, 19, []{O,#18}, []{}; // full_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#17) { // SourceFile + #13; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl003/atrcvl00301m1/atrcvl00301m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl003.atrcvl00301m1.atrcvl00301m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl003.atrcvl00301m1.atrcvl00301m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00301m1 failed to reject bad classfile atrcvl00301m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl003/atrcvl00301m1/atrcvl00301m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00301m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00301m1 failed to load or instantiate good classfile atrcvl00301m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00301m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,75 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl003/atrcvl00301m1/atrcvl00301m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl003/atrcvl00301m1/atrcvl00301m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #19; + } // end of ConstantValue + ; + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00301m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl003/atrcvl00301m1/atrcvl00301m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl003/atrcvl00301m1/atrcvl00301m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,252 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl004.atrcvl00401m1.atrcvl00401m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1n"; // #20 + Class #22; // #21 + Utf8 "java/lang/Exception"; // #22 + Method #24 #25; // #23 + Class #26; // #24 + NameAndType #27 #28; // #25 + Utf8 "java/lang/String"; // #26 + Utf8 "valueOf"; // #27 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #28 + InvokeDynamic 0s #30; // #29 + NameAndType #31 #32; // #30 + Utf8 "makeConcatWithConstants"; // #31 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #32 + Method #34 #35; // #33 + Class #36; // #34 + NameAndType #37 #38; // #35 + Utf8 "java/io/PrintStream"; // #36 + Utf8 "println"; // #37 + Utf8 "(Ljava/lang/String;)V"; // #38 + Class #40; // #39 + Utf8 "java/lang/Throwable"; // #40 + InvokeDynamic 1s #30; // #41 + InterfaceMethod #19 #43; // #42 + NameAndType #44 #45; // #43 + Utf8 "get_i1"; // #44 + Utf8 "()I"; // #45 + Integer 0x0130BF9D; // #46 + String #48; // #47 + Utf8 "invalid value i1"; // #48 + InterfaceMethod #19 #50; // #49 + NameAndType #51 #45; // #50 + Utf8 "get_i2"; // #51 + Integer 0x0130E6AE; // #52 + String #54; // #53 + Utf8 "invalid value i2"; // #54 + Field #56 #57; // #55 + Class #58; // #56 + NameAndType #59 #60; // #57 + Utf8 "java/lang/System"; // #58 + Utf8 "out"; // #59 + Utf8 "Ljava/io/PrintStream;"; // #60 + Method #62 #63; // #61 + Class #64; // #62 + NameAndType #65 #66; // #63 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1"; // #64 + Utf8 "run"; // #65 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #66 + Method #56 #68; // #67 + NameAndType #69 #70; // #68 + Utf8 "exit"; // #69 + Utf8 "(I)V"; // #70 + Utf8 "Code"; // #71 + Utf8 "LineNumberTable"; // #72 + Utf8 "StackMapTable"; // #73 + Utf8 "main"; // #74 + Utf8 "([Ljava/lang/String;)V"; // #75 + Utf8 "SourceFile"; // #76 + Utf8 "atrcvl00401m1.java"; // #77 + Utf8 "BootstrapMethods"; // #78 + String #80; // #79 + Utf8 "failed create an instance of atrcvl00401m1p:\u0001"; // #80 + String #82; // #81 + Utf8 "failed to load class atrcvl00401m1p:\u0001"; // #82 + MethodHandle 6b #84; // #83 + Method #85 #86; // #84 + Class #87; // #85 + NameAndType #31 #88; // #86 + Utf8 "java/lang/invoke/StringConcatFactory"; // #87 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #88 + Utf8 "InnerClasses"; // #89 + Class #91; // #90 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #91 + Class #93; // #92 + Utf8 "java/lang/invoke/MethodHandles"; // #93 + Utf8 "Lookup"; // #94 + } + + 0x0021; // access + #62; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 13; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #65; // name_index + #66; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0xC0 0x00; + 0x13 0x4E 0xA7 0x00 0x27 0x3A 0x04 0x2B 0x19 0x04 0xB8 0x00; + 0x17 0xBA 0x00 0x1D 0x00 0x00 0xB6 0x00 0x21 0x05 0xAC 0x3A; + 0x04 0x2B 0x19 0x04 0xB8 0x00 0x17 0xBA 0x00 0x29 0x00 0x00; + 0xB6 0x00 0x21 0x05 0xAC 0x2D 0xB9 0x00 0x2A 0x01 0x00 0x12; + 0x2E 0x9F 0x00 0x0B 0x2B 0x12 0x2F 0xB6 0x00 0x21 0x05 0xAC; + 0x2D 0xB9 0x00 0x31 0x01 0x00 0x12 0x34 0x9F 0x00 0x0B 0x2B; + 0x12 0x35 0xB6 0x00 0x21 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 14 17 21; + 0 14 35 39; + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 18; + 6 19; + 14 26; + 17 20; + 19 21; + 33 22; + 35 23; + 37 24; + 51 25; + 53 27; + 64 28; + 70 29; + 72 31; + 83 32; + 89 33; + 91 35; + } + } // end of LineNumberTable + ; + Attr(#73) { // StackMapTable + [] { // + 81b, []z{O,#21}; // same_locals_1_stack_item_frame + 81b, []z{O,#39}; // same_locals_1_stack_item_frame + 253b, 17, []z{O,#10; O,#19}; // append_frame 2 + 18b; // same_frame + 18b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #74; // name_index + #75; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x37 0xB8 0x00 0x3D 0x10 0x5F 0x60 0xB8 0x00; + 0x43 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 39; + 13 40; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#76) { // SourceFile + #77; + } // end of SourceFile + ; + Attr(#78) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #83; // bootstrap_method_ref + [] { // bootstrap_arguments + #79; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #83; // bootstrap_method_ref + [] { // bootstrap_arguments + #81; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#89) { // InnerClasses + [] { // classes + #90 #92 #94 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,51 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1n { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Class #2; // #1 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1n"; // #2 + Class #4; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 "get_i1"; // #5 + Utf8 "()I"; // #6 + Utf8 "get_i2"; // #7 + Utf8 "SourceFile"; // #8 + Utf8 "atrcvl00401m1n.java"; // #9 + } + + 0x0600; // access + #1; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0401; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // method + 0x0401; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#8) { // SourceFile + #9; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00401m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,131 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Field #6 #18; // #1 + Field #6 #20; // #2 + Method #21 #13; // #3 + Utf8 "i2"; // #4 + Utf8 "atrcvl00401m1p.jasm"; // #5 + Class #14; // #6 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1n"; // #7 + Utf8 "get_i1"; // #8 + Integer 0x0130BF9D; // #9 + Utf8 "get_i2"; // #10 + Utf8 "SourceFile"; // #11 + Integer 0x0130E6AE; // #12 + NameAndType #15 #17; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00401m1/atrcvl00401m1p"; // #14 + Utf8 ""; // #15 + Class #7; // #16 + Utf8 "()V"; // #17 + NameAndType #4 #24; // #18 + Utf8 "ConstantValue"; // #19 + NameAndType #23 #24; // #20 + Class #25; // #21 + Utf8 "()I"; // #22 + Utf8 "i1"; // #23 + Utf8 "I"; // #24 + Utf8 "java/lang/Object"; // #25 + Utf8 "Code"; // #26 + } + + 0x0000; // access + #6; // this_cpx + #21; // super_cpx + + [] { // Interfaces + #16; + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #23; // name_index + #24; // descriptor_index + [] { // Attributes + Attr(#19) { // ConstantValue + #9; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #4; // name_index + #24; // descriptor_index + [] { // Attributes + Attr(#19) { // ConstantValue + #12; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #8; // name_index + #22; // descriptor_index + [] { // Attributes + Attr(#26) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0xB2 0x00 0x02 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #10; // name_index + #22; // descriptor_index + [] { // Attributes + Attr(#26) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0xB2 0x00 0x01 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #15; // name_index + #17; // descriptor_index + [] { // Attributes + Attr(#26) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#11) { // SourceFile + #5; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,692 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00402m1/atrcvl00402m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00402m1/atrcvl00402m1t"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + Field #8 #9; // #7 + Class #10; // #8 + NameAndType #11 #12; // #9 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00402m1/atrcvl00402m1"; // #10 + Utf8 "sfStringMirror"; // #11 + Utf8 "Ljava/lang/String;"; // #12 + String #14; // #13 + Utf8 "sfString"; // #14 + Method #16 #17; // #15 + Class #18; // #16 + NameAndType #19 #20; // #17 + Utf8 "java/lang/String"; // #18 + Utf8 "equals"; // #19 + Utf8 "(Ljava/lang/Object;)Z"; // #20 + InvokeDynamic 0s #22; // #21 + NameAndType #23 #24; // #22 + Utf8 "makeConcatWithConstants"; // #23 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #24 + Method #26 #27; // #25 + Class #28; // #26 + NameAndType #29 #30; // #27 + Utf8 "java/io/PrintStream"; // #28 + Utf8 "println"; // #29 + Utf8 "(Ljava/lang/String;)V"; // #30 + Field #8 #32; // #31 + NameAndType #33 #12; // #32 + Utf8 "sStringMirror"; // #33 + Field #8 #35; // #34 + NameAndType #36 #12; // #35 + Utf8 "sString"; // #36 + InvokeDynamic 1s #38; // #37 + NameAndType #23 #39; // #38 + Utf8 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; // #39 + String #36; // #40 + InvokeDynamic 2s #22; // #41 + Field #8 #43; // #42 + NameAndType #44 #45; // #43 + Utf8 "sfBooleanMirror"; // #44 + Utf8 "Z"; // #45 + InvokeDynamic 3s #47; // #46 + NameAndType #23 #48; // #47 + Utf8 "(Z)Ljava/lang/String;"; // #48 + Field #8 #50; // #49 + NameAndType #51 #45; // #50 + Utf8 "sBooleanMirror"; // #51 + Field #8 #53; // #52 + NameAndType #54 #45; // #53 + Utf8 "sBoolean"; // #54 + InvokeDynamic 1s #56; // #55 + NameAndType #23 #57; // #56 + Utf8 "(ZZ)Ljava/lang/String;"; // #57 + InvokeDynamic 4s #47; // #58 + Field #8 #60; // #59 + NameAndType #61 #62; // #60 + Utf8 "sfShortMirror"; // #61 + Utf8 "S"; // #62 + InvokeDynamic 5s #64; // #63 + NameAndType #23 #65; // #64 + Utf8 "(S)Ljava/lang/String;"; // #65 + Field #8 #67; // #66 + NameAndType #68 #62; // #67 + Utf8 "sShortMirror"; // #68 + Field #8 #70; // #69 + NameAndType #71 #62; // #70 + Utf8 "sShort"; // #71 + InvokeDynamic 1s #73; // #72 + NameAndType #23 #74; // #73 + Utf8 "(SS)Ljava/lang/String;"; // #74 + InvokeDynamic 6s #64; // #75 + Field #8 #77; // #76 + NameAndType #78 #79; // #77 + Utf8 "sfCharMirror"; // #78 + Utf8 "C"; // #79 + InvokeDynamic 7s #81; // #80 + NameAndType #23 #82; // #81 + Utf8 "(C)Ljava/lang/String;"; // #82 + InvokeDynamic 8s #81; // #83 + Field #8 #85; // #84 + NameAndType #86 #79; // #85 + Utf8 "sCharMirror"; // #86 + Field #8 #88; // #87 + NameAndType #89 #79; // #88 + Utf8 "sChar"; // #89 + InvokeDynamic 1s #91; // #90 + NameAndType #23 #92; // #91 + Utf8 "(CC)Ljava/lang/String;"; // #92 + InvokeDynamic 9s #81; // #93 + Field #8 #95; // #94 + NameAndType #96 #97; // #95 + Utf8 "sfByteMirror"; // #96 + Utf8 "B"; // #97 + InvokeDynamic 10s #99; // #98 + NameAndType #23 #100; // #99 + Utf8 "(B)Ljava/lang/String;"; // #100 + Field #8 #102; // #101 + NameAndType #103 #97; // #102 + Utf8 "sByteMirror"; // #103 + Field #8 #105; // #104 + NameAndType #106 #97; // #105 + Utf8 "sByte"; // #106 + InvokeDynamic 1s #108; // #107 + NameAndType #23 #109; // #108 + Utf8 "(BB)Ljava/lang/String;"; // #109 + InvokeDynamic 11s #99; // #110 + Field #8 #112; // #111 + NameAndType #113 #114; // #112 + Utf8 "sfLongMirror"; // #113 + Utf8 "J"; // #114 + Long 0x0000000000000005;; // #115 + InvokeDynamic 12s #118; // #117 + NameAndType #23 #119; // #118 + Utf8 "(J)Ljava/lang/String;"; // #119 + Field #8 #121; // #120 + NameAndType #122 #114; // #121 + Utf8 "sLongMirror"; // #122 + Field #8 #124; // #123 + NameAndType #125 #114; // #124 + Utf8 "sLong"; // #125 + InvokeDynamic 1s #127; // #126 + NameAndType #23 #128; // #127 + Utf8 "(JJ)Ljava/lang/String;"; // #128 + Long 0x000000000000000F;; // #129 + InvokeDynamic 13s #118; // #131 + Field #8 #133; // #132 + NameAndType #134 #135; // #133 + Utf8 "sfFloatMirror"; // #134 + Utf8 "F"; // #135 + Float 0x40C00000; // #136 + InvokeDynamic 14s #138; // #137 + NameAndType #23 #139; // #138 + Utf8 "(F)Ljava/lang/String;"; // #139 + InvokeDynamic 15s #138; // #140 + Field #8 #142; // #141 + NameAndType #143 #135; // #142 + Utf8 "sFloatMirror"; // #143 + Field #8 #145; // #144 + NameAndType #146 #135; // #145 + Utf8 "sFloat"; // #146 + InvokeDynamic 1s #148; // #147 + NameAndType #23 #149; // #148 + Utf8 "(FF)Ljava/lang/String;"; // #149 + Float 0x41800000; // #150 + InvokeDynamic 16s #138; // #151 + Field #8 #153; // #152 + NameAndType #154 #155; // #153 + Utf8 "sfDoubleMirror"; // #154 + Utf8 "D"; // #155 + Double 0x401C000000000000;; // #156 + InvokeDynamic 17s #159; // #158 + NameAndType #23 #160; // #159 + Utf8 "(D)Ljava/lang/String;"; // #160 + InvokeDynamic 18s #159; // #161 + Field #8 #163; // #162 + NameAndType #164 #155; // #163 + Utf8 "sDoubleMirror"; // #164 + Field #8 #166; // #165 + NameAndType #167 #155; // #166 + Utf8 "sDouble"; // #167 + InvokeDynamic 1s #169; // #168 + NameAndType #23 #170; // #169 + Utf8 "(DD)Ljava/lang/String;"; // #170 + Double 0x4031000000000000;; // #171 + InvokeDynamic 19s #159; // #173 + Field #175 #176; // #174 + Class #177; // #175 + NameAndType #178 #179; // #176 + Utf8 "java/lang/System"; // #177 + Utf8 "out"; // #178 + Utf8 "Ljava/io/PrintStream;"; // #179 + Method #8 #181; // #180 + NameAndType #182 #183; // #181 + Utf8 "run"; // #182 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #183 + Method #175 #185; // #184 + NameAndType #186 #187; // #185 + Utf8 "exit"; // #186 + Utf8 "(I)V"; // #187 + Utf8 "Code"; // #188 + Utf8 "LineNumberTable"; // #189 + Utf8 "StackMapTable"; // #190 + Utf8 "main"; // #191 + Utf8 "([Ljava/lang/String;)V"; // #192 + Utf8 "SourceFile"; // #193 + Utf8 "atrcvl00402m1.java"; // #194 + Utf8 "BootstrapMethods"; // #195 + String #197; // #196 + Utf8 "\u0001 != sfString"; // #197 + String #199; // #198 + Utf8 "\u0001 != \u0001"; // #199 + String #201; // #200 + Utf8 "\u0001 != sString"; // #201 + String #203; // #202 + Utf8 "\u0001 != true"; // #203 + String #205; // #204 + Utf8 "\u0001 != false"; // #205 + String #207; // #206 + Utf8 "\u0001 != 2"; // #207 + String #209; // #208 + Utf8 "\u0001 != 12"; // #209 + String #211; // #210 + Utf8 "\u0001 != \u0002"; // #211 + String #213; // #212 + Utf8 "\u0001"; // #213 + String #215; // #214 + Utf8 "\u0001 != 1"; // #215 + String #217; // #216 + Utf8 "\u0001 != 11"; // #217 + String #219; // #218 + Utf8 "\u0001 != 4"; // #219 + String #221; // #220 + Utf8 "\u0001 != 14"; // #221 + String #223; // #222 + Utf8 "\u0001 != 5"; // #223 + String #225; // #224 + Utf8 "\u0001 != 15"; // #225 + String #227; // #226 + Utf8 "\u0001 != 6.0"; // #227 + String #229; // #228 + Utf8 "\u0001 != 6.0F"; // #229 + String #231; // #230 + Utf8 "\u0001 != 16.0F"; // #231 + String #233; // #232 + Utf8 "\u0001 != 7.0"; // #233 + String #235; // #234 + Utf8 "\u0001 != 7.0D"; // #235 + String #237; // #236 + Utf8 "\u0001 != 17.0D"; // #237 + MethodHandle 6b #239; // #238 + Method #240 #241; // #239 + Class #242; // #240 + NameAndType #23 #243; // #241 + Utf8 "java/lang/invoke/StringConcatFactory"; // #242 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #243 + Utf8 "InnerClasses"; // #244 + Class #246; // #245 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #246 + Class #248; // #247 + Utf8 "java/lang/invoke/MethodHandles"; // #248 + Utf8 "Lookup"; // #249 + } + + 0x0021; // access + #8; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#188) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#189) { // LineNumberTable + [] { // line_number_table + 0 13; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #182; // name_index + #183; // descriptor_index + [] { // Attributes + Attr(#188) { // Code + 5; // max_stack + 2; // max_locals + Bytes[]{ + 0xB2 0x00 0x07 0x12 0x0D 0xB6 0x00 0x0F 0x9A 0x00 0x11 0x2B; + 0xB2 0x00 0x07 0xBA 0x00 0x15 0x00 0x00 0xB6 0x00 0x19 0x05; + 0xAC 0xB2 0x00 0x07 0x12 0x0D 0xB6 0x00 0x0F 0x9A 0x00 0x11; + 0x2B 0xB2 0x00 0x07 0xBA 0x00 0x15 0x00 0x00 0xB6 0x00 0x19; + 0x05 0xAC 0xB2 0x00 0x1F 0xB2 0x00 0x22 0xB6 0x00 0x0F 0x9A; + 0x00 0x14 0x2B 0xB2 0x00 0x1F 0xB2 0x00 0x22 0xBA 0x00 0x25; + 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x1F 0x12 0x28; + 0xB6 0x00 0x0F 0x9A 0x00 0x11 0x2B 0xB2 0x00 0x1F 0xBA 0x00; + 0x29 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x2A 0x04; + 0x9F 0x00 0x11 0x2B 0xB2 0x00 0x2A 0xBA 0x00 0x2E 0x00 0x00; + 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x2A 0x04 0x9F 0x00 0x11; + 0x2B 0xB2 0x00 0x2A 0xBA 0x00 0x2E 0x00 0x00 0xB6 0x00 0x19; + 0x05 0xAC 0xB2 0x00 0x31 0xB2 0x00 0x34 0x9F 0x00 0x14 0x2B; + 0xB2 0x00 0x31 0xB2 0x00 0x34 0xBA 0x00 0x37 0x00 0x00 0xB6; + 0x00 0x19 0x05 0xAC 0xB2 0x00 0x31 0x99 0x00 0x11 0x2B 0xB2; + 0x00 0x31 0xBA 0x00 0x3A 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC; + 0xB2 0x00 0x3B 0x05 0x9F 0x00 0x11 0x2B 0xB2 0x00 0x3B 0xBA; + 0x00 0x3F 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x3B; + 0x05 0x9F 0x00 0x11 0x2B 0xB2 0x00 0x3B 0xBA 0x00 0x3F 0x00; + 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x42 0xB2 0x00 0x45; + 0x9F 0x00 0x14 0x2B 0xB2 0x00 0x42 0xB2 0x00 0x45 0xBA 0x00; + 0x48 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x42 0x10; + 0x0C 0x9F 0x00 0x11 0x2B 0xB2 0x00 0x42 0xBA 0x00 0x4B 0x00; + 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x4C 0x04 0x9F 0x00; + 0x11 0x2B 0xB2 0x00 0x4C 0xBA 0x00 0x50 0x00 0x00 0xB6 0x00; + 0x19 0x05 0xAC 0xB2 0x00 0x4C 0x04 0x9F 0x00 0x11 0x2B 0xB2; + 0x00 0x4C 0xBA 0x00 0x53 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC; + 0xB2 0x00 0x54 0xB2 0x00 0x57 0x9F 0x00 0x14 0x2B 0xB2 0x00; + 0x54 0xB2 0x00 0x57 0xBA 0x00 0x5A 0x00 0x00 0xB6 0x00 0x19; + 0x05 0xAC 0xB2 0x00 0x54 0x10 0x0B 0x9F 0x00 0x11 0x2B 0xB2; + 0x00 0x54 0xBA 0x00 0x5D 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC; + 0xB2 0x00 0x5E 0x07 0x9F 0x00 0x11 0x2B 0xB2 0x00 0x5E 0xBA; + 0x00 0x62 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x5E; + 0x07 0x9F 0x00 0x11 0x2B 0xB2 0x00 0x5E 0xBA 0x00 0x62 0x00; + 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x65 0xB2 0x00 0x68; + 0x9F 0x00 0x14 0x2B 0xB2 0x00 0x65 0xB2 0x00 0x68 0xBA 0x00; + 0x6B 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x65 0x10; + 0x0E 0x9F 0x00 0x11 0x2B 0xB2 0x00 0x65 0xBA 0x00 0x6E 0x00; + 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x6F 0x14 0x00 0x73; + 0x94 0x99 0x00 0x11 0x2B 0xB2 0x00 0x6F 0xBA 0x00 0x75 0x00; + 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x6F 0x14 0x00 0x73; + 0x94 0x99 0x00 0x11 0x2B 0xB2 0x00 0x6F 0xBA 0x00 0x75 0x00; + 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x78 0xB2 0x00 0x7B; + 0x94 0x99 0x00 0x14 0x2B 0xB2 0x00 0x78 0xB2 0x00 0x7B 0xBA; + 0x00 0x7E 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x78; + 0x14 0x00 0x81 0x94 0x99 0x00 0x11 0x2B 0xB2 0x00 0x78 0xBA; + 0x00 0x83 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x84; + 0x12 0x88 0x95 0x99 0x00 0x11 0x2B 0xB2 0x00 0x84 0xBA 0x00; + 0x89 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x84 0x12; + 0x88 0x95 0x99 0x00 0x11 0x2B 0xB2 0x00 0x84 0xBA 0x00 0x8C; + 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x8D 0xB2 0x00; + 0x90 0x95 0x99 0x00 0x14 0x2B 0xB2 0x00 0x8D 0xB2 0x00 0x90; + 0xBA 0x00 0x93 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00; + 0x8D 0x12 0x96 0x95 0x99 0x00 0x11 0x2B 0xB2 0x00 0x8D 0xBA; + 0x00 0x97 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x98; + 0x14 0x00 0x9C 0x97 0x99 0x00 0x11 0x2B 0xB2 0x00 0x98 0xBA; + 0x00 0x9E 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0x98; + 0x14 0x00 0x9C 0x97 0x99 0x00 0x11 0x2B 0xB2 0x00 0x98 0xBA; + 0x00 0xA1 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC 0xB2 0x00 0xA2; + 0xB2 0x00 0xA5 0x97 0x99 0x00 0x14 0x2B 0xB2 0x00 0xA2 0xB2; + 0x00 0xA5 0xBA 0x00 0xA8 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC; + 0xB2 0x00 0xA2 0x14 0x00 0xAB 0x97 0x99 0x00 0x11 0x2B 0xB2; + 0x00 0xA2 0xBA 0x00 0xAD 0x00 0x00 0xB6 0x00 0x19 0x05 0xAC; + 0x03 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#189) { // LineNumberTable + [] { // line_number_table + 0 17; + 11 18; + 23 19; + 25 21; + 36 22; + 48 23; + 50 27; + 62 28; + 77 29; + 79 31; + 90 32; + 102 33; + 104 37; + 111 38; + 123 39; + 125 41; + 132 42; + 144 43; + 146 47; + 155 48; + 170 49; + 172 51; + 178 52; + 190 53; + 192 57; + 199 58; + 211 59; + 213 61; + 220 62; + 232 63; + 234 67; + 243 68; + 258 69; + 260 71; + 268 72; + 280 73; + 282 77; + 289 78; + 301 79; + 303 81; + 310 82; + 322 83; + 324 87; + 333 88; + 348 89; + 350 91; + 358 92; + 370 93; + 372 97; + 379 98; + 391 99; + 393 101; + 400 102; + 412 103; + 414 107; + 423 108; + 438 109; + 440 111; + 448 112; + 460 113; + 462 117; + 472 118; + 484 119; + 486 121; + 496 122; + 508 123; + 510 127; + 520 128; + 535 129; + 537 131; + 547 132; + 559 133; + 561 137; + 570 138; + 582 139; + 584 141; + 593 142; + 605 143; + 607 147; + 617 148; + 632 149; + 634 151; + 643 152; + 655 153; + 657 157; + 667 158; + 679 159; + 681 161; + 691 162; + 703 163; + 705 167; + 715 168; + 730 169; + 732 171; + 742 172; + 754 173; + 756 176; + } + } // end of LineNumberTable + ; + Attr(#190) { // StackMapTable + [] { // + 25b; // same_frame + 24b; // same_frame + 28b; // same_frame + 24b; // same_frame + 20b; // same_frame + 20b; // same_frame + 25b; // same_frame + 19b; // same_frame + 20b; // same_frame + 20b; // same_frame + 25b; // same_frame + 21b; // same_frame + 20b; // same_frame + 20b; // same_frame + 25b; // same_frame + 21b; // same_frame + 20b; // same_frame + 20b; // same_frame + 25b; // same_frame + 21b; // same_frame + 23b; // same_frame + 23b; // same_frame + 26b; // same_frame + 23b; // same_frame + 22b; // same_frame + 22b; // same_frame + 26b; // same_frame + 22b; // same_frame + 23b; // same_frame + 23b; // same_frame + 26b; // same_frame + 23b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #191; // name_index + #192; // descriptor_index + [] { // Attributes + Attr(#188) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0xAE 0xB8 0x00 0xB4 0x10 0x5F 0x60 0xB8 0x00; + 0xB8 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#189) { // LineNumberTable + [] { // line_number_table + 0 180; + 13 181; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#193) { // SourceFile + #194; + } // end of SourceFile + ; + Attr(#195) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #196; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #198; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #200; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #202; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #204; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #206; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #208; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #210; + #212; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #214; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #216; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #218; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #220; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #222; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #224; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #226; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #228; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #230; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #232; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #234; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #238; // bootstrap_method_ref + [] { // bootstrap_arguments + #236; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#244) { // InnerClasses + [] { // classes + #245 #247 #249 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1t.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1t.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1t.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00402m1t.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,507 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00402m1/atrcvl00402m1t { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Field #112 #54; // #1 + Field #112 #56; // #2 + Field #112 #109; // #3 + Field #112 #38; // #4 + Field #112 #50; // #5 + Field #112 #89; // #6 + Field #112 #105; // #7 + Field #112 #61; // #8 + Field #112 #47; // #9 + Field #112 #74; // #10 + Field #112 #110; // #11 + Field #112 #136; // #12 + Field #112 #77; // #13 + Field #112 #101; // #14 + Field #112 #113; // #15 + Field #112 #76; // #16 + Field #112 #124; // #17 + Field #112 #85; // #18 + Field #112 #96; // #19 + Field #112 #57; // #20 + Field #112 #60; // #21 + Field #112 #95; // #22 + Field #112 #42; // #23 + Field #112 #43; // #24 + Method #46 #106; // #25 + Field #112 #98; // #26 + Field #112 #68; // #27 + Field #112 #119; // #28 + Field #112 #102; // #29 + Field #112 #111; // #30 + Field #112 #84; // #31 + Field #112 #127; // #32 + Field #112 #37; // #33 + Utf8 "sfByteMirror"; // #34 + Utf8 "sfChar"; // #35 + Utf8 "sLongMirror"; // #36 + NameAndType #94 #116; // #37 + NameAndType #83 #128; // #38 + Utf8 "ConstantValue"; // #39 + Utf8 "B"; // #40 + Utf8 "sBooleanMirror"; // #41 + NameAndType #70 #81; // #42 + NameAndType #73 #134; // #43 + Utf8 "sfLong"; // #44 + Float 0x40C00000; // #45 + Class #92; // #46 + NameAndType #71 #135; // #47 + Integer 0x00000004; // #48 + Utf8 "sfString"; // #49 + NameAndType #66 #128; // #50 + Integer 0x0000000E; // #51 + Utf8 "sfBoolean"; // #52 + Utf8 "sfDouble"; // #53 + NameAndType #93 #81; // #54 + Utf8 "sByte"; // #55 + NameAndType #41 #125; // #56 + NameAndType #107 #135; // #57 + Utf8 "sfDoubleMirror"; // #58 + Utf8 "J"; // #59 + NameAndType #34 #40; // #60 + NameAndType #91 #59; // #61 + Utf8 "sfFloatMirror"; // #62 + Double 0x401C000000000000;; // #63 + Integer 0x00000002; // #65 + Utf8 "sDoubleMirror"; // #66 + Utf8 "Code"; // #67 + NameAndType #75 #116; // #68 + Utf8 "sFloatMirror"; // #69 + Utf8 "sShort"; // #70 + Utf8 "sChar"; // #71 + Integer 0x0000000C; // #72 + Utf8 "sString"; // #73 + NameAndType #121 #134; // #74 + Utf8 "sFloat"; // #75 + NameAndType #117 #125; // #76 + NameAndType #49 #134; // #77 + Long 0x0000000000000005;; // #78 + Integer 0x00000001; // #80 + Utf8 "S"; // #81 + String #49; // #82 + Utf8 "sDouble"; // #83 + NameAndType #118 #134; // #84 + NameAndType #132 #59; // #85 + Long 0x000000000000000F;; // #86 + Utf8 "sfShort"; // #88 + NameAndType #120 #135; // #89 + Integer 0x0000000B; // #90 + Utf8 "sLong"; // #91 + Utf8 "java/lang/Object"; // #92 + Utf8 "sfShortMirror"; // #93 + Utf8 "sfFloat"; // #94 + NameAndType #126 #81; // #95 + NameAndType #133 #40; // #96 + Utf8 "()V"; // #97 + NameAndType #58 #128; // #98 + Integer 0x00000000; // #99 + Utf8 ""; // #100 + NameAndType #52 #125; // #101 + NameAndType #44 #59; // #102 + Double 0x4031000000000000;; // #103 + NameAndType #62 #116; // #105 + NameAndType #108 #97; // #106 + Utf8 "sfCharMirror"; // #107 + Utf8 ""; // #108 + NameAndType #53 #128; // #109 + NameAndType #129 #125; // #110 + NameAndType #35 #135; // #111 + Class #131; // #112 + NameAndType #36 #59; // #113 + Utf8 "atrcvl00402m1t.jasm"; // #114 + Float 0x41800000; // #115 + Utf8 "F"; // #116 + Utf8 "sBoolean"; // #117 + Utf8 "sfStringMirror"; // #118 + NameAndType #55 #40; // #119 + Utf8 "sCharMirror"; // #120 + Utf8 "sStringMirror"; // #121 + Utf8 "SourceFile"; // #122 + String #73; // #123 + NameAndType #88 #81; // #124 + Utf8 "Z"; // #125 + Utf8 "sShortMirror"; // #126 + NameAndType #69 #116; // #127 + Utf8 "D"; // #128 + Utf8 "sfBooleanMirror"; // #129 + Utf8 "sfByte"; // #130 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl004/atrcvl00402m1/atrcvl00402m1t"; // #131 + Utf8 "sfLongMirror"; // #132 + Utf8 "sByteMirror"; // #133 + Utf8 "Ljava/lang/String;"; // #134 + Utf8 "C"; // #135 + NameAndType #130 #40; // #136 + } + + 0x0000; // access + #112; // this_cpx + #46; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #49; // name_index + #134; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #82; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #118; // name_index + #134; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #73; // name_index + #134; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #123; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #121; // name_index + #134; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0018; // access + #52; // name_index + #125; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #80; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #129; // name_index + #125; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #117; // name_index + #125; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #99; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #41; // name_index + #125; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0018; // access + #88; // name_index + #81; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #65; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #93; // name_index + #81; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #70; // name_index + #81; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #72; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #126; // name_index + #81; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0018; // access + #35; // name_index + #135; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #80; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #107; // name_index + #135; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #71; // name_index + #135; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #90; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #120; // name_index + #135; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0018; // access + #130; // name_index + #40; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #48; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #34; // name_index + #40; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #55; // name_index + #40; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #51; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #133; // name_index + #40; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0018; // access + #44; // name_index + #59; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #78; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #132; // name_index + #59; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #91; // name_index + #59; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #86; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #36; // name_index + #59; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0018; // access + #94; // name_index + #116; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #45; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #62; // name_index + #116; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #75; // name_index + #116; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #115; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #69; // name_index + #116; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0018; // access + #53; // name_index + #128; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #63; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #58; // name_index + #128; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #83; // name_index + #128; // descriptor_index + [] { // Attributes + Attr(#39) { // ConstantValue + #103; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #66; // name_index + #128; // descriptor_index + [] { // Attributes + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #108; // name_index + #97; // descriptor_index + [] { // Attributes + Attr(#67) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x19 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0008; // access + #100; // name_index + #97; // descriptor_index + [] { // Attributes + Attr(#67) { // Code + 2; // max_stack + 0; // max_locals + Bytes[]{ + 0xB2 0x00 0x0D 0xB3 0x00 0x1F 0xB2 0x00 0x18 0xB3 0x00 0x0A; + 0xB2 0x00 0x0E 0xB3 0x00 0x0B 0xB2 0x00 0x10 0xB3 0x00 0x02; + 0xB2 0x00 0x11 0xB3 0x00 0x01 0xB2 0x00 0x17 0xB3 0x00 0x16; + 0xB2 0x00 0x1E 0xB3 0x00 0x14 0xB2 0x00 0x09 0xB3 0x00 0x06; + 0xB2 0x00 0x0C 0xB3 0x00 0x15 0xB2 0x00 0x1C 0xB3 0x00 0x13; + 0xB2 0x00 0x1D 0xB3 0x00 0x12 0xB2 0x00 0x08 0xB3 0x00 0x0F; + 0xB2 0x00 0x21 0xB3 0x00 0x07 0xB2 0x00 0x1B 0xB3 0x00 0x20; + 0xB2 0x00 0x03 0xB3 0x00 0x1A 0xB2 0x00 0x04 0xB3 0x00 0x05; + 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#122) { // SourceFile + #114; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00501m1/atrcvl00501m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl005.atrcvl00501m1.atrcvl00501m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl005.atrcvl00501m1.atrcvl00501m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00501m1 failed to reject bad classfile atrcvl00501m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00501m1/atrcvl00501m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00501m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00501m1 failed to load or instantiate good classfile atrcvl00501m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00501m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00501m1/atrcvl00501m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00501m1/atrcvl00501m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#0) { // #0 + 0x00 0x01; + } // end of #0 + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00501m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00501m1/atrcvl00501m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00501m1/atrcvl00501m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00502m1/atrcvl00502m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl005.atrcvl00502m1.atrcvl00502m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl005.atrcvl00502m1.atrcvl00502m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00502m1 failed to reject bad classfile atrcvl00502m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00502m1/atrcvl00502m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00502m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00502m1 failed to load or instantiate good classfile atrcvl00502m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00502m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00502m1/atrcvl00502m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "dummy"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00502m1/atrcvl00502m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "ConstantValue"; // #20 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + // == Corrupted class file. The bytes do not represent a valid class attribute. == + Attr(#21) { // #21 + 0x00 0x01; + } // end of #21 + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00502m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,72 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00502m1/atrcvl00502m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "dummy"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl005/atrcvl00502m1/atrcvl00502m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "ConstantValue"; // #20 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // dummy + 0x00 0x01; + } // end of dummy + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl006/atrcvl00601m1/atrcvl00601m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl006.atrcvl00601m1.atrcvl00601m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl006.atrcvl00601m1.atrcvl00601m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00601m1 failed to reject bad classfile atrcvl00601m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl006/atrcvl00601m1/atrcvl00601m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00601m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00601m1 failed to load or instantiate good classfile atrcvl00601m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00601m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl006/atrcvl00601m1/atrcvl00601m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl006/atrcvl00601m1/atrcvl00601m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#1) { // #1 + 0x00 0x01; + } // end of #1 + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00601m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl006/atrcvl00601m1/atrcvl00601m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl006/atrcvl00601m1/atrcvl00601m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,357 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00701m1/atrcvl00701m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "atrcvl00701m10p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00701m1/atrcvl00701m1"; // #12 + Utf8 "loadPositive"; // #13 + Utf8 "(Ljava/lang/String;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #14 + String #16; // #15 + Utf8 "atrcvl00701m11n"; // #16 + Class #18; // #17 + Utf8 "java/lang/ClassFormatError"; // #18 + Method #10 #20; // #19 + NameAndType #21 #22; // #20 + Utf8 "loadNegative"; // #21 + Utf8 "(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #22 + InvokeDynamic 0s #24; // #23 + NameAndType #25 #26; // #24 + Utf8 "makeConcatWithConstants"; // #25 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #26 + Method #28 #29; // #27 + Class #30; // #28 + NameAndType #31 #32; // #29 + Utf8 "java/lang/Class"; // #30 + Utf8 "forName"; // #31 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #32 + Class #34; // #33 + Utf8 "java/lang/ThreadDeath"; // #34 + Class #36; // #35 + Utf8 "java/lang/Throwable"; // #36 + Method #38 #39; // #37 + Class #40; // #38 + NameAndType #41 #42; // #39 + Utf8 "java/lang/String"; // #40 + Utf8 "valueOf"; // #41 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #42 + InvokeDynamic 1s #24; // #43 + Method #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/io/PrintStream"; // #47 + Utf8 "println"; // #48 + Utf8 "(Ljava/lang/String;)V"; // #49 + Method #28 #51; // #50 + NameAndType #52 #53; // #51 + Utf8 "isInstance"; // #52 + Utf8 "(Ljava/lang/Object;)Z"; // #53 + InvokeDynamic 2s #24; // #54 + InvokeDynamic 3s #24; // #55 + InvokeDynamic 4s #24; // #56 + Field #58 #59; // #57 + Class #60; // #58 + NameAndType #61 #62; // #59 + Utf8 "java/lang/System"; // #60 + Utf8 "out"; // #61 + Utf8 "Ljava/io/PrintStream;"; // #62 + Method #10 #64; // #63 + NameAndType #65 #66; // #64 + Utf8 "run"; // #65 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #66 + Method #58 #68; // #67 + NameAndType #69 #70; // #68 + Utf8 "exit"; // #69 + Utf8 "(I)V"; // #70 + Utf8 "Code"; // #71 + Utf8 "LineNumberTable"; // #72 + Utf8 "StackMapTable"; // #73 + Class #75; // #74 + Utf8 "[Ljava/lang/String;"; // #75 + Utf8 "main"; // #76 + Utf8 "([Ljava/lang/String;)V"; // #77 + Utf8 "SourceFile"; // #78 + Utf8 "atrcvl00701m1.java"; // #79 + Utf8 "BootstrapMethods"; // #80 + String #82; // #81 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl007.atrcvl00701m1.\u0001"; // #82 + String #84; // #83 + Utf8 "Failed with loading exception: \u0001"; // #84 + String #86; // #85 + Utf8 "Passed with loading exception: \u0001"; // #86 + String #88; // #87 + Utf8 "Failed with unexpected loading exception: \u0001"; // #88 + String #90; // #89 + Utf8 "Failed to reject invalid class \u0001"; // #90 + MethodHandle 6b #92; // #91 + Method #93 #94; // #92 + Class #95; // #93 + NameAndType #25 #96; // #94 + Utf8 "java/lang/invoke/StringConcatFactory"; // #95 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #96 + Utf8 "InnerClasses"; // #97 + Class #99; // #98 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #99 + Class #101; // #100 + Utf8 "java/lang/invoke/MethodHandles"; // #101 + Utf8 "Lookup"; // #102 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 12; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #65; // name_index + #66; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 4; // max_stack + 2; // max_locals + Bytes[]{ + 0x12 0x07 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x0F 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 16; + 10 17; + 12 18; + 24 19; + 26 21; + } + } // end of LineNumberTable + ; + Attr(#73) { // StackMapTable + [] { // + 12b; // same_frame + 13b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x01 0x4E 0x2A 0xBA 0x00 0x17 0x00 0x00 0xB8 0x00 0x1B 0x4E; + 0xA7 0x00 0x1A 0x3A 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19; + 0x04 0xB8 0x00 0x25 0xBA 0x00 0x2B 0x00 0x00 0xB6 0x00 0x2C; + 0x05 0xAC 0x03 0xAC } + [] { // Traps + 2 12 15 33; + 2 12 20 35; + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 26; + 2 28; + 12 34; + 15 29; + 17 30; + 20 31; + 22 32; + 36 33; + 38 36; + } + } // end of LineNumberTable + ; + Attr(#73) { // StackMapTable + [] { // + 255b, 15, []{O,#38; O,#74; O,#45; O,#28}, []{O,#33}; // full_frame + 68b, []z{O,#35}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #21; // name_index + #22; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 2; // max_stack + 6; // max_locals + Bytes[]{ + 0x01 0x3A 0x04 0x2A 0xBA 0x00 0x17 0x00 0x00 0xB8 0x00 0x1B; + 0x3A 0x04 0xA7 0x00 0x33 0x3A 0x05 0x19 0x05 0xBF 0x3A 0x05; + 0x2B 0x19 0x05 0xB6 0x00 0x32 0x99 0x00 0x13 0x2D 0x19 0x05; + 0xB8 0x00 0x25 0xBA 0x00 0x36 0x00 0x00 0xB6 0x00 0x2C 0x03; + 0xAC 0x2D 0x19 0x05 0xB8 0x00 0x25 0xBA 0x00 0x37 0x00 0x00; + 0xB6 0x00 0x2C 0x05 0xAC 0x2D 0x2A 0xBA 0x00 0x38 0x00 0x00; + 0xB6 0x00 0x2C 0x05 0xAC; + } + [] { // Traps + 3 14 17 33; + 3 14 22 35; + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 41; + 3 43; + 14 54; + 17 44; + 19 45; + 22 46; + 24 47; + 33 48; + 47 49; + 49 51; + 63 52; + 65 55; + 75 56; + } + } // end of LineNumberTable + ; + Attr(#73) { // StackMapTable + [] { // + 255b, 17, []{O,#38; O,#28; O,#74; O,#45; O,#28}, []{O,#33}; // full_frame + 68b, []z{O,#35}; // same_locals_1_stack_item_frame + 252b, 26, []z{O,#35}; // append_frame 1 + 250b, 15; // chop_frame 1 + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #76; // name_index + #77; // descriptor_index + [] { // Attributes + Attr(#71) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x39 0xB8 0x00 0x3F 0x10 0x5F 0x60 0xB8 0x00; + 0x43 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#72) { // LineNumberTable + [] { // line_number_table + 0 60; + 13 61; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#78) { // SourceFile + #79; + } // end of SourceFile + ; + Attr(#80) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #91; // bootstrap_method_ref + [] { // bootstrap_arguments + #81; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #91; // bootstrap_method_ref + [] { // bootstrap_arguments + #83; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #91; // bootstrap_method_ref + [] { // bootstrap_arguments + #85; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #91; // bootstrap_method_ref + [] { // bootstrap_arguments + #87; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #91; // bootstrap_method_ref + [] { // bootstrap_arguments + #89; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#97) { // InnerClasses + [] { // classes + #98 #100 #102 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m10p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m10p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m10p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m10p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00701m1/atrcvl00701m10p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #4; // #1 + Class #5; // #2 + Field #2 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00701m1/atrcvl00701m10p"; // #5 + NameAndType #8 #9; // #6 + Utf8 "ConstantValue"; // #7 + Utf8 "number"; // #8 + Utf8 "I"; // #9 + Integer 0x0000007B; // #10 + } + + 0x0001; // access + #2; // this_cpx + #1; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0009; // access + #8; // name_index + #9; // descriptor_index + [] { // Attributes + Attr(#7) { // ConstantValue + #10; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m11n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m11n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m11n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00701m11n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00701m1/atrcvl00701m11n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #4; // #1 + Class #5; // #2 + Field #2 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00701m1/atrcvl00701m11n"; // #5 + NameAndType #8 #9; // #6 + Utf8 "ConstantValue"; // #7 + Utf8 "number"; // #8 + Utf8 "I"; // #9 + Integer 0x0000007B; // #10 + } + + 0x0001; // access + #2; // this_cpx + #1; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0009; // access + #8; // name_index + #9; // descriptor_index + [] { // Attributes + Attr(#7) { // ConstantValue + // == invalid length of ConstantValue attr: 4 (should be 2) == + 0x0000000A; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,362 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "atrcvl00702m10p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m1"; // #12 + Utf8 "loadPositive"; // #13 + Utf8 "(Ljava/lang/String;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #14 + String #16; // #15 + Utf8 "atrcvl00702m11p"; // #16 + String #18; // #17 + Utf8 "atrcvl00702m12n"; // #18 + Class #20; // #19 + Utf8 "java/lang/ClassFormatError"; // #20 + Method #10 #22; // #21 + NameAndType #23 #24; // #22 + Utf8 "loadNegative"; // #23 + Utf8 "(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #24 + InvokeDynamic 0s #26; // #25 + NameAndType #27 #28; // #26 + Utf8 "makeConcatWithConstants"; // #27 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #28 + Method #30 #31; // #29 + Class #32; // #30 + NameAndType #33 #34; // #31 + Utf8 "java/lang/Class"; // #32 + Utf8 "forName"; // #33 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #34 + Class #36; // #35 + Utf8 "java/lang/ThreadDeath"; // #36 + Class #38; // #37 + Utf8 "java/lang/Throwable"; // #38 + Method #40 #41; // #39 + Class #42; // #40 + NameAndType #43 #44; // #41 + Utf8 "java/lang/String"; // #42 + Utf8 "valueOf"; // #43 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #44 + InvokeDynamic 1s #26; // #45 + Method #47 #48; // #46 + Class #49; // #47 + NameAndType #50 #51; // #48 + Utf8 "java/io/PrintStream"; // #49 + Utf8 "println"; // #50 + Utf8 "(Ljava/lang/String;)V"; // #51 + Method #30 #53; // #52 + NameAndType #54 #55; // #53 + Utf8 "isInstance"; // #54 + Utf8 "(Ljava/lang/Object;)Z"; // #55 + InvokeDynamic 2s #26; // #56 + InvokeDynamic 3s #26; // #57 + InvokeDynamic 4s #26; // #58 + Field #60 #61; // #59 + Class #62; // #60 + NameAndType #63 #64; // #61 + Utf8 "java/lang/System"; // #62 + Utf8 "out"; // #63 + Utf8 "Ljava/io/PrintStream;"; // #64 + Method #10 #66; // #65 + NameAndType #67 #68; // #66 + Utf8 "run"; // #67 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #68 + Method #60 #70; // #69 + NameAndType #71 #72; // #70 + Utf8 "exit"; // #71 + Utf8 "(I)V"; // #72 + Utf8 "Code"; // #73 + Utf8 "LineNumberTable"; // #74 + Utf8 "StackMapTable"; // #75 + Class #77; // #76 + Utf8 "[Ljava/lang/String;"; // #77 + Utf8 "main"; // #78 + Utf8 "([Ljava/lang/String;)V"; // #79 + Utf8 "SourceFile"; // #80 + Utf8 "atrcvl00702m1.java"; // #81 + Utf8 "BootstrapMethods"; // #82 + String #84; // #83 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl007.atrcvl00702m1.\u0001"; // #84 + String #86; // #85 + Utf8 "Failed with loading exception: \u0001"; // #86 + String #88; // #87 + Utf8 "Passed with loading exception: \u0001"; // #88 + String #90; // #89 + Utf8 "Failed with unexpected loading exception: \u0001"; // #90 + String #92; // #91 + Utf8 "Failed to reject invalid class \u0001"; // #92 + MethodHandle 6b #94; // #93 + Method #95 #96; // #94 + Class #97; // #95 + NameAndType #27 #98; // #96 + Utf8 "java/lang/invoke/StringConcatFactory"; // #97 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #98 + Utf8 "InnerClasses"; // #99 + Class #101; // #100 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #101 + Class #103; // #102 + Utf8 "java/lang/invoke/MethodHandles"; // #103 + Utf8 "Lookup"; // #104 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#73) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#74) { // LineNumberTable + [] { // line_number_table + 0 12; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #67; // name_index + #68; // descriptor_index + [] { // Attributes + Attr(#73) { // Code + 4; // max_stack + 2; // max_locals + Bytes[]{ + 0x12 0x07 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x0F 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x11 0x12 0x13 0x2A 0x2B 0xB8 0x00 0x15 0x99 0x00 0x05; + 0x05 0xAC 0x03 0xAC } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#74) { // LineNumberTable + [] { // line_number_table + 0 16; + 10 17; + 12 18; + 22 19; + 24 20; + 36 21; + 38 23; + } + } // end of LineNumberTable + ; + Attr(#75) { // StackMapTable + [] { // + 12b; // same_frame + 11b; // same_frame + 13b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#73) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x01 0x4E 0x2A 0xBA 0x00 0x19 0x00 0x00 0xB8 0x00 0x1D 0x4E; + 0xA7 0x00 0x1A 0x3A 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19; + 0x04 0xB8 0x00 0x27 0xBA 0x00 0x2D 0x00 0x00 0xB6 0x00 0x2E; + 0x05 0xAC 0x03 0xAC } + [] { // Traps + 2 12 15 35; + 2 12 20 37; + } // end of Traps + [] { // Attributes + Attr(#74) { // LineNumberTable + [] { // line_number_table + 0 28; + 2 30; + 12 36; + 15 31; + 17 32; + 20 33; + 22 34; + 36 35; + 38 38; + } + } // end of LineNumberTable + ; + Attr(#75) { // StackMapTable + [] { // + 255b, 15, []{O,#40; O,#76; O,#47; O,#30}, []{O,#35}; // full_frame + 68b, []z{O,#37}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #23; // name_index + #24; // descriptor_index + [] { // Attributes + Attr(#73) { // Code + 2; // max_stack + 6; // max_locals + Bytes[]{ + 0x01 0x3A 0x04 0x2A 0xBA 0x00 0x19 0x00 0x00 0xB8 0x00 0x1D; + 0x3A 0x04 0xA7 0x00 0x33 0x3A 0x05 0x19 0x05 0xBF 0x3A 0x05; + 0x2B 0x19 0x05 0xB6 0x00 0x34 0x99 0x00 0x13 0x2D 0x19 0x05; + 0xB8 0x00 0x27 0xBA 0x00 0x38 0x00 0x00 0xB6 0x00 0x2E 0x03; + 0xAC 0x2D 0x19 0x05 0xB8 0x00 0x27 0xBA 0x00 0x39 0x00 0x00; + 0xB6 0x00 0x2E 0x05 0xAC 0x2D 0x2A 0xBA 0x00 0x3A 0x00 0x00; + 0xB6 0x00 0x2E 0x05 0xAC; + } + [] { // Traps + 3 14 17 35; + 3 14 22 37; + } // end of Traps + [] { // Attributes + Attr(#74) { // LineNumberTable + [] { // line_number_table + 0 43; + 3 45; + 14 56; + 17 46; + 19 47; + 22 48; + 24 49; + 33 50; + 47 51; + 49 53; + 63 54; + 65 57; + 75 58; + } + } // end of LineNumberTable + ; + Attr(#75) { // StackMapTable + [] { // + 255b, 17, []{O,#40; O,#30; O,#76; O,#47; O,#30}, []{O,#35}; // full_frame + 68b, []z{O,#37}; // same_locals_1_stack_item_frame + 252b, 26, []z{O,#37}; // append_frame 1 + 250b, 15; // chop_frame 1 + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #78; // name_index + #79; // descriptor_index + [] { // Attributes + Attr(#73) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x3B 0xB8 0x00 0x41 0x10 0x5F 0x60 0xB8 0x00; + 0x45 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#74) { // LineNumberTable + [] { // line_number_table + 0 62; + 13 63; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#80) { // SourceFile + #81; + } // end of SourceFile + ; + Attr(#82) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #93; // bootstrap_method_ref + [] { // bootstrap_arguments + #83; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #93; // bootstrap_method_ref + [] { // bootstrap_arguments + #85; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #93; // bootstrap_method_ref + [] { // bootstrap_arguments + #87; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #93; // bootstrap_method_ref + [] { // bootstrap_arguments + #89; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #93; // bootstrap_method_ref + [] { // bootstrap_arguments + #91; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#99) { // InnerClasses + [] { // classes + #100 #102 #104 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m10p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m10p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m10p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m10p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m10p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #4; // #1 + Class #5; // #2 + Field #2 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m10p"; // #5 + NameAndType #8 #9; // #6 + Utf8 "constantValue"; // #7 + Utf8 "number"; // #8 + Utf8 "I"; // #9 + Integer 0x0000007B; // #10 + } + + 0x0001; // access + #2; // this_cpx + #1; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0009; // access + #8; // name_index + #9; // descriptor_index + [] { // Attributes + Attr(#7) { // constantValue + 0x00 0x00 0x00 0x0A; + } // end of constantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m11p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m11p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m11p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m11p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m11p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #4; // #1 + Class #5; // #2 + Field #2 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m11p"; // #5 + NameAndType #8 #9; // #6 + Utf8 "ConstantValue1"; // #7 + Utf8 "number"; // #8 + Utf8 "I"; // #9 + Integer 0x0000007B; // #10 + } + + 0x0001; // access + #2; // this_cpx + #1; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0009; // access + #8; // name_index + #9; // descriptor_index + [] { // Attributes + Attr(#7) { // ConstantValue1 + 0x00 0x00 0x00 0x0A; + } // end of ConstantValue1 + } // end of Attributes + } + } // end of Fields + + [] { // Methods + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m12n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m12n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m12n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00702m12n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m12n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #4; // #1 + Class #5; // #2 + Field #2 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl007/atrcvl00702m1/atrcvl00702m12n"; // #5 + NameAndType #8 #9; // #6 + Utf8 "ConstantValue"; // #7 + Utf8 "number"; // #8 + Utf8 "I"; // #9 + Integer 0x0000007B; // #10 + } + + 0x0001; // access + #2; // this_cpx + #1; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0009; // access + #8; // name_index + #9; // descriptor_index + [] { // Attributes + Attr(#7) { // ConstantValue + // == invalid length of ConstantValue attr: 4 (should be 2) == + 0x0000000A; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00801m1/atrcvl00801m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl008.atrcvl00801m1.atrcvl00801m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl008.atrcvl00801m1.atrcvl00801m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00801m1 failed to reject bad classfile atrcvl00801m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00801m1/atrcvl00801m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00801m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00801m1 failed to load or instantiate good classfile atrcvl00801m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00801m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00801m1/atrcvl00801m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00801m1/atrcvl00801m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #0; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00801m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00801m1/atrcvl00801m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00801m1/atrcvl00801m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00802m1/atrcvl00802m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl008.atrcvl00802m1.atrcvl00802m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl008.atrcvl00802m1.atrcvl00802m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00802m1 failed to reject bad classfile atrcvl00802m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00802m1/atrcvl00802m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00802m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00802m1 failed to load or instantiate good classfile atrcvl00802m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00802m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00802m1/atrcvl00802m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00802m1/atrcvl00802m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #20; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00802m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00802m1/atrcvl00802m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl008/atrcvl00802m1/atrcvl00802m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00901m1/atrcvl00901m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00901m1.atrcvl00901m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00901m1.atrcvl00901m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00901m1 failed to reject bad classfile atrcvl00901m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00901m1/atrcvl00901m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00901m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00901m1 failed to load or instantiate good classfile atrcvl00901m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00901m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,70 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00901m1/atrcvl00901m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00901m1/atrcvl00901m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #2; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00901m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,70 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00901m1/atrcvl00901m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00901m1/atrcvl00901m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00902m1/atrcvl00902m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00902m1.atrcvl00902m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00902m1.atrcvl00902m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00902m1 failed to reject bad classfile atrcvl00902m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00902m1/atrcvl00902m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00902m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00902m1 failed to load or instantiate good classfile atrcvl00902m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00902m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00902m1/atrcvl00902m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000010; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "I"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00902m1/atrcvl00902m1n"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00902m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00902m1/atrcvl00902m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000010; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "I"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00902m1/atrcvl00902m1p"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00903m1/atrcvl00903m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00903m1.atrcvl00903m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00903m1.atrcvl00903m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00903m1 failed to reject bad classfile atrcvl00903m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00903m1/atrcvl00903m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00903m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00903m1 failed to load or instantiate good classfile atrcvl00903m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00903m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00903m1/atrcvl00903m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000001; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Z"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00903m1/atrcvl00903m1n"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00903m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00903m1/atrcvl00903m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000001; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Z"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00903m1/atrcvl00903m1p"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00904m1/atrcvl00904m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00904m1.atrcvl00904m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00904m1.atrcvl00904m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00904m1 failed to reject bad classfile atrcvl00904m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00904m1/atrcvl00904m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00904m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00904m1 failed to load or instantiate good classfile atrcvl00904m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00904m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00904m1/atrcvl00904m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000010; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "S"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00904m1/atrcvl00904m1n"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00904m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00904m1/atrcvl00904m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000010; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "S"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00904m1/atrcvl00904m1p"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00905m1/atrcvl00905m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00905m1.atrcvl00905m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00905m1.atrcvl00905m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00905m1 failed to reject bad classfile atrcvl00905m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00905m1/atrcvl00905m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00905m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00905m1 failed to load or instantiate good classfile atrcvl00905m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00905m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00905m1/atrcvl00905m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Float 0x41200000; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "F"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00905m1/atrcvl00905m1n"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00905m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00905m1/atrcvl00905m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Float 0x41200000; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "F"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00905m1/atrcvl00905m1p"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00906m1/atrcvl00906m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00906m1.atrcvl00906m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00906m1.atrcvl00906m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00906m1 failed to reject bad classfile atrcvl00906m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00906m1/atrcvl00906m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00906m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00906m1 failed to load or instantiate good classfile atrcvl00906m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00906m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00906m1/atrcvl00906m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000010; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "B"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00906m1/atrcvl00906m1n"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00906m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00906m1/atrcvl00906m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00000010; // #1 + Class #13; // #2 + Class #16; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "B"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "SourceFile"; // #12 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00906m1/atrcvl00906m1p"; // #13 + Utf8 "Test.java"; // #14 + Utf8 "i"; // #15 + Utf8 "java/lang/Object"; // #16 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #15; // name_index + #10; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#12) { // SourceFile + #14; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00907m1/atrcvl00907m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00907m1.atrcvl00907m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00907m1.atrcvl00907m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00907m1 failed to reject bad classfile atrcvl00907m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00907m1/atrcvl00907m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00907m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00907m1 failed to load or instantiate good classfile atrcvl00907m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00907m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00907m1/atrcvl00907m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #14; // #1 + Class #17; // #2 + Method #2 #6; // #3 + Long 0x000000000000000A;; // #4 + NameAndType #8 #7; // #6 + Utf8 "()V"; // #7 + Utf8 ""; // #8 + Utf8 "Code"; // #9 + Utf8 "ConstantValue"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "SourceFile"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00907m1/atrcvl00907m1n"; // #14 + Utf8 "Test.java"; // #15 + Utf8 "i"; // #16 + Utf8 "java/lang/Object"; // #17 + } + + 0x0021; // access + #1; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #16; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#10) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #8; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#9) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#12) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#13) { // SourceFile + #15; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00907m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00907m1/atrcvl00907m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #14; // #1 + Class #17; // #2 + Method #2 #6; // #3 + Long 0x000000000000000A;; // #4 + NameAndType #8 #7; // #6 + Utf8 "()V"; // #7 + Utf8 ""; // #8 + Utf8 "Code"; // #9 + Utf8 "ConstantValue"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "SourceFile"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00907m1/atrcvl00907m1p"; // #14 + Utf8 "Test.java"; // #15 + Utf8 "i"; // #16 + Utf8 "java/lang/Object"; // #17 + } + + 0x0021; // access + #1; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #16; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#10) { // ConstantValue + #4; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #8; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#9) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#12) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#13) { // SourceFile + #15; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00908m1/atrcvl00908m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00908m1.atrcvl00908m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00908m1.atrcvl00908m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00908m1 failed to reject bad classfile atrcvl00908m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00908m1/atrcvl00908m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00908m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00908m1 failed to load or instantiate good classfile atrcvl00908m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00908m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00908m1/atrcvl00908m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #14; // #1 + Class #17; // #2 + Method #2 #6; // #3 + Double 0x4024000000000000;; // #4 + NameAndType #8 #7; // #6 + Utf8 "()V"; // #7 + Utf8 ""; // #8 + Utf8 "Code"; // #9 + Utf8 "ConstantValue"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "SourceFile"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00908m1/atrcvl00908m1n"; // #14 + Utf8 "Test.java"; // #15 + Utf8 "i"; // #16 + Utf8 "java/lang/Object"; // #17 + } + + 0x0021; // access + #1; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #16; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#10) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #8; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#9) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#12) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#13) { // SourceFile + #15; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00908m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00908m1/atrcvl00908m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #14; // #1 + Class #17; // #2 + Method #2 #6; // #3 + Double 0x4024000000000000;; // #4 + NameAndType #8 #7; // #6 + Utf8 "()V"; // #7 + Utf8 ""; // #8 + Utf8 "Code"; // #9 + Utf8 "ConstantValue"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "SourceFile"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00908m1/atrcvl00908m1p"; // #14 + Utf8 "Test.java"; // #15 + Utf8 "i"; // #16 + Utf8 "java/lang/Object"; // #17 + } + + 0x0021; // access + #1; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #16; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#10) { // ConstantValue + #4; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #8; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#9) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#12) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#13) { // SourceFile + #15; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00909m1/atrcvl00909m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00909m1.atrcvl00909m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl009.atrcvl00909m1.atrcvl00909m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl00909m1 failed to reject bad classfile atrcvl00909m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00909m1/atrcvl00909m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl00909m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl00909m1 failed to load or instantiate good classfile atrcvl00909m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl00909m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,103 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00909m1/atrcvl00909m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #14; // #1 + Class #17; // #2 + Method #2 #5; // #3 + Field #1 #6; // #4 + NameAndType #9 #7; // #5 + NameAndType #16 #12; // #6 + Utf8 "()V"; // #7 + Utf8 ""; // #8 + Utf8 ""; // #9 + Utf8 "Code"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "Ljava/lang/Object;"; // #12 + Utf8 "SourceFile"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00909m1/atrcvl00909m1n"; // #14 + Utf8 "Test.java"; // #15 + Utf8 "i"; // #16 + Utf8 "java/lang/Object"; // #17 + Utf8 "ConstantValue"; // #18 + } + + 0x0021; // access + #1; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #16; // name_index + #12; // descriptor_index + [] { // Attributes + Attr(#18) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0008; // access + #8; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#10) { // Code + 2; // max_stack + 0; // max_locals + Bytes[]{ + 0xBB 0x00 0x02 0x59 0xB7 0x00 0x03 0xB3 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 3; + 10 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #9; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#10) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#13) { // SourceFile + #15; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl00909m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,100 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00909m1/atrcvl00909m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #14; // #1 + Class #17; // #2 + Method #2 #5; // #3 + Field #1 #6; // #4 + NameAndType #9 #7; // #5 + NameAndType #16 #12; // #6 + Utf8 "()V"; // #7 + Utf8 ""; // #8 + Utf8 ""; // #9 + Utf8 "Code"; // #10 + Utf8 "LineNumberTable"; // #11 + Utf8 "Ljava/lang/Object;"; // #12 + Utf8 "SourceFile"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl009/atrcvl00909m1/atrcvl00909m1p"; // #14 + Utf8 "Test.java"; // #15 + Utf8 "i"; // #16 + Utf8 "java/lang/Object"; // #17 + Utf8 "ConstantValue"; // #18 + } + + 0x0021; // access + #1; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #16; // name_index + #12; // descriptor_index + [] { // Attributes + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0008; // access + #8; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#10) { // Code + 2; // max_stack + 0; // max_locals + Bytes[]{ + 0xBB 0x00 0x02 0x59 0xB7 0x00 0x03 0xB3 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 3; + 10 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #9; // name_index + #7; // descriptor_index + [] { // Attributes + Attr(#10) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#11) { // LineNumberTable + [] { // line_number_table + 0 2; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#13) { // SourceFile + #15; + } // end of SourceFile + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,239 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01001m1/atrcvl01001m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl010.atrcvl01001m1.atrcvl01001m1p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/Class"; // #12 + Utf8 "forName"; // #13 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #14 + Method #10 #16; // #15 + NameAndType #17 #18; // #16 + Utf8 "newInstance"; // #17 + Utf8 "()Ljava/lang/Object;"; // #18 + Class #20; // #19 + Utf8 "java/lang/Throwable"; // #20 + Method #22 #23; // #21 + Class #24; // #22 + NameAndType #25 #26; // #23 + Utf8 "java/lang/String"; // #24 + Utf8 "valueOf"; // #25 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #26 + InvokeDynamic 0s #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "makeConcatWithConstants"; // #29 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #30 + Method #32 #33; // #31 + Class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/io/PrintStream"; // #34 + Utf8 "println"; // #35 + Utf8 "(Ljava/lang/String;)V"; // #36 + String #38; // #37 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl010.atrcvl01001m1.atrcvl01001m1n"; // #38 + String #40; // #39 + Utf8 "test atrcvl01001m1 failed to reject bad classfile atrcvl01001m1n"; // #40 + Class #42; // #41 + Utf8 "java/lang/ClassFormatError"; // #42 + InvokeDynamic 1s #28; // #43 + Field #45 #46; // #44 + Class #47; // #45 + NameAndType #48 #49; // #46 + Utf8 "java/lang/System"; // #47 + Utf8 "out"; // #48 + Utf8 "Ljava/io/PrintStream;"; // #49 + Method #51 #52; // #50 + Class #53; // #51 + NameAndType #54 #55; // #52 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01001m1/atrcvl01001m1"; // #53 + Utf8 "run"; // #54 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #55 + Method #45 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "exit"; // #58 + Utf8 "(I)V"; // #59 + Utf8 "Code"; // #60 + Utf8 "LineNumberTable"; // #61 + Utf8 "StackMapTable"; // #62 + Utf8 "main"; // #63 + Utf8 "([Ljava/lang/String;)V"; // #64 + Utf8 "SourceFile"; // #65 + Utf8 "atrcvl01001m1.java"; // #66 + Utf8 "BootstrapMethods"; // #67 + String #69; // #68 + Utf8 "test atrcvl01001m1 failed to load or instantiate good classfile atrcvl01001m1p: \u0001"; // #69 + String #71; // #70 + Utf8 "test atrcvl01001m1 failed with unexpected loading exception: \u0001"; // #71 + MethodHandle 6b #73; // #72 + Method #74 #75; // #73 + Class #76; // #74 + NameAndType #29 #77; // #75 + Utf8 "java/lang/invoke/StringConcatFactory"; // #76 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #77 + Utf8 "InnerClasses"; // #78 + Class #80; // #79 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #80 + Class #82; // #81 + Utf8 "java/lang/invoke/MethodHandles"; // #82 + Utf8 "Lookup"; // #83 + } + + 0x0021; // access + #51; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 11; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 4; // max_locals + Bytes[]{ + 0x12 0x07 0xB8 0x00 0x09 0x4D 0x2C 0xB6 0x00 0x0F 0x4E 0xA7; + 0x00 0x13 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x1B 0x00; + 0x00 0xB6 0x00 0x1F 0x05 0xAC 0x12 0x25 0xB8 0x00 0x09 0x4D; + 0x2B 0x12 0x27 0xB6 0x00 0x1F 0x05 0xAC 0x4D 0xA7 0x00 0x13; + 0x4D 0x2B 0x2C 0xB8 0x00 0x15 0xBA 0x00 0x2B 0x00 0x00 0xB6; + 0x00 0x1F 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + 0 11 14 19; + 30 43 44 41; + 30 43 48 19; + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 16; + 6 17; + 11 21; + 14 18; + 15 19; + 28 20; + 30 24; + 36 25; + 42 26; + 44 27; + 45 32; + 48 29; + 49 30; + 62 31; + 64 34; + } + } // end of LineNumberTable + ; + Attr(#62) { // StackMapTable + [] { // + 78b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + 77b, []z{O,#41}; // same_locals_1_stack_item_frame + 67b, []z{O,#19}; // same_locals_1_stack_item_frame + 15b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #63; // name_index + #64; // descriptor_index + [] { // Attributes + Attr(#60) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0x2C 0xB8 0x00 0x32 0x10 0x5F 0x60 0xB8 0x00; + 0x38 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#61) { // LineNumberTable + [] { // line_number_table + 0 38; + 13 39; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#65) { // SourceFile + #66; + } // end of SourceFile + ; + Attr(#67) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #68; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #72; // bootstrap_method_ref + [] { // bootstrap_arguments + #70; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#78) { // InnerClasses + [] { // classes + #79 #81 #83 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01001m1/atrcvl01001m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Float 0x40490FD8; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01001m1/atrcvl01001m1n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01001m1p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01001m1/atrcvl01001m1p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01001m1/atrcvl01001m1p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #1; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m1.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m1.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m1.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m1.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,719 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m1 { + 0xCAFEBABE; + 0; // minor version + 67; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "atrcvl01002m10p"; // #8 + Method #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m1"; // #12 + Utf8 "loadPositive"; // #13 + Utf8 "(Ljava/lang/String;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #14 + String #16; // #15 + Utf8 "atrcvl01002m11n"; // #16 + Class #18; // #17 + Utf8 "java/lang/ClassFormatError"; // #18 + Method #10 #20; // #19 + NameAndType #21 #22; // #20 + Utf8 "loadNegative"; // #21 + Utf8 "(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/String;Ljava/io/PrintStream;)I"; // #22 + String #24; // #23 + Utf8 "atrcvl01002m12n"; // #24 + String #26; // #25 + Utf8 "atrcvl01002m13n"; // #26 + String #28; // #27 + Utf8 "atrcvl01002m14n"; // #28 + String #30; // #29 + Utf8 "atrcvl01002m15p"; // #30 + String #32; // #31 + Utf8 "atrcvl01002m16n"; // #32 + String #34; // #33 + Utf8 "atrcvl01002m17n"; // #34 + String #36; // #35 + Utf8 "atrcvl01002m18n"; // #36 + String #38; // #37 + Utf8 "atrcvl01002m19n"; // #38 + String #40; // #39 + Utf8 "atrcvl01002m110p"; // #40 + String #42; // #41 + Utf8 "atrcvl01002m111n"; // #42 + String #44; // #43 + Utf8 "atrcvl01002m112n"; // #44 + String #46; // #45 + Utf8 "atrcvl01002m113n"; // #46 + String #48; // #47 + Utf8 "atrcvl01002m114n"; // #48 + String #50; // #49 + Utf8 "atrcvl01002m115p"; // #50 + String #52; // #51 + Utf8 "atrcvl01002m116n"; // #52 + String #54; // #53 + Utf8 "atrcvl01002m117n"; // #54 + String #56; // #55 + Utf8 "atrcvl01002m118n"; // #56 + String #58; // #57 + Utf8 "atrcvl01002m119n"; // #58 + String #60; // #59 + Utf8 "atrcvl01002m120p"; // #60 + String #62; // #61 + Utf8 "atrcvl01002m121n"; // #62 + String #64; // #63 + Utf8 "atrcvl01002m122n"; // #64 + String #66; // #65 + Utf8 "atrcvl01002m123n"; // #66 + String #68; // #67 + Utf8 "atrcvl01002m124n"; // #68 + String #70; // #69 + Utf8 "atrcvl01002m125n"; // #70 + String #72; // #71 + Utf8 "atrcvl01002m126n"; // #72 + String #74; // #73 + Utf8 "atrcvl01002m127n"; // #74 + String #76; // #75 + Utf8 "atrcvl01002m128n"; // #76 + String #78; // #77 + Utf8 "atrcvl01002m129n"; // #78 + String #80; // #79 + Utf8 "atrcvl01002m130p"; // #80 + String #82; // #81 + Utf8 "atrcvl01002m131n"; // #82 + String #84; // #83 + Utf8 "atrcvl01002m132n"; // #84 + String #86; // #85 + Utf8 "atrcvl01002m133n"; // #86 + String #88; // #87 + Utf8 "atrcvl01002m134n"; // #88 + String #90; // #89 + Utf8 "atrcvl01002m135n"; // #90 + String #92; // #91 + Utf8 "atrcvl01002m136n"; // #92 + String #94; // #93 + Utf8 "atrcvl01002m137n"; // #94 + String #96; // #95 + Utf8 "atrcvl01002m138n"; // #96 + String #98; // #97 + Utf8 "atrcvl01002m139n"; // #98 + String #100; // #99 + Utf8 "atrcvl01002m140p"; // #100 + String #102; // #101 + Utf8 "atrcvl01002m141n"; // #102 + String #104; // #103 + Utf8 "atrcvl01002m142n"; // #104 + String #106; // #105 + Utf8 "atrcvl01002m143n"; // #106 + String #108; // #107 + Utf8 "atrcvl01002m144n"; // #108 + String #110; // #109 + Utf8 "atrcvl01002m145n"; // #110 + String #112; // #111 + Utf8 "atrcvl01002m146n"; // #112 + String #114; // #113 + Utf8 "atrcvl01002m147n"; // #114 + String #116; // #115 + Utf8 "atrcvl01002m148n"; // #116 + String #118; // #117 + Utf8 "atrcvl01002m149n"; // #118 + String #120; // #119 + Utf8 "atrcvl01002m150p"; // #120 + String #122; // #121 + Utf8 "atrcvl01002m151n"; // #122 + String #124; // #123 + Utf8 "atrcvl01002m152n"; // #124 + String #126; // #125 + Utf8 "atrcvl01002m153n"; // #126 + String #128; // #127 + Utf8 "atrcvl01002m154n"; // #128 + String #130; // #129 + Utf8 "atrcvl01002m155n"; // #130 + String #132; // #131 + Utf8 "atrcvl01002m156n"; // #132 + String #134; // #133 + Utf8 "atrcvl01002m157n"; // #134 + String #136; // #135 + Utf8 "atrcvl01002m158n"; // #136 + String #138; // #137 + Utf8 "atrcvl01002m159n"; // #138 + String #140; // #139 + Utf8 "atrcvl01002m160p"; // #140 + InvokeDynamic 0s #142; // #141 + NameAndType #143 #144; // #142 + Utf8 "makeConcatWithConstants"; // #143 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #144 + Method #146 #147; // #145 + Class #148; // #146 + NameAndType #149 #150; // #147 + Utf8 "java/lang/Class"; // #148 + Utf8 "forName"; // #149 + Utf8 "(Ljava/lang/String;)Ljava/lang/Class;"; // #150 + Class #152; // #151 + Utf8 "java/lang/ThreadDeath"; // #152 + Class #154; // #153 + Utf8 "java/lang/Throwable"; // #154 + Method #156 #157; // #155 + Class #158; // #156 + NameAndType #159 #160; // #157 + Utf8 "java/lang/String"; // #158 + Utf8 "valueOf"; // #159 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #160 + InvokeDynamic 1s #142; // #161 + Method #163 #164; // #162 + Class #165; // #163 + NameAndType #166 #167; // #164 + Utf8 "java/io/PrintStream"; // #165 + Utf8 "println"; // #166 + Utf8 "(Ljava/lang/String;)V"; // #167 + Method #146 #169; // #168 + NameAndType #170 #171; // #169 + Utf8 "isInstance"; // #170 + Utf8 "(Ljava/lang/Object;)Z"; // #171 + InvokeDynamic 2s #142; // #172 + InvokeDynamic 3s #142; // #173 + InvokeDynamic 4s #142; // #174 + Field #176 #177; // #175 + Class #178; // #176 + NameAndType #179 #180; // #177 + Utf8 "java/lang/System"; // #178 + Utf8 "out"; // #179 + Utf8 "Ljava/io/PrintStream;"; // #180 + Method #10 #182; // #181 + NameAndType #183 #184; // #182 + Utf8 "run"; // #183 + Utf8 "([Ljava/lang/String;Ljava/io/PrintStream;)I"; // #184 + Method #176 #186; // #185 + NameAndType #187 #188; // #186 + Utf8 "exit"; // #187 + Utf8 "(I)V"; // #188 + Utf8 "Code"; // #189 + Utf8 "LineNumberTable"; // #190 + Utf8 "StackMapTable"; // #191 + Class #193; // #192 + Utf8 "[Ljava/lang/String;"; // #193 + Utf8 "main"; // #194 + Utf8 "([Ljava/lang/String;)V"; // #195 + Utf8 "SourceFile"; // #196 + Utf8 "atrcvl01002m1.java"; // #197 + Utf8 "BootstrapMethods"; // #198 + String #200; // #199 + Utf8 "javasoft.sqe.tests.vm.classfmt.atr.atrcvl010.atrcvl01002m1.\u0001"; // #200 + String #202; // #201 + Utf8 "Failed with loading exception: \u0001"; // #202 + String #204; // #203 + Utf8 "Passed with loading exception: \u0001"; // #204 + String #206; // #205 + Utf8 "Failed with unexpected loading exception: \u0001"; // #206 + String #208; // #207 + Utf8 "Failed to reject invalid class \u0001"; // #208 + MethodHandle 6b #210; // #209 + Method #211 #212; // #210 + Class #213; // #211 + NameAndType #143 #214; // #212 + Utf8 "java/lang/invoke/StringConcatFactory"; // #213 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #214 + Utf8 "InnerClasses"; // #215 + Class #217; // #216 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #217 + Class #219; // #218 + Utf8 "java/lang/invoke/MethodHandles"; // #219 + Utf8 "Lookup"; // #220 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#189) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#190) { // LineNumberTable + [] { // line_number_table + 0 12; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #183; // name_index + #184; // descriptor_index + [] { // Attributes + Attr(#189) { // Code + 4; // max_stack + 2; // max_locals + Bytes[]{ + 0x12 0x07 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x0F 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x17 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x19 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x1B 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x1D 0x2A 0x2B; + 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC 0x12 0x1F 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x21; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x23 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x25 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x27 0x2A 0x2B 0xB8 0x00 0x09 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x29 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x2B 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x2D 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x2F; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x31 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x33 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x35 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x37 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x39 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x3B 0x2A 0x2B; + 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC 0x12 0x3D 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x3F; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x41 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x43 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x45 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x47 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x49 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x4B; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x4D 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x4F 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x51 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x53 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x55 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x57 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x59; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x5B 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x5D 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x5F 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x61 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x63 0x2A 0x2B; + 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC 0x12 0x65 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x67; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x69 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x6B 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x6D 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x6F 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x71 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x73; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x75 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x77 0x2A 0x2B 0xB8 0x00 0x09 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x79 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x7B 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x7D 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x7F 0x12 0x11; + 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x81; + 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC; + 0x12 0x83 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99 0x00 0x05; + 0x05 0xAC 0x12 0x85 0x12 0x11 0x2A 0x2B 0xB8 0x00 0x13 0x99; + 0x00 0x05 0x05 0xAC 0x12 0x87 0x12 0x11 0x2A 0x2B 0xB8 0x00; + 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x89 0x12 0x11 0x2A 0x2B; + 0xB8 0x00 0x13 0x99 0x00 0x05 0x05 0xAC 0x12 0x8B 0x2A 0x2B; + 0xB8 0x00 0x09 0x99 0x00 0x05 0x05 0xAC 0x03 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#190) { // LineNumberTable + [] { // line_number_table + 0 16; + 10 17; + 12 18; + 24 19; + 26 20; + 38 21; + 40 22; + 52 23; + 54 24; + 66 25; + 68 26; + 78 27; + 80 28; + 92 29; + 94 30; + 106 31; + 108 32; + 120 33; + 122 34; + 134 35; + 136 36; + 146 37; + 148 38; + 160 39; + 162 40; + 174 41; + 176 42; + 188 43; + 190 44; + 202 45; + 204 46; + 214 47; + 216 48; + 228 49; + 230 50; + 242 51; + 244 52; + 256 53; + 258 54; + 270 55; + 272 56; + 282 57; + 284 58; + 296 59; + 298 60; + 310 61; + 312 62; + 324 63; + 326 64; + 338 65; + 340 66; + 352 67; + 354 68; + 366 69; + 368 70; + 380 71; + 382 72; + 394 73; + 396 74; + 408 75; + 410 76; + 420 77; + 422 78; + 434 79; + 436 80; + 448 81; + 450 82; + 462 83; + 464 84; + 476 85; + 478 86; + 490 87; + 492 88; + 504 89; + 506 90; + 518 91; + 520 92; + 532 93; + 534 94; + 546 95; + 548 96; + 558 97; + 560 98; + 572 99; + 574 100; + 586 101; + 588 102; + 600 103; + 602 104; + 614 105; + 616 106; + 628 107; + 630 108; + 642 109; + 644 110; + 656 111; + 658 112; + 670 113; + 672 114; + 684 115; + 686 116; + 696 117; + 698 118; + 710 119; + 712 120; + 724 121; + 726 122; + 738 123; + 740 124; + 752 125; + 754 126; + 766 127; + 768 128; + 780 129; + 782 130; + 794 131; + 796 132; + 808 133; + 810 134; + 822 135; + 824 136; + 834 137; + 836 139; + } + } // end of LineNumberTable + ; + Attr(#191) { // StackMapTable + [] { // + 12b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 13b; // same_frame + 11b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#189) { // Code + 2; // max_stack + 5; // max_locals + Bytes[]{ + 0x01 0x4E 0x2A 0xBA 0x00 0x8D 0x00 0x00 0xB8 0x00 0x91 0x4E; + 0xA7 0x00 0x1A 0x3A 0x04 0x19 0x04 0xBF 0x3A 0x04 0x2C 0x19; + 0x04 0xB8 0x00 0x9B 0xBA 0x00 0xA1 0x00 0x00 0xB6 0x00 0xA2; + 0x05 0xAC 0x03 0xAC } + [] { // Traps + 2 12 15 151; + 2 12 20 153; + } // end of Traps + [] { // Attributes + Attr(#190) { // LineNumberTable + [] { // line_number_table + 0 144; + 2 146; + 12 152; + 15 147; + 17 148; + 20 149; + 22 150; + 36 151; + 38 154; + } + } // end of LineNumberTable + ; + Attr(#191) { // StackMapTable + [] { // + 255b, 15, []{O,#156; O,#192; O,#163; O,#146}, []{O,#151}; // full_frame + 68b, []z{O,#153}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #21; // name_index + #22; // descriptor_index + [] { // Attributes + Attr(#189) { // Code + 2; // max_stack + 6; // max_locals + Bytes[]{ + 0x01 0x3A 0x04 0x2A 0xBA 0x00 0x8D 0x00 0x00 0xB8 0x00 0x91; + 0x3A 0x04 0xA7 0x00 0x33 0x3A 0x05 0x19 0x05 0xBF 0x3A 0x05; + 0x2B 0x19 0x05 0xB6 0x00 0xA8 0x99 0x00 0x13 0x2D 0x19 0x05; + 0xB8 0x00 0x9B 0xBA 0x00 0xAC 0x00 0x00 0xB6 0x00 0xA2 0x03; + 0xAC 0x2D 0x19 0x05 0xB8 0x00 0x9B 0xBA 0x00 0xAD 0x00 0x00; + 0xB6 0x00 0xA2 0x05 0xAC 0x2D 0x2A 0xBA 0x00 0xAE 0x00 0x00; + 0xB6 0x00 0xA2 0x05 0xAC; + } + [] { // Traps + 3 14 17 151; + 3 14 22 153; + } // end of Traps + [] { // Attributes + Attr(#190) { // LineNumberTable + [] { // line_number_table + 0 159; + 3 161; + 14 172; + 17 162; + 19 163; + 22 164; + 24 165; + 33 166; + 47 167; + 49 169; + 63 170; + 65 173; + 75 174; + } + } // end of LineNumberTable + ; + Attr(#191) { // StackMapTable + [] { // + 255b, 17, []{O,#156; O,#146; O,#192; O,#163; O,#146}, []{O,#151}; // full_frame + 68b, []z{O,#153}; // same_locals_1_stack_item_frame + 252b, 26, []z{O,#153}; // append_frame 1 + 250b, 15; // chop_frame 1 + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #194; // name_index + #195; // descriptor_index + [] { // Attributes + Attr(#189) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB2 0x00 0xAF 0xB8 0x00 0xB5 0x10 0x5F 0x60 0xB8 0x00; + 0xB9 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#190) { // LineNumberTable + [] { // line_number_table + 0 178; + 13 179; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#196) { // SourceFile + #197; + } // end of SourceFile + ; + Attr(#198) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #209; // bootstrap_method_ref + [] { // bootstrap_arguments + #199; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #209; // bootstrap_method_ref + [] { // bootstrap_arguments + #201; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #209; // bootstrap_method_ref + [] { // bootstrap_arguments + #203; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #209; // bootstrap_method_ref + [] { // bootstrap_arguments + #205; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #209; // bootstrap_method_ref + [] { // bootstrap_arguments + #207; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#215) { // InnerClasses + [] { // classes + #216 #218 #220 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m10p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m10p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m10p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m10p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m10p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m10p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m110p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m110p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m110p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m110p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m110p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "C"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m110p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m111n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m111n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m111n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m111n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m111n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m111n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m112n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m112n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m112n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m112n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m112n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m112n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m113n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m113n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m113n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m113n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m113n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m113n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m114n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m114n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m114n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m114n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m114n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m114n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m115p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m115p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m115p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m115p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m115p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "B"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m115p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m116n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m116n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m116n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m116n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m116n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m116n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m117n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m117n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m117n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m117n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m117n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m117n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m118n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m118n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m118n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m118n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m118n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m118n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m119n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m119n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m119n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m119n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m119n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m119n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m11n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m11n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m11n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m11n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m11n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m11n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m120p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m120p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m120p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m120p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m120p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Z"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m120p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m121n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m121n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m121n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m121n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m121n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m121n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m122n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m122n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m122n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m122n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m122n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m122n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m123n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m123n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m123n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m123n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m123n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m123n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m124n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m124n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m124n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m124n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m124n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m124n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m125n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m125n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m125n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m125n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m125n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m125n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m126n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m126n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m126n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m126n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m126n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "S"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m126n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m127n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m127n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m127n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m127n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m127n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "C"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m127n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m128n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m128n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m128n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m128n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m128n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "B"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m128n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m129n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m129n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m129n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m129n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m129n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Z"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m129n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m12n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m12n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m12n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m12n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m12n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m12n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m130p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m130p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m130p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m130p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m130p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m130p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m131n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m131n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m131n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m131n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m131n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m131n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m132n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m132n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m132n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m132n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m132n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m132n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m133n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m133n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m133n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m133n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m133n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m133n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Long 0x0000000000000005;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m134n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m134n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m134n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m134n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m134n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m134n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m135n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m135n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m135n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m135n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m135n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "S"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m135n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m136n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m136n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m136n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m136n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m136n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "C"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m136n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m137n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m137n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m137n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m137n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m137n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "B"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m137n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m138n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m138n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m138n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m138n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m138n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Z"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m138n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m139n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m139n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m139n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m139n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m139n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m139n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m13n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m13n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m13n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m13n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m13n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m13n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m140p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m140p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m140p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m140p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m140p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m140p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m141n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m141n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m141n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m141n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m141n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m141n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m142n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m142n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m142n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m142n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m142n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m142n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Float 0x00000006; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m143n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m143n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m143n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m143n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m143n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m143n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m144n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m144n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m144n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m144n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m144n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "S"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m144n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m145n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m145n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m145n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m145n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m145n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "C"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m145n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m146n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m146n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m146n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m146n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m146n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "B"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m146n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m147n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m147n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m147n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m147n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m147n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Z"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m147n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m148n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m148n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m148n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m148n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m148n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m148n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m149n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m149n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m149n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m149n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m149n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m149n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m14n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m14n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m14n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m14n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m14n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m14n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000001; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m150p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m150p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m150p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m150p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m150p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m150p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m151n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m151n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m151n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m151n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m151n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m151n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Double 0x0000000000000007;; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m152n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m152n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m152n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m152n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m152n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "I"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m152n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m153n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m153n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m153n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m153n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m153n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "S"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m153n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m154n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m154n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m154n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m154n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m154n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "C"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m154n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m155n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m155n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m155n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m155n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m155n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "B"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m155n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m156n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m156n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m156n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m156n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m156n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Z"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m156n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m157n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m157n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m157n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m157n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m157n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m157n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m158n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m158n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m158n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m158n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m158n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m158n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m159n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m159n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m159n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m159n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m159n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m159n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m15p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m15p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m15p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m15p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m15p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "S"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m15p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m160p.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m160p.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m160p.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m160p.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m160p { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m160p"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + String #20; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m16n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m16n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m16n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m16n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m16n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "J"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m16n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m17n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m17n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m17n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m17n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m17n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "F"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m17n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m18n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m18n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m18n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m18n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m18n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "D"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m18n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m19n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m19n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m19n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/jcod-files/atrcvl01002m19n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,73 @@ +class javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m19n { + 0xCAFEBABE; + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Integer 0x00030D40; // #1 + Class #14; // #2 + Class #18; // #3 + Method #3 #5; // #4 + NameAndType #7 #6; // #5 + Utf8 "()V"; // #6 + Utf8 ""; // #7 + Utf8 "Code"; // #8 + Utf8 "ConstantValue"; // #9 + Utf8 "Exceptions"; // #10 + Utf8 "Ljava/lang/String;"; // #11 + Utf8 "LineNumberTable"; // #12 + Utf8 "LocalVariables"; // #13 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcvl010/atrcvl01002m1/atrcvl01002m19n"; // #14 + Utf8 "SourceFile"; // #15 + Utf8 "f.java"; // #16 + Utf8 "i"; // #17 + Utf8 "java/lang/Object"; // #18 + Integer 0x00000D40; // #19 + Utf8 "Hello, World!"; // #20 + Integer 0x00000000; // #21 + } + + 0x0020; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #17; // name_index + #11; // descriptor_index + [] { // Attributes + Attr(#9) { // ConstantValue + #21; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #7; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x04 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package javasoft/sqe/tests/package; + +public super class #6 /* BSMCase7903791 */ version 50:0 +{ + const #1 = Method #13.#14; // java/lang/Object."":"()V" + const #2 = Field #6.#15; // BSMCase7903791.field:"I" + const #3 = InvokeDynamic 0:#28; // #0:_:"()Ljava/lang/String;" + const #4 = InvokeDynamic 1:#35; // #1:_:"()[I" + const #5 = Utf8 "javasoft/sqe/tests/package/BSMCase7903791"; + const #6 = class #5; // BSMCase7903791 + const #7 = Utf8 "field"; + const #8 = Utf8 "I"; + const #9 = Utf8 ""; + const #10 = Utf8 "()V"; + const #11 = Utf8 "Code"; + const #12 = Utf8 "java/lang/Object"; + const #13 = class #12; // java/lang/Object + const #14 = NameAndType #9:#10; // "":"()V" + const #15 = NameAndType #7:#8; // field:"I" + const #16 = Utf8 "StackMapTable"; + const #17 = Utf8 "constantFilled2I"; + const #18 = Utf8 "()[I"; + const #19 = Utf8 "java/lang/runtime/ArrayCreation"; + const #20 = class #19; // java/lang/runtime/ArrayCreation + const #21 = Utf8 "constantFilled01"; + const #22 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;"; + const #23 = NameAndType #21:#22; // constantFilled01:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #24 = Method #20.#23; // java/lang/runtime/ArrayCreation.constantFilled01:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #25 = MethodHandle 6:#24; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled01:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #26 = Utf8 "_"; + const #27 = Utf8 "()Ljava/lang/String;"; + const #28 = NameAndType #26:#27; // _:"()Ljava/lang/String;" + const #29 = Utf8 "BootstrapMethods"; + const #30 = Utf8 "constantFilled3I"; + const #31 = Utf8 "constantFilled"; + const #32 = NameAndType #31:#22; // constantFilled:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #33 = Method #20.#32; // java/lang/runtime/ArrayCreation.constantFilled:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #34 = MethodHandle 6:#33; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #35 = NameAndType #26:#18; // _:"()[I" + const #36 = Utf8 "java/lang/invoke/ConstantBootstraps"; + const #37 = class #36; // java/lang/invoke/ConstantBootstraps + const #38 = Utf8 "primitiveClass"; + const #39 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;"; + const #40 = NameAndType #38:#39; // primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;" + const #41 = Method #37.#40; // java/lang/invoke/ConstantBootstraps.primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;" + const #42 = MethodHandle 6:#41; // REF_invokeStatic:java/lang/invoke/ConstantBootstraps.primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;" + const #43 = Utf8 "Ljava/lang/Class;"; + const #44 = NameAndType #8:#43; // I:"Ljava/lang/Class;" + const #45 = Dynamic 2:#44; // #2:I:"Ljava/lang/Class;" + const #46 = int 0; + const #47 = int 3; + const #48 = int -3; + const #49 = Utf8 "SourceFile"; + const #50 = Utf8 "BSMCase7903791.jasm"; + + private Field #7:#8; // field:I + + Method #9:#10 // "":"()V" + stack 4 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + 5: stack_frame_type full; // frame_type 255 + locals_map; + stack_map #6, 2; // class BSMCase7903791, float; + putfield #2; // Field field:"I" + 8: return; + } + + public static Method #17:#18 // constantFilled2I:"()[I" + stack 1 locals 0 + { + 0: invokedynamic #3; // InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ArrayCreation.constantFilled01: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;": + // _:"()Ljava/lang/String;"{} + 5: areturn; + } + + public static Method #30:#18 // constantFilled3I:"()[I" + stack 1 locals 0 + { + 0: invokedynamic #4; // InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ArrayCreation.constantFilled: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;": + // _:"()[I" { + // Dynamic REF_invokeStatic:Method java/lang/invoke/ConstantBootstraps.primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;": + // I:"Ljava/lang/Class;"{}, + // int 0, + // int 3, + // int -3 + // } + 5: areturn; + } + + SourceFile #50; // BSMCase7903791.jasm + + BootstrapMethod #25; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled01: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { } + + BootstrapMethod #34; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #45, // Dynamic REF_invokeStatic:java/lang/invoke/ConstantBootstraps.primitiveClass: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;": + // I:"Ljava/lang/Class;"{} + #46, // int 0 + #47, // int 3 + #48 // int -3 + } + + BootstrapMethod #42; // REF_invokeStatic:java/lang/invoke/ConstantBootstraps.primitiveClass: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;"; + { } +} // end Class javasoft/sqe/tests/package/BSMCase7903791 compiled from "BSMCase7903791.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +class javasoft/sqe/tests/package/BSMCase7903791 { + 0xCAFEBABE; + 0; // minor version + 50; // version + [51] { // Constant Pool + ; // first element is empty + Method #13 #14; // #1 at 0x0A + Field #6 #15; // #2 at 0x0F + InvokeDynamic 0s #28; // #3 at 0x14 + InvokeDynamic 1s #35; // #4 at 0x19 + Utf8 "javasoft/sqe/tests/package/BSMCase7903791"; // #5 at 0x1E + Class #5; // #6 at 0x4A + Utf8 "field"; // #7 at 0x4D + Utf8 "I"; // #8 at 0x55 + Utf8 ""; // #9 at 0x59 + Utf8 "()V"; // #10 at 0x62 + Utf8 "Code"; // #11 at 0x68 + Utf8 "java/lang/Object"; // #12 at 0x6F + Class #12; // #13 at 0x82 + NameAndType #9 #10; // #14 at 0x85 + NameAndType #7 #8; // #15 at 0x8A + Utf8 "StackMapTable"; // #16 at 0x8F + Utf8 "constantFilled2I"; // #17 at 0x9F + Utf8 "()[I"; // #18 at 0xB2 + Utf8 "java/lang/runtime/ArrayCreation"; // #19 at 0xB9 + Class #19; // #20 at 0xDB + Utf8 "constantFilled01"; // #21 at 0xDE + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #22 at 0xF1 + NameAndType #21 #22; // #23 at 0x019A + Method #20 #23; // #24 at 0x019F + MethodHandle 6b #24; // #25 at 0x01A4 + Utf8 "_"; // #26 at 0x01A8 + Utf8 "()Ljava/lang/String;"; // #27 at 0x01AC + NameAndType #26 #27; // #28 at 0x01C3 + Utf8 "BootstrapMethods"; // #29 at 0x01C8 + Utf8 "constantFilled3I"; // #30 at 0x01DB + Utf8 "constantFilled"; // #31 at 0x01EE + NameAndType #31 #22; // #32 at 0x01FF + Method #20 #32; // #33 at 0x0204 + MethodHandle 6b #33; // #34 at 0x0209 + NameAndType #26 #18; // #35 at 0x020D + Utf8 "java/lang/invoke/ConstantBootstraps"; // #36 at 0x0212 + Class #36; // #37 at 0x0238 + Utf8 "primitiveClass"; // #38 at 0x023B + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;"; // #39 at 0x024C + NameAndType #38 #39; // #40 at 0x02AC + Method #37 #40; // #41 at 0x02B1 + MethodHandle 6b #41; // #42 at 0x02B6 + Utf8 "Ljava/lang/Class;"; // #43 at 0x02BA + NameAndType #8 #43; // #44 at 0x02CE + Dynamic 2s #44; // #45 at 0x02D3 + Integer 0x00000000; // #46 at 0x02D8 + Integer 0x00000003; // #47 at 0x02DD + Integer 0xFFFFFFFD; // #48 at 0x02E2 + Utf8 "SourceFile"; // #49 at 0x02E7 + Utf8 "BSMCase7903791.jasm"; // #50 at 0x02F4 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #6; // this_cpx + #13; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [1] { // Fields + { // field at 0x0314 + 0x0002; // access + #7; // name_index : field + #8; // descriptor_index : I + [0] { // Attributes + } // end of Attributes + } + } // end of Fields + + [3] { // Methods + { // method at 0x031E + 0x0000; // access + #9; // name_index : + #10; // descriptor_index : ()V + [1] { // Attributes + Attr(#11, 40) { // Code at 0x0326 + 4; // max_stack + 1; // max_locals + Bytes[9]{ + 0x2A 0xB7 0x00 0x01 0xB1 0xB5 0x00 0x02 0xB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#16, 13) { // StackMapTable at 0x0341 + [1] { // + 255b, 5, [0]{}, [2]{7b,#6; 2b}; // full_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0354 + 0x0009; // access + #17; // name_index : constantFilled2I + #18; // descriptor_index : ()[I + [1] { // Attributes + Attr(#11, 18) { // Code at 0x035C + 1; // max_stack + 0; // max_locals + Bytes[6]{ + 0xBA 0x00 0x03 0x00 0x00 0xB0; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0374 + 0x0009; // access + #30; // name_index : constantFilled3I + #18; // descriptor_index : ()[I + [1] { // Attributes + Attr(#11, 18) { // Code at 0x037C + 1; // max_stack + 0; // max_locals + Bytes[6]{ + 0xBA 0x00 0x04 0x00 0x00 0xB0; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [2] { // Attributes + Attr(#49, 2) { // SourceFile at 0x0396 + #50; + } // end of SourceFile + ; + Attr(#29, 22) { // BootstrapMethods at 0x039E + [3] { // bootstrap_methods + { // bootstrap_method + #25; // bootstrap_method_ref + [0] { // bootstrap_arguments + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #34; // bootstrap_method_ref + [4] { // bootstrap_arguments + #45; // at 0x03B0 + #46; // at 0x03B2 + #47; // at 0x03B4 + #48; // at 0x03B6 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #42; // bootstrap_method_ref + [0] { // bootstrap_arguments + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + } // end of Attributes +} // end of class javasoft/sqe/tests/package/BSMCase7903791 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.t.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.t.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.t.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.g.t.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package javasoft/sqe/tests/package; + +public super class #6 /* BSMCase7903791 */ version 50:0 +{ + const #1 = Methodref #13.#14; // java/lang/Object."":"()V" + const #2 = Fieldref #6.#15; // BSMCase7903791.field:"I" + const #3 = InvokeDynamic 0:#28; // #0:_:"()Ljava/lang/String;" + const #4 = InvokeDynamic 1:#35; // #1:_:"()[I" + const #5 = Utf8 "javasoft/sqe/tests/package/BSMCase7903791"; + const #6 = Class #5; // BSMCase7903791 + const #7 = Utf8 "field"; + const #8 = Utf8 "I"; + const #9 = Utf8 ""; + const #10 = Utf8 "()V"; + const #11 = Utf8 "Code"; + const #12 = Utf8 "java/lang/Object"; + const #13 = Class #12; // java/lang/Object + const #14 = NameAndType #9:#10; // "":"()V" + const #15 = NameAndType #7:#8; // field:"I" + const #16 = Utf8 "StackMapTable"; + const #17 = Utf8 "constantFilled2I"; + const #18 = Utf8 "()[I"; + const #19 = Utf8 "java/lang/runtime/ArrayCreation"; + const #20 = Class #19; // java/lang/runtime/ArrayCreation + const #21 = Utf8 "constantFilled01"; + const #22 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;"; + const #23 = NameAndType #21:#22; // constantFilled01:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #24 = Methodref #20.#23; // java/lang/runtime/ArrayCreation.constantFilled01:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #25 = MethodHandle 6:#24; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled01:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #26 = Utf8 "_"; + const #27 = Utf8 "()Ljava/lang/String;"; + const #28 = NameAndType #26:#27; // _:"()Ljava/lang/String;" + const #29 = Utf8 "BootstrapMethods"; + const #30 = Utf8 "constantFilled3I"; + const #31 = Utf8 "constantFilled"; + const #32 = NameAndType #31:#22; // constantFilled:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #33 = Methodref #20.#32; // java/lang/runtime/ArrayCreation.constantFilled:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #34 = MethodHandle 6:#33; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #35 = NameAndType #26:#18; // _:"()[I" + const #36 = Utf8 "java/lang/invoke/ConstantBootstraps"; + const #37 = Class #36; // java/lang/invoke/ConstantBootstraps + const #38 = Utf8 "primitiveClass"; + const #39 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;"; + const #40 = NameAndType #38:#39; // primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;" + const #41 = Methodref #37.#40; // java/lang/invoke/ConstantBootstraps.primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;" + const #42 = MethodHandle 6:#41; // REF_invokeStatic:java/lang/invoke/ConstantBootstraps.primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;" + const #43 = Utf8 "Ljava/lang/Class;"; + const #44 = NameAndType #8:#43; // I:"Ljava/lang/Class;" + const #45 = Dynamic 2:#44; // #2:I:"Ljava/lang/Class;" + const #46 = Integer 0; + const #47 = Integer 3; + const #48 = Integer -3; + const #49 = Utf8 "SourceFile"; + const #50 = Utf8 "BSMCase7903791.jasm"; + + private Field #7:#8; // field:I + + Method #9:#10 // "":"()V" + stack 4 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + 5: putfield #2; // Field field:"I" + 8: return; + StackMapTable: number_of_entries = 1 + frame_type = 255 // full + offset_delta = 5 + locals_map = [] // + stack_map = [ #6, 2; ] // class BSMCase7903791, float; + } + + public static Method #17:#18 // constantFilled2I:"()[I" + stack 1 locals 0 + { + 0: invokedynamic #3; // InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ArrayCreation.constantFilled01: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;": + // _:"()Ljava/lang/String;"{} + 5: areturn; + } + + public static Method #30:#18 // constantFilled3I:"()[I" + stack 1 locals 0 + { + 0: invokedynamic #4; // InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ArrayCreation.constantFilled: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;": + // _:"()[I" { + // Dynamic REF_invokeStatic:Method java/lang/invoke/ConstantBootstraps.primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;": + // I:"Ljava/lang/Class;"{}, + // int 0, + // int 3, + // int -3 + // } + 5: areturn; + } + + SourceFile #50; // BSMCase7903791.jasm + + BootstrapMethods { + 0: #25; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled01: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;"; + + 1: #34; // REF_invokeStatic:java/lang/runtime/ArrayCreation.constantFilled: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #45, // Dynamic REF_invokeStatic:java/lang/invoke/ConstantBootstraps.primitiveClass: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;": + // I:"Ljava/lang/Class;"{} + #46, // int 0 + #47, // int 3 + #48; // int -3 + + 2: #42; // REF_invokeStatic:java/lang/invoke/ConstantBootstraps.primitiveClass: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;"; + } +} // end Class javasoft/sqe/tests/package/BSMCase7903791 compiled from "BSMCase7903791.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/BootstrapMethods/BSMCase7903791.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package javasoft/sqe/tests/package; + +public super class BSMCase7903791 version 50:0 +{ + private Field field:I; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_frame_type full; + locals_map; + stack_map class BSMCase7903791, float; + putfield Field field:"I"; + return; + } + + public static Method constantFilled2I:"()[I" + stack 1 locals 0 + { + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ArrayCreation.constantFilled01: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;": + _:"()Ljava/lang/String;"{}; + areturn; + } + + public static Method constantFilled3I:"()[I" + stack 1 locals 0 + { + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ArrayCreation.constantFilled: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/reflect/RuntimeType;IILjava/lang/Object;)Ljava/lang/invoke/CallSite;": + _:"()[I" { + Dynamic REF_invokeStatic:Method java/lang/invoke/ConstantBootstraps.primitiveClass:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;": + I:"Ljava/lang/Class;"{}, + int 0, + int 3, + int -3 + }; + areturn; + } + + SourceFile "BSMCase7903791.jasm"; +} // end Class javasoft/sqe/tests/package/BSMCase7903791 compiled from "BSMCase7903791.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +final class #2 /* LoadableDescriptorsAttributeTest$X */ version 69:65535 +{ + const #1 = Field #2.#3; // LoadableDescriptorsAttributeTest$X.v1:"[LLoadableDescriptorsAttributeTest$V1;" + const #2 = class #4; // LoadableDescriptorsAttributeTest$X + const #3 = NameAndType #5:#6; // v1:"[LLoadableDescriptorsAttributeTest$V1;" + const #4 = Utf8 "LoadableDescriptorsAttributeTest$X"; + const #5 = Utf8 "v1"; + const #6 = Utf8 "[LLoadableDescriptorsAttributeTest$V1;"; + const #7 = Field #2.#8; // LoadableDescriptorsAttributeTest$X.v7:"LLoadableDescriptorsAttributeTest$V7;" + const #8 = NameAndType #9:#10; // v7:"LLoadableDescriptorsAttributeTest$V7;" + const #9 = Utf8 "v7"; + const #10 = Utf8 "LLoadableDescriptorsAttributeTest$V7;"; + const #11 = Field #2.#12; // LoadableDescriptorsAttributeTest$X.v10:"LLoadableDescriptorsAttributeTest$V10;" + const #12 = NameAndType #13:#14; // v10:"LLoadableDescriptorsAttributeTest$V10;" + const #13 = Utf8 "v10"; + const #14 = Utf8 "LLoadableDescriptorsAttributeTest$V10;"; + const #15 = Method #16.#17; // java/lang/Object."":"()V" + const #16 = class #18; // java/lang/Object + const #17 = NameAndType #19:#20; // "":"()V" + const #18 = Utf8 "java/lang/Object"; + const #19 = Utf8 ""; + const #20 = Utf8 "()V"; + const #21 = Utf8 "Code"; + const #22 = Utf8 "LineNumberTable"; + const #23 = Utf8 "foo"; + const #24 = Utf8 "()LLoadableDescriptorsAttributeTest$V2;"; + const #25 = Utf8 "(LLoadableDescriptorsAttributeTest$V3;)V"; + const #26 = Utf8 "(I)V"; + const #27 = Utf8 "goo"; + const #28 = Utf8 "([LLoadableDescriptorsAttributeTest$V6;)V"; + const #29 = Utf8 "StackMapTable"; + const #30 = class #31; // LoadableDescriptorsAttributeTest$V5 + const #31 = Utf8 "LoadableDescriptorsAttributeTest$V5"; + const #32 = Utf8 "([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8;"; + const #33 = Utf8 "SourceFile"; + const #34 = Utf8 "LoadableDescriptorsAttributeTest.java"; + const #35 = Utf8 "NestHost"; + const #36 = class #37; // LoadableDescriptorsAttributeTest + const #37 = Utf8 "LoadableDescriptorsAttributeTest"; + const #38 = Utf8 "InnerClasses"; + const #39 = Utf8 "X"; + const #40 = class #41; // LoadableDescriptorsAttributeTest$V1 + const #41 = Utf8 "LoadableDescriptorsAttributeTest$V1"; + const #42 = Utf8 "V1"; + const #43 = class #44; // LoadableDescriptorsAttributeTest$V7 + const #44 = Utf8 "LoadableDescriptorsAttributeTest$V7"; + const #45 = Utf8 "V7"; + const #46 = class #47; // LoadableDescriptorsAttributeTest$V10 + const #47 = Utf8 "LoadableDescriptorsAttributeTest$V10"; + const #48 = Utf8 "V10"; + const #49 = class #50; // LoadableDescriptorsAttributeTest$V2 + const #50 = Utf8 "LoadableDescriptorsAttributeTest$V2"; + const #51 = Utf8 "V2"; + const #52 = class #53; // LoadableDescriptorsAttributeTest$V3 + const #53 = Utf8 "LoadableDescriptorsAttributeTest$V3"; + const #54 = Utf8 "V3"; + const #55 = class #56; // LoadableDescriptorsAttributeTest$V6 + const #56 = Utf8 "LoadableDescriptorsAttributeTest$V6"; + const #57 = Utf8 "V6"; + const #58 = Utf8 "V5"; + const #59 = class #60; // LoadableDescriptorsAttributeTest$V9 + const #60 = Utf8 "LoadableDescriptorsAttributeTest$V9"; + const #61 = Utf8 "V9"; + const #62 = class #63; // LoadableDescriptorsAttributeTest$V8 + const #63 = Utf8 "LoadableDescriptorsAttributeTest$V8"; + const #64 = Utf8 "V8"; + const #65 = Utf8 "LoadableDescriptors"; + const #66 = Utf8 "LLoadableDescriptorsAttributeTest$V3;"; + const #67 = Utf8 "LLoadableDescriptorsAttributeTest$V2;"; + + final strict Field #5:#6; // v1:"[LLoadableDescriptorsAttributeTest$V1;" + final strict Field #9:#10; // v7:"LLoadableDescriptorsAttributeTest$V7;" + final strict Field #13:#14; // v10:"LLoadableDescriptorsAttributeTest$V10;" + + Method #19:#20 // "":"()V" + stack 2 locals 1 + { + 0: aload_0; + 1: aconst_null; + 2: putfield #1; // Field v1:"[LLoadableDescriptorsAttributeTest$V1;" + 5: aload_0; + 6: aconst_null; + 7: putfield #7; // Field v7:"LLoadableDescriptorsAttributeTest$V7;" + 10: aload_0; + 11: aconst_null; + 12: putfield #11; // Field v10:"LLoadableDescriptorsAttributeTest$V10;" + 15: aload_0; + 16: invokespecial #15; // Method java/lang/Object."":"()V" + 19: return; + } + + Method #23:#24 // foo:"()LLoadableDescriptorsAttributeTest$V2;" + stack 1 locals 1 + { + 0: aconst_null; + 1: areturn; + } + + Method #23:#25 // foo:"(LLoadableDescriptorsAttributeTest$V3;)V" + stack 0 locals 2 + { + 0: return; + } + + Method #23:#26 // foo:"(I)V" + stack 1 locals 3 + { + 0: aconst_null; + 1: astore_2; + 2: return; + } + + Method #27:#28 // goo:"([LLoadableDescriptorsAttributeTest$V6;)V" + stack 1 locals 4 + { + 0: aconst_null; + 1: astore_2; + 2: aload_2; + 3: ifnonnull 9; + 6: goto 11; + 9: stack_frame_type append; // frame_type 252 + locals_map #30; // class LoadableDescriptorsAttributeTest$V5; + aconst_null; + 10: astore_3; + 11: stack_frame_type same; // frame_type 1 + return; + } + + Method #27:#32 // goo:"([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8;" + stack 1 locals 2 + { + 0: aconst_null; + 1: areturn; + } + + SourceFile #34; // LoadableDescriptorsAttributeTest.java + + NestHost #36; // LoadableDescriptorsAttributeTest + + InnerClass static final #39 = #2 of #36; // X = class LoadableDescriptorsAttributeTest$X of class LoadableDescriptorsAttributeTest + InnerClass final #42 = #40 of #36; // V1 = class LoadableDescriptorsAttributeTest$V1 of class LoadableDescriptorsAttributeTest + InnerClass final #45 = #43 of #36; // V7 = class LoadableDescriptorsAttributeTest$V7 of class LoadableDescriptorsAttributeTest + InnerClass abstract #48 = #46 of #36; // V10 = class LoadableDescriptorsAttributeTest$V10 of class LoadableDescriptorsAttributeTest + InnerClass final #51 = #49 of #36; // V2 = class LoadableDescriptorsAttributeTest$V2 of class LoadableDescriptorsAttributeTest + InnerClass final #54 = #52 of #36; // V3 = class LoadableDescriptorsAttributeTest$V3 of class LoadableDescriptorsAttributeTest + InnerClass final #57 = #55 of #36; // V6 = class LoadableDescriptorsAttributeTest$V6 of class LoadableDescriptorsAttributeTest + InnerClass final #58 = #30 of #36; // V5 = class LoadableDescriptorsAttributeTest$V5 of class LoadableDescriptorsAttributeTest + InnerClass final #61 = #59 of #36; // V9 = class LoadableDescriptorsAttributeTest$V9 of class LoadableDescriptorsAttributeTest + InnerClass final #64 = #62 of #36; // V8 = class LoadableDescriptorsAttributeTest$V8 of class LoadableDescriptorsAttributeTest + + LoadableDescriptors #66, #10, #67; // "LLoadableDescriptorsAttributeTest$V3;", "LLoadableDescriptorsAttributeTest$V7;", "LLoadableDescriptorsAttributeTest$V2;" +} // end Class LoadableDescriptorsAttributeTest$X compiled from "LoadableDescriptorsAttributeTest.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +class LoadableDescriptorsAttributeTest$X { + 0xCAFEBABE; + 65535; // minor version + 69; // version + [68] { // Constant Pool + ; // first element is empty + Field #2 #3; // #1 at 0x0A + Class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "LoadableDescriptorsAttributeTest$X"; // #4 at 0x17 + Utf8 "v1"; // #5 at 0x3C + Utf8 "[LLoadableDescriptorsAttributeTest$V1;"; // #6 at 0x41 + Field #2 #8; // #7 at 0x6A + NameAndType #9 #10; // #8 at 0x6F + Utf8 "v7"; // #9 at 0x74 + Utf8 "LLoadableDescriptorsAttributeTest$V7;"; // #10 at 0x79 + Field #2 #12; // #11 at 0xA1 + NameAndType #13 #14; // #12 at 0xA6 + Utf8 "v10"; // #13 at 0xAB + Utf8 "LLoadableDescriptorsAttributeTest$V10;"; // #14 at 0xB1 + Method #16 #17; // #15 at 0xDA + Class #18; // #16 at 0xDF + NameAndType #19 #20; // #17 at 0xE2 + Utf8 "java/lang/Object"; // #18 at 0xE7 + Utf8 ""; // #19 at 0xFA + Utf8 "()V"; // #20 at 0x0103 + Utf8 "Code"; // #21 at 0x0109 + Utf8 "LineNumberTable"; // #22 at 0x0110 + Utf8 "foo"; // #23 at 0x0122 + Utf8 "()LLoadableDescriptorsAttributeTest$V2;"; // #24 at 0x0128 + Utf8 "(LLoadableDescriptorsAttributeTest$V3;)V"; // #25 at 0x0152 + Utf8 "(I)V"; // #26 at 0x017D + Utf8 "goo"; // #27 at 0x0184 + Utf8 "([LLoadableDescriptorsAttributeTest$V6;)V"; // #28 at 0x018A + Utf8 "StackMapTable"; // #29 at 0x01B6 + Class #31; // #30 at 0x01C6 + Utf8 "LoadableDescriptorsAttributeTest$V5"; // #31 at 0x01C9 + Utf8 "([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8;"; // #32 at 0x01EF + Utf8 "SourceFile"; // #33 at 0x0240 + Utf8 "LoadableDescriptorsAttributeTest.java"; // #34 at 0x024D + Utf8 "NestHost"; // #35 at 0x0275 + Class #37; // #36 at 0x0280 + Utf8 "LoadableDescriptorsAttributeTest"; // #37 at 0x0283 + Utf8 "InnerClasses"; // #38 at 0x02A6 + Utf8 "X"; // #39 at 0x02B5 + Class #41; // #40 at 0x02B9 + Utf8 "LoadableDescriptorsAttributeTest$V1"; // #41 at 0x02BC + Utf8 "V1"; // #42 at 0x02E2 + Class #44; // #43 at 0x02E7 + Utf8 "LoadableDescriptorsAttributeTest$V7"; // #44 at 0x02EA + Utf8 "V7"; // #45 at 0x0310 + Class #47; // #46 at 0x0315 + Utf8 "LoadableDescriptorsAttributeTest$V10"; // #47 at 0x0318 + Utf8 "V10"; // #48 at 0x033F + Class #50; // #49 at 0x0345 + Utf8 "LoadableDescriptorsAttributeTest$V2"; // #50 at 0x0348 + Utf8 "V2"; // #51 at 0x036E + Class #53; // #52 at 0x0373 + Utf8 "LoadableDescriptorsAttributeTest$V3"; // #53 at 0x0376 + Utf8 "V3"; // #54 at 0x039C + Class #56; // #55 at 0x03A1 + Utf8 "LoadableDescriptorsAttributeTest$V6"; // #56 at 0x03A4 + Utf8 "V6"; // #57 at 0x03CA + Utf8 "V5"; // #58 at 0x03CF + Class #60; // #59 at 0x03D4 + Utf8 "LoadableDescriptorsAttributeTest$V9"; // #60 at 0x03D7 + Utf8 "V9"; // #61 at 0x03FD + Class #63; // #62 at 0x0402 + Utf8 "LoadableDescriptorsAttributeTest$V8"; // #63 at 0x0405 + Utf8 "V8"; // #64 at 0x042B + Utf8 "LoadableDescriptors"; // #65 at 0x0430 + Utf8 "LLoadableDescriptorsAttributeTest$V3;"; // #66 at 0x0446 + Utf8 "LLoadableDescriptorsAttributeTest$V2;"; // #67 at 0x046E + } // end of Constant Pool + + 0x0010; // access [ ACC_FINAL ] + #2; // this_cpx + #16; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [3] { // Fields + { // field at 0x04A0 + 0x0810; // access + #5; // name_index : v1 + #6; // descriptor_index : [LLoadableDescriptorsAttributeTest$V1; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x04A8 + 0x0810; // access + #9; // name_index : v7 + #10; // descriptor_index : LLoadableDescriptorsAttributeTest$V7; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x04B0 + 0x0810; // access + #13; // name_index : v10 + #14; // descriptor_index : LLoadableDescriptorsAttributeTest$V10; + [0] { // Attributes + } // end of Attributes + } + } // end of Fields + + [6] { // Methods + { // method at 0x04BA + 0x0000; // access + #19; // name_index : + #20; // descriptor_index : ()V + [1] { // Attributes + Attr(#21, 60) { // Code at 0x04C2 + 2; // max_stack + 1; // max_locals + Bytes[20]{ + 0x2A 0x01 0xB5 0x00 0x01 0x2A 0x01 0xB5 0x00 0x07 0x2A 0x01; + 0xB5 0x00 0x0B 0x2A 0xB7 0x00 0x0F 0xB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#22, 22) { // LineNumberTable at 0x04E8 + [5] { // line_number_table + 0 50; // at 0x04F4 + 5 67; // at 0x04F8 + 10 71; // at 0x04FC + 15 49; // at 0x0500 + 19 71; // at 0x0504 + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0504 + 0x0000; // access + #23; // name_index : foo + #24; // descriptor_index : ()LLoadableDescriptorsAttributeTest$V2; + [1] { // Attributes + Attr(#21, 26) { // Code at 0x050C + 1; // max_stack + 1; // max_locals + Bytes[2]{ + 0x01 0xB0; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#22, 6) { // LineNumberTable at 0x0520 + [1] { // line_number_table + 0 52; // at 0x052C + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x052C + 0x0000; // access + #23; // name_index : foo + #25; // descriptor_index : (LLoadableDescriptorsAttributeTest$V3;)V + [1] { // Attributes + Attr(#21, 25) { // Code at 0x0534 + 0; // max_stack + 2; // max_locals + Bytes[1]{ + 0xB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#22, 6) { // LineNumberTable at 0x0547 + [1] { // line_number_table + 0 55; // at 0x0553 + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0553 + 0x0000; // access + #23; // name_index : foo + #26; // descriptor_index : (I)V + [1] { // Attributes + Attr(#21, 31) { // Code at 0x055B + 1; // max_stack + 3; // max_locals + Bytes[3]{ + 0x01 0x4D 0xB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#22, 10) { // LineNumberTable at 0x0570 + [2] { // line_number_table + 0 57; // at 0x057C + 2 58; // at 0x0580 + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0580 + 0x0000; // access + #27; // name_index : goo + #28; // descriptor_index : ([LLoadableDescriptorsAttributeTest$V6;)V + [1] { // Attributes + Attr(#21, 63) { // Code at 0x0588 + 1; // max_stack + 4; // max_locals + Bytes[12]{ + 0x01 0x4D 0x2C 0xC7 0x00 0x06 0xA7 0x00 0x05 0x01 0x4E 0xB1; +; + } + [0] { // Traps + } // end of Traps + [2] { // Attributes + Attr(#22, 18) { // LineNumberTable at 0x05A6 + [4] { // line_number_table + 0 60; // at 0x05B2 + 2 61; // at 0x05B6 + 9 64; // at 0x05BA + 11 66; // at 0x05BE + } + } // end of LineNumberTable + ; + Attr(#29, 9) { // StackMapTable at 0x05BE + [2] { // + 252b, 9, [1]z{7b,#30}; // append_frame 1 + 1b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x05CD + 0x0000; // access + #27; // name_index : goo + #32; // descriptor_index : ([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8; + [1] { // Attributes + Attr(#21, 26) { // Code at 0x05D5 + 1; // max_stack + 2; // max_locals + Bytes[2]{ + 0x01 0xB0; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#22, 6) { // LineNumberTable at 0x05E9 + [1] { // line_number_table + 0 69; // at 0x05F5 + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [4] { // Attributes + Attr(#33, 2) { // SourceFile at 0x05F7 + #34; + } // end of SourceFile + ; + Attr(#35, 2) { // NestHost at 0x05FF + #36; // class: LoadableDescriptorsAttributeTest at 0x0607 + } // end of NestHost + ; + Attr(#38, 82) { // InnerClasses at 0x0607 + [10] { // classes + #2 #36 #39 24; // access [ ACC_STATIC, ACC_FINAL ] + #40 #36 #42 16; // access [ ACC_FINAL ] + #43 #36 #45 16; // access [ ACC_FINAL ] + #46 #36 #48 1024; // access [ ACC_ABSTRACT ] + #49 #36 #51 16; // access [ ACC_FINAL ] + #52 #36 #54 16; // access [ ACC_FINAL ] + #55 #36 #57 16; // access [ ACC_FINAL ] + #30 #36 #58 16; // access [ ACC_FINAL ] + #59 #36 #61 16; // access [ ACC_FINAL ] + #62 #36 #64 16; // access [ ACC_FINAL ] + } + } // end of InnerClasses + ; + Attr(#65, 8) { // LoadableDescriptors at 0x065F + [3] { // Utf8 + #66; // descriptor: LLoadableDescriptorsAttributeTest$V3; at 0x0669 + #10; // descriptor: LLoadableDescriptorsAttributeTest$V7; at 0x066B + #67; // descriptor: LLoadableDescriptorsAttributeTest$V2; at 0x066D + } + } // end of LoadableDescriptors + } // end of Attributes +} // end of class LoadableDescriptorsAttributeTest$X diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.t.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.t.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.t.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.g.t.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +final class #2 /* LoadableDescriptorsAttributeTest$X */ version 69:65535 +{ + const #1 = Fieldref #2.#3; // LoadableDescriptorsAttributeTest$X.v1:"[LLoadableDescriptorsAttributeTest$V1;" + const #2 = Class #4; // LoadableDescriptorsAttributeTest$X + const #3 = NameAndType #5:#6; // v1:"[LLoadableDescriptorsAttributeTest$V1;" + const #4 = Utf8 "LoadableDescriptorsAttributeTest$X"; + const #5 = Utf8 "v1"; + const #6 = Utf8 "[LLoadableDescriptorsAttributeTest$V1;"; + const #7 = Fieldref #2.#8; // LoadableDescriptorsAttributeTest$X.v7:"LLoadableDescriptorsAttributeTest$V7;" + const #8 = NameAndType #9:#10; // v7:"LLoadableDescriptorsAttributeTest$V7;" + const #9 = Utf8 "v7"; + const #10 = Utf8 "LLoadableDescriptorsAttributeTest$V7;"; + const #11 = Fieldref #2.#12; // LoadableDescriptorsAttributeTest$X.v10:"LLoadableDescriptorsAttributeTest$V10;" + const #12 = NameAndType #13:#14; // v10:"LLoadableDescriptorsAttributeTest$V10;" + const #13 = Utf8 "v10"; + const #14 = Utf8 "LLoadableDescriptorsAttributeTest$V10;"; + const #15 = Methodref #16.#17; // java/lang/Object."":"()V" + const #16 = Class #18; // java/lang/Object + const #17 = NameAndType #19:#20; // "":"()V" + const #18 = Utf8 "java/lang/Object"; + const #19 = Utf8 ""; + const #20 = Utf8 "()V"; + const #21 = Utf8 "Code"; + const #22 = Utf8 "LineNumberTable"; + const #23 = Utf8 "foo"; + const #24 = Utf8 "()LLoadableDescriptorsAttributeTest$V2;"; + const #25 = Utf8 "(LLoadableDescriptorsAttributeTest$V3;)V"; + const #26 = Utf8 "(I)V"; + const #27 = Utf8 "goo"; + const #28 = Utf8 "([LLoadableDescriptorsAttributeTest$V6;)V"; + const #29 = Utf8 "StackMapTable"; + const #30 = Class #31; // LoadableDescriptorsAttributeTest$V5 + const #31 = Utf8 "LoadableDescriptorsAttributeTest$V5"; + const #32 = Utf8 "([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8;"; + const #33 = Utf8 "SourceFile"; + const #34 = Utf8 "LoadableDescriptorsAttributeTest.java"; + const #35 = Utf8 "NestHost"; + const #36 = Class #37; // LoadableDescriptorsAttributeTest + const #37 = Utf8 "LoadableDescriptorsAttributeTest"; + const #38 = Utf8 "InnerClasses"; + const #39 = Utf8 "X"; + const #40 = Class #41; // LoadableDescriptorsAttributeTest$V1 + const #41 = Utf8 "LoadableDescriptorsAttributeTest$V1"; + const #42 = Utf8 "V1"; + const #43 = Class #44; // LoadableDescriptorsAttributeTest$V7 + const #44 = Utf8 "LoadableDescriptorsAttributeTest$V7"; + const #45 = Utf8 "V7"; + const #46 = Class #47; // LoadableDescriptorsAttributeTest$V10 + const #47 = Utf8 "LoadableDescriptorsAttributeTest$V10"; + const #48 = Utf8 "V10"; + const #49 = Class #50; // LoadableDescriptorsAttributeTest$V2 + const #50 = Utf8 "LoadableDescriptorsAttributeTest$V2"; + const #51 = Utf8 "V2"; + const #52 = Class #53; // LoadableDescriptorsAttributeTest$V3 + const #53 = Utf8 "LoadableDescriptorsAttributeTest$V3"; + const #54 = Utf8 "V3"; + const #55 = Class #56; // LoadableDescriptorsAttributeTest$V6 + const #56 = Utf8 "LoadableDescriptorsAttributeTest$V6"; + const #57 = Utf8 "V6"; + const #58 = Utf8 "V5"; + const #59 = Class #60; // LoadableDescriptorsAttributeTest$V9 + const #60 = Utf8 "LoadableDescriptorsAttributeTest$V9"; + const #61 = Utf8 "V9"; + const #62 = Class #63; // LoadableDescriptorsAttributeTest$V8 + const #63 = Utf8 "LoadableDescriptorsAttributeTest$V8"; + const #64 = Utf8 "V8"; + const #65 = Utf8 "LoadableDescriptors"; + const #66 = Utf8 "LLoadableDescriptorsAttributeTest$V3;"; + const #67 = Utf8 "LLoadableDescriptorsAttributeTest$V2;"; + + final strict Field #5:#6; // v1:"[LLoadableDescriptorsAttributeTest$V1;" + final strict Field #9:#10; // v7:"LLoadableDescriptorsAttributeTest$V7;" + final strict Field #13:#14; // v10:"LLoadableDescriptorsAttributeTest$V10;" + + Method #19:#20 // "":"()V" + stack 2 locals 1 + { + 0: aload_0; + 1: aconst_null; + 2: putfield #1; // Field v1:"[LLoadableDescriptorsAttributeTest$V1;" + 5: aload_0; + 6: aconst_null; + 7: putfield #7; // Field v7:"LLoadableDescriptorsAttributeTest$V7;" + 10: aload_0; + 11: aconst_null; + 12: putfield #11; // Field v10:"LLoadableDescriptorsAttributeTest$V10;" + 15: aload_0; + 16: invokespecial #15; // Method java/lang/Object."":"()V" + 19: return; + } + + Method #23:#24 // foo:"()LLoadableDescriptorsAttributeTest$V2;" + stack 1 locals 1 + { + 0: aconst_null; + 1: areturn; + } + + Method #23:#25 // foo:"(LLoadableDescriptorsAttributeTest$V3;)V" + stack 0 locals 2 + { + 0: return; + } + + Method #23:#26 // foo:"(I)V" + stack 1 locals 3 + { + 0: aconst_null; + 1: astore_2; + 2: return; + } + + Method #27:#28 // goo:"([LLoadableDescriptorsAttributeTest$V6;)V" + stack 1 locals 4 + { + 0: aconst_null; + 1: astore_2; + 2: aload_2; + 3: ifnonnull 9; + 6: goto 11; + 9: aconst_null; + 10: astore_3; + 11: return; + StackMapTable: number_of_entries = 2 + frame_type = 252 // append + offset_delta = 9 + locals_map = [ #30; ] // class LoadableDescriptorsAttributeTest$V5; + frame_type = 1 // same + } + + Method #27:#32 // goo:"([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8;" + stack 1 locals 2 + { + 0: aconst_null; + 1: areturn; + } + + SourceFile #34; // LoadableDescriptorsAttributeTest.java + + NestHost #36; // LoadableDescriptorsAttributeTest + + InnerClasses { + static final #39 = #2 of #36; // X = class LoadableDescriptorsAttributeTest$X of class LoadableDescriptorsAttributeTest + final #42 = #40 of #36; // V1 = class LoadableDescriptorsAttributeTest$V1 of class LoadableDescriptorsAttributeTest + final #45 = #43 of #36; // V7 = class LoadableDescriptorsAttributeTest$V7 of class LoadableDescriptorsAttributeTest + abstract #48 = #46 of #36; // V10 = class LoadableDescriptorsAttributeTest$V10 of class LoadableDescriptorsAttributeTest + final #51 = #49 of #36; // V2 = class LoadableDescriptorsAttributeTest$V2 of class LoadableDescriptorsAttributeTest + final #54 = #52 of #36; // V3 = class LoadableDescriptorsAttributeTest$V3 of class LoadableDescriptorsAttributeTest + final #57 = #55 of #36; // V6 = class LoadableDescriptorsAttributeTest$V6 of class LoadableDescriptorsAttributeTest + final #58 = #30 of #36; // V5 = class LoadableDescriptorsAttributeTest$V5 of class LoadableDescriptorsAttributeTest + final #61 = #59 of #36; // V9 = class LoadableDescriptorsAttributeTest$V9 of class LoadableDescriptorsAttributeTest + final #64 = #62 of #36; // V8 = class LoadableDescriptorsAttributeTest$V8 of class LoadableDescriptorsAttributeTest + } + + LoadableDescriptors #66, #10, #67; // "LLoadableDescriptorsAttributeTest$V3;", "LLoadableDescriptorsAttributeTest$V7;", "LLoadableDescriptorsAttributeTest$V2;" +} // end Class LoadableDescriptorsAttributeTest$X compiled from "LoadableDescriptorsAttributeTest.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +final class LoadableDescriptorsAttributeTest$X version 69:65535 +{ + final strict Field v1:"[LLoadableDescriptorsAttributeTest$V1;"; + final strict Field v7:"LLoadableDescriptorsAttributeTest$V7;"; + final strict Field v10:"LLoadableDescriptorsAttributeTest$V10;"; + + Method "":"()V" + stack 2 locals 1 + { + aload_0; + aconst_null; + putfield Field v1:"[LLoadableDescriptorsAttributeTest$V1;"; + aload_0; + aconst_null; + putfield Field v7:"LLoadableDescriptorsAttributeTest$V7;"; + aload_0; + aconst_null; + putfield Field v10:"LLoadableDescriptorsAttributeTest$V10;"; + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method foo:"()LLoadableDescriptorsAttributeTest$V2;" + stack 1 locals 1 + { + aconst_null; + areturn; + } + + Method foo:"(LLoadableDescriptorsAttributeTest$V3;)V" + stack 0 locals 2 + { + return; + } + + Method foo:"(I)V" + stack 1 locals 3 + { + aconst_null; + astore_2; + return; + } + + Method goo:"([LLoadableDescriptorsAttributeTest$V6;)V" + stack 1 locals 4 + { + aconst_null; + astore_2; + aload_2; + ifnonnull L9; + goto L11; + L9: stack_frame_type append; + locals_map class LoadableDescriptorsAttributeTest$V5; + aconst_null; + astore_3; + L11: stack_frame_type same; + return; + } + + Method goo:"([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8;" + stack 1 locals 2 + { + aconst_null; + areturn; + } + + SourceFile "LoadableDescriptorsAttributeTest.java"; + + NestHost "LoadableDescriptorsAttributeTest"; + + InnerClass static final X = class LoadableDescriptorsAttributeTest$X of class LoadableDescriptorsAttributeTest; + InnerClass final V1 = class LoadableDescriptorsAttributeTest$V1 of class LoadableDescriptorsAttributeTest; + InnerClass final V7 = class LoadableDescriptorsAttributeTest$V7 of class LoadableDescriptorsAttributeTest; + InnerClass abstract V10 = class LoadableDescriptorsAttributeTest$V10 of class LoadableDescriptorsAttributeTest; + InnerClass final V2 = class LoadableDescriptorsAttributeTest$V2 of class LoadableDescriptorsAttributeTest; + InnerClass final V3 = class LoadableDescriptorsAttributeTest$V3 of class LoadableDescriptorsAttributeTest; + InnerClass final V6 = class LoadableDescriptorsAttributeTest$V6 of class LoadableDescriptorsAttributeTest; + InnerClass final V5 = class LoadableDescriptorsAttributeTest$V5 of class LoadableDescriptorsAttributeTest; + InnerClass final V9 = class LoadableDescriptorsAttributeTest$V9 of class LoadableDescriptorsAttributeTest; + InnerClass final V8 = class LoadableDescriptorsAttributeTest$V8 of class LoadableDescriptorsAttributeTest; + + LoadableDescriptors "LLoadableDescriptorsAttributeTest$V3;", + "LLoadableDescriptorsAttributeTest$V7;", + "LLoadableDescriptorsAttributeTest$V2;"; +} // end Class LoadableDescriptorsAttributeTest$X compiled from "LoadableDescriptorsAttributeTest.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/LoadableDescriptorsAttributeTest$X.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +class LoadableDescriptorsAttributeTest$X { + 0xCAFEBABE; + 65535; // minor version + 69; // version + [] { // Constant Pool + ; // first element is empty + Field #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "LoadableDescriptorsAttributeTest$X"; // #4 + Utf8 "v1"; // #5 + Utf8 "[LLoadableDescriptorsAttributeTest$V1;"; // #6 + Field #2 #8; // #7 + NameAndType #9 #10; // #8 + Utf8 "v7"; // #9 + Utf8 "LLoadableDescriptorsAttributeTest$V7;"; // #10 + Field #2 #12; // #11 + NameAndType #13 #14; // #12 + Utf8 "v10"; // #13 + Utf8 "LLoadableDescriptorsAttributeTest$V10;"; // #14 + Method #16 #17; // #15 + Class #18; // #16 + NameAndType #19 #20; // #17 + Utf8 "java/lang/Object"; // #18 + Utf8 ""; // #19 + Utf8 "()V"; // #20 + Utf8 "Code"; // #21 + Utf8 "LineNumberTable"; // #22 + Utf8 "foo"; // #23 + Utf8 "()LLoadableDescriptorsAttributeTest$V2;"; // #24 + Utf8 "(LLoadableDescriptorsAttributeTest$V3;)V"; // #25 + Utf8 "(I)V"; // #26 + Utf8 "goo"; // #27 + Utf8 "([LLoadableDescriptorsAttributeTest$V6;)V"; // #28 + Utf8 "StackMapTable"; // #29 + Class #31; // #30 + Utf8 "LoadableDescriptorsAttributeTest$V5"; // #31 + Utf8 "([LLoadableDescriptorsAttributeTest$V9;)[LLoadableDescriptorsAttributeTest$V8;"; // #32 + Utf8 "SourceFile"; // #33 + Utf8 "LoadableDescriptorsAttributeTest.java"; // #34 + Utf8 "NestHost"; // #35 + Class #37; // #36 + Utf8 "LoadableDescriptorsAttributeTest"; // #37 + Utf8 "InnerClasses"; // #38 + Utf8 "X"; // #39 + Class #41; // #40 + Utf8 "LoadableDescriptorsAttributeTest$V1"; // #41 + Utf8 "V1"; // #42 + Class #44; // #43 + Utf8 "LoadableDescriptorsAttributeTest$V7"; // #44 + Utf8 "V7"; // #45 + Class #47; // #46 + Utf8 "LoadableDescriptorsAttributeTest$V10"; // #47 + Utf8 "V10"; // #48 + Class #50; // #49 + Utf8 "LoadableDescriptorsAttributeTest$V2"; // #50 + Utf8 "V2"; // #51 + Class #53; // #52 + Utf8 "LoadableDescriptorsAttributeTest$V3"; // #53 + Utf8 "V3"; // #54 + Class #56; // #55 + Utf8 "LoadableDescriptorsAttributeTest$V6"; // #56 + Utf8 "V6"; // #57 + Utf8 "V5"; // #58 + Class #60; // #59 + Utf8 "LoadableDescriptorsAttributeTest$V9"; // #60 + Utf8 "V9"; // #61 + Class #63; // #62 + Utf8 "LoadableDescriptorsAttributeTest$V8"; // #63 + Utf8 "V8"; // #64 + Utf8 "LoadableDescriptors"; // #65 + Utf8 "LLoadableDescriptorsAttributeTest$V3;"; // #66 + Utf8 "LLoadableDescriptorsAttributeTest$V2;"; // #67 + } + + 0x0010; // access + #2; // this_cpx + #16; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0810; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0810; // access + #9; // name_index + #10; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0810; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0000; // access + #19; // name_index + #20; // descriptor_index + [] { // Attributes + Attr(#21) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0x01 0xB5 0x00 0x01 0x2A 0x01 0xB5 0x00 0x07 0x2A 0x01; + 0xB5 0x00 0x0B 0x2A 0xB7 0x00 0x0F 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#22) { // LineNumberTable + [] { // line_number_table + 0 50; + 5 67; + 10 71; + 15 49; + 19 71; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0000; // access + #23; // name_index + #24; // descriptor_index + [] { // Attributes + Attr(#21) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x01 0xB0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#22) { // LineNumberTable + [] { // line_number_table + 0 52; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0000; // access + #23; // name_index + #25; // descriptor_index + [] { // Attributes + Attr(#21) { // Code + 0; // max_stack + 2; // max_locals + Bytes[]{ + 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#22) { // LineNumberTable + [] { // line_number_table + 0 55; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0000; // access + #23; // name_index + #26; // descriptor_index + [] { // Attributes + Attr(#21) { // Code + 1; // max_stack + 3; // max_locals + Bytes[]{ + 0x01 0x4D 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#22) { // LineNumberTable + [] { // line_number_table + 0 57; + 2 58; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0000; // access + #27; // name_index + #28; // descriptor_index + [] { // Attributes + Attr(#21) { // Code + 1; // max_stack + 4; // max_locals + Bytes[]{ + 0x01 0x4D 0x2C 0xC7 0x00 0x06 0xA7 0x00 0x05 0x01 0x4E 0xB1; +; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#22) { // LineNumberTable + [] { // line_number_table + 0 60; + 2 61; + 9 64; + 11 66; + } + } // end of LineNumberTable + ; + Attr(#29) { // StackMapTable + [] { // + 252b, 9, []z{O,#30}; // append_frame 1 + 1b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0000; // access + #27; // name_index + #32; // descriptor_index + [] { // Attributes + Attr(#21) { // Code + 1; // max_stack + 2; // max_locals + Bytes[]{ + 0x01 0xB0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#22) { // LineNumberTable + [] { // line_number_table + 0 69; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#33) { // SourceFile + #34; + } // end of SourceFile + ; + Attr(#35) { // NestHost + #36; + } // end of NestHost + ; + Attr(#38) { // InnerClasses + [] { // classes + #2 #36 #39 24; + #40 #36 #42 16; + #43 #36 #45 16; + #46 #36 #48 1024; + #49 #36 #51 16; + #52 #36 #54 16; + #55 #36 #57 16; + #30 #36 #58 16; + #59 #36 #61 16; + #62 #36 #64 16; + } + } // end of InnerClasses + ; + Attr(#65) { // LoadableDescriptors + [] { // Utf8 + #66; + #10; + #67; + } + } // end of LoadableDescriptors + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/Test01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/Test01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/Test01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/LoadableDescriptors/Test01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package org/openjdk/asmtools/attribute/LoadableDescriptors; + +public class Test01 version 55:0 +{ + LoadableDescriptors "LLoadableDescriptors01;", "LLoadableDescriptors02;"; + + InnerClass public Test01 = class Test01 of class OuterClass; +} // end Class org/openjdk/asmtools/attribute/NestHost/Test01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package org/openjdk/asmtools/attribute/NestHost; + +public class #2 /* Test01 */ version 55:0 +{ + const #1 = Utf8 "org/openjdk/asmtools/attribute/NestHost/Test01"; + const #2 = Class #1; // Test01 + const #3 = Utf8 "org/openjdk/asmtools/attribute/NestHost/NestHost01"; + const #4 = Utf8 "NestHost"; + const #5 = Class #3; // NestHost01 + const #6 = Utf8 "Test01"; + const #7 = Utf8 "org/openjdk/asmtools/attribute/NestHost/OuterClass"; + const #8 = Class #7; // OuterClass + const #9 = Utf8 "InnerClasses"; + const #10 = Utf8 "Test01.jasm"; + const #11 = Utf8 "SourceFile"; + const #12 = Utf8 "java/lang/Object"; + const #13 = Class #12; // java/lang/Object + + SourceFile #10; // Test01.jasm + + NestHost #5; // org/openjdk/asmtools/attribute/NestHost/NestHost01 + + InnerClasses { + public #6 = #2 of #8; // Test01 = class Test01 of class OuterClass + } +} // end Class org/openjdk/asmtools/attribute/NestHost/Test01 compiled from "Test01.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package org/openjdk/asmtools/attribute/NestHost; + +public class Test01 version 55:0 +{ + NestHost "NestHost01"; + + InnerClass public Test01 = class Test01 of class OuterClass; +} // end Class org/openjdk/asmtools/attribute/NestHost/Test01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test01.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ +class org/openjdk/asmtools/attribute/NestHost/Test01 { + 0xCAFEBABE; + 0; // minor version + 55; // version + [14] { // Constant Pool + ; // first element is empty + Utf8 "org/openjdk/asmtools/attribute/NestHost/Test01"; // #1 at 0x0A + Class #1; // #2 at 0x36 + Utf8 "org/openjdk/asmtools/attribute/NestHost/NestHost01"; // #3 at 0x39 + Utf8 "NestHost"; // #4 at 0x69 + Class #3; // #5 at 0x74 + Utf8 "Test01"; // #6 at 0x77 + Utf8 "org/openjdk/asmtools/attribute/NestHost/OuterClass"; // #7 at 0x80 + Class #7; // #8 at 0xB0 + Utf8 "InnerClasses"; // #9 at 0xB3 + Utf8 "Test01.jasm"; // #10 at 0xC2 + Utf8 "SourceFile"; // #11 at 0xD0 + Utf8 "java/lang/Object"; // #12 at 0xDD + Class #12; // #13 at 0xF0 + } // end of Constant Pool + + 0x0001; // access [ ACC_PUBLIC ] + #2; // this_cpx + #13; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [0] { // Methods + } // end of Methods + + [3] { // Attributes + Attr(#11, 2) { // SourceFile at 0x0101 + #10; + } // end of SourceFile + ; + Attr(#9, 10) { // InnerClasses at 0x0109 + [1] { // classes + #2 #8 #6 1; // access [ ACC_PUBLIC ] + } + } // end of InnerClasses + ; + Attr(#4, 2) { // NestHost at 0x0119 + #5; // class: org/openjdk/asmtools/attribute/NestHost/NestHost01 at 0x0121 + } // end of NestHost + } // end of Attributes +} // end of class org/openjdk/asmtools/attribute/NestHost/Test01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestHost/Test02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package org/openjdk/asmtools/attribute/NestHost; + +public class Test02 version 55:0 +{ + SourceFile "Test02.jasm"; + + NestHost org/openjdk/asmtools/attribute/NestHost/NestHost02; + + InnerClass public Test02 = class Test02 of class OuterClass; +} // end Class org/openjdk/asmtools/attribute/NestHost/Test02 compiled from "Test02.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.g.t.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.g.t.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.g.t.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.g.t.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + package org/openjdk/asmtools/attribute/NestMembers/Test01; + +public class #2 /* Test01 */ version 55:0 +{ + const #1 = Utf8 "org/openjdk/asmtools/attribute/NestMembers/Test01/Test01"; + const #2 = Class #1; // Test01 + const #3 = Utf8 "NestMember01"; + const #4 = Utf8 "org/openjdk/asmtools/attribute/NestMembers/Test01/NestMember01"; + const #5 = Class #4; // NestMember01 + const #6 = Utf8 "InnerClasses"; + const #7 = Utf8 "NestMembers"; + const #8 = Utf8 "Test01.jasm"; + const #9 = Utf8 "SourceFile"; + const #10 = Utf8 "java/lang/Object"; + const #11 = Class #10; // java/lang/Object + + SourceFile #8; // Test01.jasm + + InnerClasses { + public #3 = #5 of #2; // NestMember01 = class NestMember01 of class Test01 + } + + NestMembers #5; // NestMember01 +} // end Class org/openjdk/asmtools/attribute/NestMembers/Test01/Test01 compiled from "Test01.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package org/openjdk/asmtools/attribute/NestMembers/Test01; + +public class Test01 version 55:0 +{ + InnerClass public NestMember01 = class NestMember01 of class Test01; + + NestMembers NestMember01; +} // end Class org/openjdk/asmtools/attribute/NestMembers/Test01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test01.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +class org/openjdk/asmtools/attribute/NestMembers/Test01 { + 0xCAFEBABE; + 0; // minor version + 55; // version + [12] { // Constant Pool + ; // first element is empty + Utf8 "org/openjdk/asmtools/attribute/NestMembers/Test01"; // #1 at 0x0A + Class #1; // #2 at 0x3D + Utf8 "NestMember01"; // #3 at 0x40 + Utf8 "org/openjdk/asmtools/attribute/NestMembers/Test01/NestMember01"; // #4 at 0x4F + Class #4; // #5 at 0x88 + Utf8 "InnerClasses"; // #6 at 0x8B + Utf8 "NestMembers"; // #7 at 0x9A + Utf8 "Test01.jasm"; // #8 at 0xA8 + Utf8 "SourceFile"; // #9 at 0xB6 + Utf8 "java/lang/Object"; // #10 at 0xC3 + Class #10; // #11 at 0xD6 + } // end of Constant Pool + + 0x0001; // access [ ACC_PUBLIC ] + #2; // this_cpx + #11; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [0] { // Methods + } // end of Methods + + [3] { // Attributes + Attr(#9, 2) { // SourceFile at 0xE7 + #8; + } // end of SourceFile + ; + Attr(#6, 10) { // InnerClasses at 0xEF + [1] { // classes + #5 #2 #3 1; // access [ ACC_PUBLIC ] + } + } // end of InnerClasses + ; + Attr(#7, 4) { // NestMembers at 0xFF + [1] { // classes + #5; // class: org/openjdk/asmtools/attribute/NestMembers/Test01/NestMember01 at 0x0109 + } + } // end of NestMembers + } // end of Attributes +} // end of class org/openjdk/asmtools/attribute/NestMembers/Test01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/NestMembers/Test02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package javasoft/sqe/tests/api/java/lang/reflect/RecordComponent; + +public final super class Test02 extends java/lang/Record version 69:0 +{ + private final Field cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;"; + + public Method "":"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;)V" + stack 2 locals 2 + { + aload_0; + invokespecial Method java/lang/Record."":"()V"; + aload_0; + aload_1; + putfield Field cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;"; + return; + } + + public final Method toString:"()Ljava/lang/String;" + stack 1 locals 1 + { + aload_0; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;": + toString:"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02;)Ljava/lang/String;" { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;" + }; + areturn; + } + + public final Method hashCode:"()I" + stack 1 locals 1 + { + aload_0; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;": + hashCode:"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02;)I" { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;" + }; + ireturn; + } + + public final Method equals:"(Ljava/lang/Object;)Z" + stack 2 locals 2 + { + aload_0; + aload_1; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;": + equals:"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02;Ljava/lang/Object;)Z" { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;" + }; + ireturn; + } + + public Method cir:"()Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;" + stack 1 locals 1 + { + aload_0; + getfield Field cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;"; + areturn; + } + + SourceFile "Test02.java"; + + Record { + Component cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;"; + } + + InnerClass ClassInsideRecord = class Test02$ClassInsideRecord of class Test02; + InnerClass static ClassInsideRecord2 = class Test02$ClassInsideRecord2 of class Test02; + InnerClass static final InnerRecord = class Test02$InnerRecord of class Test02; + InnerClass static abstract InnerInteface = class Test02$ClassInsideRecord2$InnerInteface of class Test02$ClassInsideRecord2; + InnerClass static final InnerInnerRecord = class Test02$InnerRecord$InnerInnerRecord of class Test02$InnerRecord; + InnerClass public static final Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + + NestMembers Test02$ClassInsideRecord2, + Test02$ClassInsideRecord2$InnerInteface, + Test02$ClassInsideRecord, + Test02$InnerRecord, + Test02$InnerRecord$InnerInnerRecord; + + BootstrapMethod REF_invokeStatic:java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; + { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02$ClassInsideRecord;" + } +} // end Class javasoft/sqe/tests/api/java/lang/reflect/RecordComponent/Test02 compiled from "Test02.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.g.t.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.g.t.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.g.t.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.g.t.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package org/openjdk/asmtools/attribute/PermittedSubclasses; + +public super class #3 /* Test01 */ version 62:0 +{ + const #1 = Methodref #9.#10; // java/lang/Object."":"()V" + const #2 = Utf8 "org/openjdk/asmtools/attribute/PermittedSubclasses/Test01"; + const #3 = Class #2; // Test01 + const #4 = Utf8 ""; + const #5 = Utf8 "()V"; + const #6 = Utf8 "Code"; + const #7 = Utf8 "LineNumberTable"; + const #8 = Utf8 "java/lang/Object"; + const #9 = Class #8; // java/lang/Object + const #10 = NameAndType #4:#5; // "":"()V" + const #11 = Utf8 "NestMember01"; + const #12 = Class #11; // NestMember01 + const #13 = Utf8 "Test01"; + const #14 = Class #13; // Test01 + const #15 = Utf8 "InnerClasses"; + const #16 = Utf8 "NestMember02"; + const #17 = Class #16; // NestMember02 + const #18 = Utf8 "NestMember03"; + const #19 = Class #18; // NestMember03 + const #20 = Utf8 "NestMember04"; + const #21 = Class #20; // NestMember04 + const #22 = Utf8 "SubClass01"; + const #23 = Utf8 "SubClass02"; + const #24 = Utf8 "SubClass03"; + const #25 = Utf8 "SubClass04"; + const #26 = Utf8 "PermittedSubclasses"; + const #27 = Class #22; // SubClass01 + const #28 = Class #23; // SubClass02 + const #29 = Class #24; // SubClass03 + const #30 = Class #25; // SubClass04 + const #31 = Utf8 "NestMembers"; + const #32 = Utf8 "Test01.jasm"; + const #33 = Utf8 "SourceFile"; + + public Method #4:#5 // "":"()V" + stack 1 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + } + + SourceFile #32; // Test01.jasm + + InnerClasses { + public #11 = #12 of #14; // NestMember01 = class NestMember01 of class Test01 + public #16 = #17 of #14; // NestMember02 = class NestMember02 of class Test01 + public #18 = #19 of #14; // NestMember03 = class NestMember03 of class Test01 + public #20 = #21 of #14; // NestMember04 = class NestMember04 of class Test01 + } + + NestMembers #12, // NestMember01 + #17, // NestMember02 + #19, // NestMember03 + #21; // NestMember04 + + PermittedSubclasses #27, // SubClass01 + #28, // SubClass02 + #29, // SubClass03 + #30; // SubClass04 +} // end Class org/openjdk/asmtools/attribute/PermittedSubclasses/Test01 compiled from "Test01.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +super public class org/openjdk/asmtools/attribute/PermittedSubclasses/Test01 + version 62:0 +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + InnerClass public NestMember01 = class NestMember01 of class Test01; + InnerClass public NestMember02 = class NestMember02 of class Test01; + InnerClass public NestMember03 = class NestMember03 of class Test01; + InnerClass public NestMember04 = class NestMember04 of class Test01; + + PermittedSubclasses SubClass01, SubClass02, SubClass03, SubClass04; + + NestMembers NestMember01, NestMember02, NestMember03, NestMember04; +} // end Class Test01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test01.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +class org/openjdk/asmtools/attribute/PermittedSubclasses/Test01 { + 0xCAFEBABE; + 0; // minor version + 62; // version + [15] { // Constant Pool + ; // first element is empty + Method #8 #9; // #1 at 0x0A + Utf8 "org/openjdk/asmtools/attribute/PermittedSubclasses/Test01"; // #2 at 0x0F + Class #2; // #3 at 0x37 + Utf8 ""; // #4 at 0x3A + Utf8 "()V"; // #5 at 0x43 + Utf8 "Code"; // #6 at 0x49 + Utf8 "java/lang/Object"; // #7 at 0x50 + Class #7; // #8 at 0x63 + NameAndType #4 #5; // #9 at 0x66 + Utf8 "org/openjdk/asmtools/attribute/PermittedSubclasses/atr/SubClass01"; // #10 at 0x6B + Utf8 "PermittedSubclasses"; // #11 at 0x9B + Class #10; // #12 at 0xB1 + Utf8 "Test01.jasm"; // #13 at 0xB4 + Utf8 "SourceFile"; // #14 at 0xC2 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #3; // this_cpx + #8; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [1] { // Methods + { // method at 0xDB + 0x0001; // access + #4; // name_index : + #5; // descriptor_index : ()V + [1] { // Attributes + Attr(#6, 17) { // Code at 0xE3 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2A 0xB7 0x00 0x01 0xB1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [2] { // Attributes + Attr(#14, 2) { // SourceFile at 0xFC + #13; + } // end of SourceFile + ; + Attr(#11, 4) { // PermittedSubclasses at 0x0104 + [1] { // subclasses + #12; // subclass: org/openjdk/asmtools/attribute/PermittedSubclasses/atr/SubClass01 at 0x010E + } + } // end of PermittedSubclasses + } // end of Attributes +} // end of class org/openjdk/asmtools/attribute/PermittedSubclasses/Test01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/PermittedSubclasses/Test02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +package javasoft/sqe/tests/api/java/lang/reflect/RecordComponent02; + +public final super class Test02 extends java/lang/Record version 69:0 +{ + private final Field cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;"; + + public Method "":"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;)V" + stack 2 locals 2 + { + aload_0; + invokespecial Method java/lang/Record."":"()V"; + aload_0; + aload_1; + putfield Field cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;"; + return; + } + + public final Method toString:"()Ljava/lang/String;" + stack 1 locals 1 + { + aload_0; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;": + toString:"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02;)Ljava/lang/String;" { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;" + }; + areturn; + } + + public final Method hashCode:"()I" + stack 1 locals 1 + { + aload_0; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;": + hashCode:"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02;)I" { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;" + }; + ireturn; + } + + public final Method equals:"(Ljava/lang/Object;)Z" + stack 2 locals 2 + { + aload_0; + aload_1; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;": + equals:"(Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02;Ljava/lang/Object;)Z" { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;" + }; + ireturn; + } + + public Method cir:"()Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;" + stack 1 locals 1 + { + aload_0; + getfield Field cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;"; + areturn; + } + + SourceFile "Test02.java"; + + Record { + Component cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;"; + } + + InnerClass ClassInsideRecord = class Test02$ClassInsideRecord of class Test02; + InnerClass static ClassInsideRecord2 = class Test02$ClassInsideRecord2 of class Test02; + InnerClass static final InnerRecord = class Test02$InnerRecord of class Test02; + InnerClass static abstract InnerInteface = class Test02$ClassInsideRecord2$InnerInteface of class Test02$ClassInsideRecord2; + InnerClass static final InnerInnerRecord = class Test02$InnerRecord$InnerInnerRecord of class Test02$InnerRecord; + InnerClass public static final Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + + PermittedSubclasses Test02$ClassInsideRecord2, + Test02$ClassInsideRecord2$InnerInteface, + Test02$ClassInsideRecord, + Test02$InnerRecord, + Test02$InnerRecord$InnerInnerRecord; + + BootstrapMethod REF_invokeStatic:java/lang/runtime/ObjectMethods.bootstrap: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; + { + class Test02, + String "cir", + MethodHandle REF_getField:Test02.cir:"Ljavasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02$ClassInsideRecord;" + } +} // end Class javasoft/sqe/tests/api/java/lang/reflect/RecordComponent02/Test02 compiled from "Test02.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + */ +package javasoft/sqe/tests/api/java/lang/classfile/resources/jasm/atr; + +public super class SourceDebugExt01 version 66:0 +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + SourceDebugExtension { + "SMAP\nSourceDebugExt01.java\nJava\n*S Java\n*F\n+ 1 SourceDebugExt01.java\nSou"; + "rceDebugExt01.java\n*L\n1#1,5:1\n*E"; + } +} // end Class SourceDebugExt01 compiled from "SourceDebugExt01.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + */ +package javasoft/sqe/tests/api/java/lang/classfile/resources/jasm/atr; + +public super class SourceDebugExt02 version 66:0 +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + SourceDebugExtension { + ""; + } +} // end Class SourceDebugExt02 compiled from "SourceDebugExt02.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt03.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt03.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt03.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/SourceDebugExtension/SourceDebugExt03.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025; Oracle and/or its affiliates. All rights reserved. + */ +package javasoft/sqe/tests/api/java/lang/classfile/resources/jasm/atr; + +public super class SourceDebugExt03 version 66:0 +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + SourceDebugExtension { + 0x01; 0x02; 0x03; 0x04; 0x05; 0x06; 0x07; 0x08; 0x09; 0x0A; 0x00; 0x0B; 0x0C; 0x0D; 0x0E; 0x0F; + } +} // end Class SourceDebugExt03 compiled from "SourceDebugExt03.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,759 @@ +package org/openjdk/asmtools/attribute/StackMapTable/data; + +public super class #10 /* StackMapData */ version 69:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = String #8; // "string" + const #8 = Utf8 "string"; + const #9 = Field #10.#11; // StackMapData.fldS:"Ljava/lang/String;" + const #10 = class #12; // StackMapData + const #11 = NameAndType #13:#14; // fldS:"Ljava/lang/String;" + const #12 = Utf8 "org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData"; + const #13 = Utf8 "fldS"; + const #14 = Utf8 "Ljava/lang/String;"; + const #15 = Field #10.#16; // StackMapData.fldFS:"Ljava/lang/String;" + const #16 = NameAndType #17:#14; // fldFS:"Ljava/lang/String;" + const #17 = Utf8 "fldFS"; + const #18 = Method #2.#19; // java/lang/Object.toString:"()Ljava/lang/String;" + const #19 = NameAndType #20:#21; // toString:"()Ljava/lang/String;" + const #20 = Utf8 "toString"; + const #21 = Utf8 "()Ljava/lang/String;"; + const #22 = class #23; // java/lang/ArithmeticException + const #23 = Utf8 "java/lang/ArithmeticException"; + const #24 = Field #25.#26; // java/lang/System.out:"Ljava/io/PrintStream;" + const #25 = class #27; // java/lang/System + const #26 = NameAndType #28:#29; // out:"Ljava/io/PrintStream;" + const #27 = Utf8 "java/lang/System"; + const #28 = Utf8 "out"; + const #29 = Utf8 "Ljava/io/PrintStream;"; + const #30 = String #31; // "frame" + const #31 = Utf8 "frame"; + const #32 = Method #33.#34; // java/io/PrintStream.println:"(Ljava/lang/String;)V" + const #33 = class #35; // java/io/PrintStream + const #34 = NameAndType #36:#37; // println:"(Ljava/lang/String;)V" + const #35 = Utf8 "java/io/PrintStream"; + const #36 = Utf8 "println"; + const #37 = Utf8 "(Ljava/lang/String;)V"; + const #38 = float 100.0f; + const #39 = Method #40.#41; // java/lang/Math.round:"(F)I" + const #40 = class #42; // java/lang/Math + const #41 = NameAndType #43:#44; // round:"(F)I" + const #42 = Utf8 "java/lang/Math"; + const #43 = Utf8 "round"; + const #44 = Utf8 "(F)I"; + const #45 = InvokeDynamic 0:#46; // #0:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #46 = NameAndType #47:#48; // makeConcatWithConstants:"(I)Ljava/lang/String;" + const #47 = Utf8 "makeConcatWithConstants"; + const #48 = Utf8 "(I)Ljava/lang/String;"; + const #49 = float 3.14f; + const #50 = InvokeDynamic 1:#46; // #1:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #51 = float 10.0f; + const #52 = float 110.0f; + const #53 = double 100.0d; + const #55 = Method #40.#56; // java/lang/Math.round:"(D)J" + const #56 = NameAndType #43:#57; // round:"(D)J" + const #57 = Utf8 "(D)J"; + const #58 = InvokeDynamic 2:#59; // #2:makeConcatWithConstants:"(J)Ljava/lang/String;" + const #59 = NameAndType #47:#60; // makeConcatWithConstants:"(J)Ljava/lang/String;" + const #60 = Utf8 "(J)Ljava/lang/String;"; + const #61 = double 99.99d; + const #63 = InvokeDynamic 3:#64; // #3:makeConcatWithConstants:"(D)Ljava/lang/String;" + const #64 = NameAndType #47:#65; // makeConcatWithConstants:"(D)Ljava/lang/String;" + const #65 = Utf8 "(D)Ljava/lang/String;"; + const #66 = String #67; // "chop_frame" + const #67 = Utf8 "chop_frame"; + const #68 = String #69; // "_frame_" + const #69 = Utf8 "_frame_"; + const #70 = Method #33.#71; // java/io/PrintStream.println:"(D)V" + const #71 = NameAndType #36:#72; // println:"(D)V" + const #72 = Utf8 "(D)V"; + const #73 = String #74; // "n_frame" + const #74 = Utf8 "n_frame"; + const #75 = InvokeDynamic 4:#76; // #4:makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #76 = NameAndType #47:#77; // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #77 = Utf8 "(Ljava/lang/String;CI)Ljava/lang/String;"; + const #78 = class #79; // java/lang/String + const #79 = Utf8 "java/lang/String"; + const #80 = Method #2.#81; // java/lang/Object.hashCode:"()I" + const #81 = NameAndType #82:#83; // hashCode:"()I" + const #82 = Utf8 "hashCode"; + const #83 = Utf8 "()I"; + const #84 = class #85; // java/lang/RuntimeException + const #85 = Utf8 "java/lang/RuntimeException"; + const #86 = String #87; // "Test exception" + const #87 = Utf8 "Test exception"; + const #88 = Method #84.#89; // java/lang/RuntimeException."":"(Ljava/lang/String;)V" + const #89 = NameAndType #5:#37; // "":"(Ljava/lang/String;)V" + const #90 = String #91; // "positive" + const #91 = Utf8 "positive"; + const #92 = String #93; // "non-positive" + const #93 = Utf8 "non-positive"; + const #94 = String #95; // "Computing result" + const #95 = Utf8 "Computing result"; + const #96 = Method #10.#3; // StackMapData."":"()V" + const #97 = Method #10.#98; // StackMapData.generateFrames:"(I)V" + const #98 = NameAndType #99:#100; // generateFrames:"(I)V" + const #99 = Utf8 "generateFrames"; + const #100 = Utf8 "(I)V"; + const #101 = String #102; // "test" + const #102 = Utf8 "test"; + const #103 = Method #10.#104; // StackMapData.complexMethod:"(ILjava/lang/Object;)I" + const #104 = NameAndType #105:#106; // complexMethod:"(ILjava/lang/Object;)I" + const #105 = Utf8 "complexMethod"; + const #106 = Utf8 "(ILjava/lang/Object;)I"; + const #107 = Method #10.#108; // StackMapData.generateFullFrame:"(I)I" + const #108 = NameAndType #109:#110; // generateFullFrame:"(I)I" + const #109 = Utf8 "generateFullFrame"; + const #110 = Utf8 "(I)I"; + const #111 = Field #10.#112; // StackMapData.fldL:"J" + const #112 = NameAndType #113:#114; // fldL:"J" + const #113 = Utf8 "fldL"; + const #114 = Utf8 "J"; + const #115 = Utf8 "fldI"; + const #116 = Utf8 "I"; + const #117 = Utf8 "ConstantValue"; + const #118 = int 0; + const #119 = Utf8 "Code"; + const #120 = Utf8 "StackMapTable"; + const #121 = class #122; // java/lang/Throwable + const #122 = Utf8 "java/lang/Throwable"; + const #123 = Utf8 "main"; + const #124 = Utf8 "([Ljava/lang/String;)V"; + const #125 = Utf8 ""; + const #126 = Utf8 "BootstrapMethods"; + const #127 = String #128; // "item_frame\u0001" + const #128 = Utf8 "item_frame\u0001"; + const #129 = String #130; // "item_frame_\u0001" + const #130 = Utf8 "item_frame_\u0001"; + const #131 = String #132; // "_frame: \u0001" + const #132 = Utf8 "_frame: \u0001"; + const #133 = String #134; // "Before chop_frame: \u0001" + const #134 = Utf8 "Before chop_frame: \u0001"; + const #135 = String #136; // "\u0001: \u0001\u0001" + const #136 = Utf8 "\u0001: \u0001\u0001"; + const #137 = MethodHandle 6:#138; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #138 = Method #139.#140; // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #139 = class #141; // java/lang/invoke/StringConcatFactory + const #140 = NameAndType #47:#142; // makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #141 = Utf8 "java/lang/invoke/StringConcatFactory"; + const #142 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + const #143 = Utf8 "InnerClasses"; + const #144 = class #145; // java/lang/invoke/MethodHandles$Lookup + const #145 = Utf8 "java/lang/invoke/MethodHandles$Lookup"; + const #146 = class #147; // java/lang/invoke/MethodHandles + const #147 = Utf8 "java/lang/invoke/MethodHandles"; + const #148 = Utf8 "Lookup"; + + static final Field #115:#116 = #118; // fldI:I = int 0 + static Field #113:#114; // fldL:J + protected Field #13:#14; // fldS:"Ljava/lang/String;" + public final Field #17:#14 = #7; // fldFS:"Ljava/lang/String;" = String "string" + + public Method #5:#6 // "":"()V" + stack 2 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: aload_0; + 5: ldc #7; // String "string" + 7: putfield #9; // Field fldS:"Ljava/lang/String;" + 10: aload_0; + 11: ldc #7; // String "string" + 13: putfield #15; // Field fldFS:"Ljava/lang/String;" + 16: return; + } + + public Method #99:#100 // generateFrames:"(I)V" + stack 5 locals 10 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + try T0, T1; + 4: iconst_1; + 5: iload_2; + 6: idiv; + 7: istore_2; + endtry T0,T1; + 8: aload_3; + 9: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 12: pop; + 13: goto 44; + catch T0 #22; // java/lang/ArithmeticException + try T2; + 16: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16; // fldFS:"Ljava/lang/String;"; + frame_type full; // frame_type 255 + locals_map #10, 1, 1, #2; // class StackMapData, int, int, class java/lang/Object; + stack_map #22; // class java/lang/ArithmeticException; + astore 4; + 18: new #2; // class java/lang/Object + 21: dup; + 22: invokespecial #1; // Method java/lang/Object."":"()V" + 25: astore_3; + endtry T2; + 26: aload_3; + 27: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 30: pop; + 31: goto 44; + catch T1 #0; // any + catch T2 #0; // any + catch T3 #0; // any + try T3; + 34: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16; // fldFS:"Ljava/lang/String;"; + frame_type stack1; // frame_type 81 + stack_map #121; // class java/lang/Throwable; + astore 5; + endtry T3; + 36: aload_3; + 37: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 40: pop; + 41: aload 5; + 43: athrow; + 44: stack_frame_type early_larval; // frame_type 246 + unset_fields #26, // out:"Ljava/io/PrintStream;", + #16; // fldFS:"Ljava/lang/String;"; + frame_type same; // frame_type 9 + iload_2; + 45: ifne 50; + 48: aconst_null; + 49: astore_3; + 50: stack_frame_type same; // frame_type 5 + iload_2; + 51: lookupswitch { // 2 + 1: 76; + 2: 87; + default: 87 }; + 76: stack_frame_type same; // frame_type 25 + new #2; // class java/lang/Object + 79: dup; + 80: invokespecial #1; // Method java/lang/Object."":"()V" + 83: astore_3; + 84: goto 87; + 87: stack_frame_type same; // frame_type 10 + iload_1; + 88: ifne 99; + 91: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 94: ldc #30; // String "frame" + 96: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 99: stack_frame_type same; // frame_type 11 + iload_1; + 100: iconst_1; + 101: if_icmpne 127; + 104: bipush 42; + 106: istore 4; + 108: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 111: iload 4; + 113: ldc #38; // float 100.0f + 115: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 118: imul; + 119: invokedynamic #45; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "item_frame\u0001" + // } + 124: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 127: stack_frame_type same; // frame_type 27 + iload_1; + 128: iconst_2; + 129: if_icmpne 184; + 132: iconst_0; + 133: istore 4; + 135: iconst_0; + 136: istore 5; + 138: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type append; // frame_type 253 + locals_map 1, 1; // int, int; + iload 5; + 140: sipush 3000; + 143: if_icmpge 171; + 146: ldc #49; // float 3.14f + 148: fstore 6; + 150: iload 4; + 152: fload 6; + 154: ldc #38; // float 100.0f + 156: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 159: i2f; + 160: fmul; + 161: f2i; + 162: iadd; + 163: istore 4; + 165: iinc 5, 1; + 168: goto 138; + 171: stack_frame_type chop1; // frame_type 250 + getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 174: iload 4; + 176: invokedynamic #50; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "item_frame_\u0001" + // } + 181: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 184: stack_frame_type chop1; // frame_type 250 + ldc #51; // float 10.0f + 186: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 189: istore 4; + 191: iload_1; + 192: iconst_3; + 193: if_icmpne 232; + 196: ldc #52; // float 110.0f + 198: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 201: istore 5; + 203: ldc2_w #53; // double 100.0d + 206: invokestatic #55; // Method java/lang/Math.round:"(D)J" + 209: lstore 6; + 211: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 214: iload 5; + 216: i2l; + 217: lload 6; + 219: ladd; + 220: iload 4; + 222: i2l; + 223: lmul; + 224: invokedynamic #58; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(J)Ljava/lang/String;" { + // String "_frame: \u0001" + // } + 229: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 232: stack_frame_type append; // frame_type 252 + locals_map 1; // int; + iload_1; + 233: iconst_4; + 234: if_icmpne 273; + 237: bipush 50; + 239: iload 4; + 241: imul; + 242: istore 5; + 244: ldc2_w #61; // double 99.99d + 247: iload 4; + 249: i2d; + 250: dmul; + 251: dstore 6; + 253: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 256: iload 5; + 258: i2d; + 259: dload 6; + 261: dadd; + 262: invokedynamic #63; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(D)Ljava/lang/String;" { + // String "Before chop_frame: \u0001" + // } + 267: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 270: goto 281; + 273: stack_frame_type same; // frame_type 40 + getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 276: ldc #66; // String "chop_frame" + 278: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 281: stack_frame_type same; // frame_type 7 + iload_1; + 282: iconst_5; + 283: if_icmpne 379; + 286: iconst_0; + 287: istore 5; + 289: iconst_0; + 290: istore 6; + 292: stack_frame_type append; // frame_type 253 + locals_map 1, 1; // int, int; + iload 6; + 294: sipush 2500; + 297: if_icmpge 326; + 300: ldc #49; // float 3.14f + 302: fstore 7; + 304: iload 5; + 306: fload 7; + 308: iload 6; + 310: i2f; + 311: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 314: i2f; + 315: fmul; + 316: f2i; + 317: iadd; + 318: istore 5; + 320: iinc 6, 1; + 323: goto 292; + 326: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type chop1; // frame_type 250 + iload 5; + 328: bipush 100; + 330: if_icmple 344; + 333: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 336: ldc #68; // String "_frame_" + 338: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 341: goto 379; + 344: stack_frame_type same; // frame_type 17 + iload 5; + 346: bipush 50; + 348: if_icmpge 379; + 351: bipush 50; + 353: iload 4; + 355: imul; + 356: istore 6; + 358: ldc2_w #61; // double 99.99d + 361: iload 4; + 363: i2d; + 364: dmul; + 365: dstore 7; + 367: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 370: iload 6; + 372: i2d; + 373: dload 7; + 375: dadd; + 376: invokevirtual #70; // Method java/io/PrintStream.println:"(D)V" + 379: stack_frame_type chop1; // frame_type 250 + iload_1; + 380: bipush 6; + 382: if_icmpne 414; + 385: ldc #73; // String "n_frame" + 387: astore 5; + 389: bipush 70; + 391: istore 6; + 393: bipush 100; + 395: istore 7; + 397: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 400: aload 5; + 402: iload 6; + 404: iload 7; + 406: invokedynamic #75; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 411: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 414: stack_frame_type same; // frame_type 34 + iconst_0; + 415: istore 5; + 417: aconst_null; + 418: astore 6; + try T4, T5; + 420: iconst_1; + 421: iload 5; + 423: idiv; + 424: istore 5; + endtry T4,T5; + 426: aload 6; + 428: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 431: pop; + 432: goto 466; + catch T4 #22; // java/lang/ArithmeticException + try T6; + 435: stack_frame_type full; // frame_type 255 + locals_map #10, 1, 1, #2, 1, 1, #2; // class StackMapData, int, int, class java/lang/Object, int, int, class java/lang/Object; + stack_map #22; // class java/lang/ArithmeticException; + astore 7; + 437: new #2; // class java/lang/Object + 440: dup; + 441: invokespecial #1; // Method java/lang/Object."":"()V" + 444: astore 6; + endtry T6; + 446: aload 6; + 448: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 451: pop; + 452: goto 466; + catch T5 #0; // any + catch T6 #0; // any + catch T7 #0; // any + try T7; + 455: stack_frame_type stack1; // frame_type 83 + stack_map #121; // class java/lang/Throwable; + astore 9; + endtry T7; + 457: aload 6; + 459: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 462: pop; + 463: aload 9; + 465: athrow; + 466: stack_frame_type same; // frame_type 10 + iload 5; + 468: ifne 474; + 471: aconst_null; + 472: astore 6; + 474: stack_frame_type same; // frame_type 7 + iload_2; + 475: lookupswitch { // 2 + 1: 500; + 2: 512; + default: 512 }; + 500: stack_frame_type same; // frame_type 25 + new #2; // class java/lang/Object + 503: dup; + 504: invokespecial #1; // Method java/lang/Object."":"()V" + 507: astore 6; + 509: goto 512; + 512: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type same; // frame_type 11 + return; + } + + public Method #105:#106 // complexMethod:"(ILjava/lang/Object;)I" + stack 3 locals 7 + { + 0: iconst_0; + 1: istore_3; + 2: iconst_1; + 3: istore 4; + 5: aconst_null; + 6: astore 5; + try T0; + 8: iload_1; + 9: ifle 47; + 12: iload_1; + 13: iconst_1; + 14: iadd; + 15: istore_3; + 16: aload_2; + 17: instanceof #78; // class java/lang/String + 20: ifeq 39; + 23: aload_2; + 24: checkcast #78; // class java/lang/String + 27: astore 5; + 29: aload 5; + 31: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 34: istore 4; + 36: iload 4; + endtry T0; + 38: ireturn; + try T1; + 39: stack_frame_type append; // frame_type 254 + locals_map 1, 1, #2; // int, int, class java/lang/Object; + iload_3; + 40: iconst_2; + 41: imul; + 42: istore 4; + 44: goto 104; + 47: stack_frame_type same; // frame_type 7 + iload_1; + 48: iconst_m1; + 49: if_icmpne 70; + 52: iload_1; + 53: ineg; + 54: istore_3; + 55: iload_3; + 56: iconst_3; + 57: iadd; + 58: istore 4; + 60: new #84; // class java/lang/RuntimeException + 63: dup; + 64: ldc #86; // String "Test exception" + 66: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 69: athrow; + 70: stack_frame_type same; // frame_type 22 + iconst_0; + 71: istore 6; + 73: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type append; // frame_type 252 + locals_map 1; // int; + iload 6; + 75: iconst_2; + 76: if_icmpge 104; + 79: iload_3; + 80: iload 6; + 82: iadd; + 83: istore_3; + 84: iload_3; + 85: iconst_1; + 86: if_icmple 98; + 89: iload_3; + 90: iload 6; + 92: isub; + 93: istore 4; + 95: goto 104; + 98: stack_frame_type same; // frame_type 24 + iinc 6, 1; + 101: goto 73; + endtry T1; + 104: stack_frame_type chop1; // frame_type 250 + goto 118; + catch T0 #84; // java/lang/RuntimeException + catch T1 #84; // java/lang/RuntimeException + 107: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type stack1; // frame_type 66 + stack_map #84; // class java/lang/RuntimeException; + astore 6; + 109: aload 6; + 111: astore 5; + 113: iload_3; + 114: iconst_5; + 115: iadd; + 116: istore 4; + 118: stack_frame_type same; // frame_type 10 + iload_3; + 119: iload 4; + 121: iadd; + 122: ireturn; + } + + public Method #109:#110 // generateFullFrame:"(I)I" + stack 3 locals 6 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + 4: iconst_0; + 5: istore 4; + try T0; + 7: iload_1; + 8: ifle 25; + 11: ldc #90; // String "positive" + 13: astore_3; + 14: iconst_1; + 15: istore 4; + 17: aload_3; + 18: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 21: istore_2; + 22: goto 39; + 25: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type append; // frame_type 254 + locals_map 1, #2, 1; // int, class java/lang/Object, int; + iload_1; + 26: iconst_2; + 27: imul; + 28: istore_2; + 29: new #84; // class java/lang/RuntimeException + 32: dup; + 33: ldc #92; // String "non-positive" + 35: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 38: athrow; + endtry T0; + 39: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26; // out:"Ljava/io/PrintStream;"; + frame_type same; // frame_type 13 + goto 53; + catch T0 #84; // java/lang/RuntimeException + 42: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16; // fldFS:"Ljava/lang/String;"; + frame_type stack1; // frame_type 66 + stack_map #84; // class java/lang/RuntimeException; + astore 5; + 44: aload 5; + 46: astore_3; + 47: iconst_0; + 48: istore 4; + 50: iload_1; + 51: ineg; + 52: istore_2; + 53: stack_frame_type early_larval; // frame_type 246 + unset_fields #11; // fldS:"Ljava/lang/String;"; + frame_type same; // frame_type 10 + iload 4; + 55: ifeq 62; + 58: iload_2; + 59: iconst_1; + 60: iadd; + 61: ireturn; + 62: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type same; // frame_type 8 + getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 65: ldc #94; // String "Computing result" + 67: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 70: iload_2; + 71: ireturn; + } + + public static Method #123:#124 // main:"([Ljava/lang/String;)V" + stack 3 locals 3 + { + 0: new #10; // class StackMapData + 3: dup; + 4: invokespecial #96; // Method "":"()V" + 7: astore_1; + 8: iconst_0; + 9: istore_2; + 10: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type append; // frame_type 253 + locals_map #10, 1; // class StackMapData, int; + iload_2; + 11: bipush 6; + 13: if_icmpgt 27; + 16: aload_1; + 17: iload_2; + 18: invokevirtual #97; // Method generateFrames:"(I)V" + 21: iinc 2, 1; + 24: goto 10; + 27: stack_frame_type chop1; // frame_type 250 + aload_1; + 28: iconst_0; + 29: ldc #101; // String "test" + 31: invokevirtual #103; // Method complexMethod:"(ILjava/lang/Object;)I" + 34: pop; + 35: aload_1; + 36: bipush 23; + 38: invokevirtual #107; // Method generateFullFrame:"(I)I" + 41: pop; + 42: return; + } + + static Method #125:#6 // "":"()V" + stack 2 locals 0 + { + 0: lconst_1; + 1: putstatic #111; // Field fldL:"J" + 4: return; + } + + InnerClass public static final #148 = #144 of #146; // Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #127 // String "item_frame\u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #129 // String "item_frame_\u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #131 // String "_frame: \u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #133 // String "Before chop_frame: \u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #135 // String "\u0001: \u0001\u0001" + } +} // end Class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,520 @@ +class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData { + 0xCAFEBABE; + 0; // minor version + 69; // version + [149] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + Class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + String #8; // #7 at 0x39 + Utf8 "string"; // #8 at 0x3C + Field #10 #11; // #9 at 0x45 + Class #12; // #10 at 0x4A + NameAndType #13 #14; // #11 at 0x4D + Utf8 "org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData"; // #12 at 0x52 + Utf8 "fldS"; // #13 at 0x93 + Utf8 "Ljava/lang/String;"; // #14 at 0x9A + Field #10 #16; // #15 at 0xAF + NameAndType #17 #14; // #16 at 0xB4 + Utf8 "fldFS"; // #17 at 0xB9 + Method #2 #19; // #18 at 0xC1 + NameAndType #20 #21; // #19 at 0xC6 + Utf8 "toString"; // #20 at 0xCB + Utf8 "()Ljava/lang/String;"; // #21 at 0xD6 + Class #23; // #22 at 0xED + Utf8 "java/lang/ArithmeticException"; // #23 at 0xF0 + Field #25 #26; // #24 at 0x0110 + Class #27; // #25 at 0x0115 + NameAndType #28 #29; // #26 at 0x0118 + Utf8 "java/lang/System"; // #27 at 0x011D + Utf8 "out"; // #28 at 0x0130 + Utf8 "Ljava/io/PrintStream;"; // #29 at 0x0136 + String #31; // #30 at 0x014E + Utf8 "frame"; // #31 at 0x0151 + Method #33 #34; // #32 at 0x0159 + Class #35; // #33 at 0x015E + NameAndType #36 #37; // #34 at 0x0161 + Utf8 "java/io/PrintStream"; // #35 at 0x0166 + Utf8 "println"; // #36 at 0x017C + Utf8 "(Ljava/lang/String;)V"; // #37 at 0x0186 + Float 0x42C80000; // #38 at 0x019E + Method #40 #41; // #39 at 0x01A3 + Class #42; // #40 at 0x01A8 + NameAndType #43 #44; // #41 at 0x01AB + Utf8 "java/lang/Math"; // #42 at 0x01B0 + Utf8 "round"; // #43 at 0x01C1 + Utf8 "(F)I"; // #44 at 0x01C9 + InvokeDynamic 0s #46; // #45 at 0x01D0 + NameAndType #47 #48; // #46 at 0x01D5 + Utf8 "makeConcatWithConstants"; // #47 at 0x01DA + Utf8 "(I)Ljava/lang/String;"; // #48 at 0x01F4 + Float 0x4048F5C3; // #49 at 0x020C + InvokeDynamic 1s #46; // #50 at 0x0211 + Float 0x41200000; // #51 at 0x0216 + Float 0x42DC0000; // #52 at 0x021B + Double 0x4059000000000000;; // #53 at 0x0220 + Method #40 #56; // #55 at 0x0229 + NameAndType #43 #57; // #56 at 0x022E + Utf8 "(D)J"; // #57 at 0x0233 + InvokeDynamic 2s #59; // #58 at 0x023A + NameAndType #47 #60; // #59 at 0x023F + Utf8 "(J)Ljava/lang/String;"; // #60 at 0x0244 + Double 0x4058FF5C28F5C28F;; // #61 at 0x025C + InvokeDynamic 3s #64; // #63 at 0x0265 + NameAndType #47 #65; // #64 at 0x026A + Utf8 "(D)Ljava/lang/String;"; // #65 at 0x026F + String #67; // #66 at 0x0287 + Utf8 "chop_frame"; // #67 at 0x028A + String #69; // #68 at 0x0297 + Utf8 "_frame_"; // #69 at 0x029A + Method #33 #71; // #70 at 0x02A4 + NameAndType #36 #72; // #71 at 0x02A9 + Utf8 "(D)V"; // #72 at 0x02AE + String #74; // #73 at 0x02B5 + Utf8 "n_frame"; // #74 at 0x02B8 + InvokeDynamic 4s #76; // #75 at 0x02C2 + NameAndType #47 #77; // #76 at 0x02C7 + Utf8 "(Ljava/lang/String;CI)Ljava/lang/String;"; // #77 at 0x02CC + Class #79; // #78 at 0x02F7 + Utf8 "java/lang/String"; // #79 at 0x02FA + Method #2 #81; // #80 at 0x030D + NameAndType #82 #83; // #81 at 0x0312 + Utf8 "hashCode"; // #82 at 0x0317 + Utf8 "()I"; // #83 at 0x0322 + Class #85; // #84 at 0x0328 + Utf8 "java/lang/RuntimeException"; // #85 at 0x032B + String #87; // #86 at 0x0348 + Utf8 "Test exception"; // #87 at 0x034B + Method #84 #89; // #88 at 0x035C + NameAndType #5 #37; // #89 at 0x0361 + String #91; // #90 at 0x0366 + Utf8 "positive"; // #91 at 0x0369 + String #93; // #92 at 0x0374 + Utf8 "non-positive"; // #93 at 0x0377 + String #95; // #94 at 0x0386 + Utf8 "Computing result"; // #95 at 0x0389 + Method #10 #3; // #96 at 0x039C + Method #10 #98; // #97 at 0x03A1 + NameAndType #99 #100; // #98 at 0x03A6 + Utf8 "generateFrames"; // #99 at 0x03AB + Utf8 "(I)V"; // #100 at 0x03BC + String #102; // #101 at 0x03C3 + Utf8 "test"; // #102 at 0x03C6 + Method #10 #104; // #103 at 0x03CD + NameAndType #105 #106; // #104 at 0x03D2 + Utf8 "complexMethod"; // #105 at 0x03D7 + Utf8 "(ILjava/lang/Object;)I"; // #106 at 0x03E7 + Method #10 #108; // #107 at 0x0400 + NameAndType #109 #110; // #108 at 0x0405 + Utf8 "generateFullFrame"; // #109 at 0x040A + Utf8 "(I)I"; // #110 at 0x041E + Field #10 #112; // #111 at 0x0425 + NameAndType #113 #114; // #112 at 0x042A + Utf8 "fldL"; // #113 at 0x042F + Utf8 "J"; // #114 at 0x0436 + Utf8 "fldI"; // #115 at 0x043A + Utf8 "I"; // #116 at 0x0441 + Utf8 "ConstantValue"; // #117 at 0x0445 + Integer 0x00000000; // #118 at 0x0455 + Utf8 "Code"; // #119 at 0x045A + Utf8 "StackMapTable"; // #120 at 0x0461 + Class #122; // #121 at 0x0471 + Utf8 "java/lang/Throwable"; // #122 at 0x0474 + Utf8 "main"; // #123 at 0x048A + Utf8 "([Ljava/lang/String;)V"; // #124 at 0x0491 + Utf8 ""; // #125 at 0x04AA + Utf8 "BootstrapMethods"; // #126 at 0x04B5 + String #128; // #127 at 0x04C8 + Utf8 "item_frame\u0001"; // #128 at 0x04CB + String #130; // #129 at 0x04D9 + Utf8 "item_frame_\u0001"; // #130 at 0x04DC + String #132; // #131 at 0x04EB + Utf8 "_frame: \u0001"; // #132 at 0x04EE + String #134; // #133 at 0x04FA + Utf8 "Before chop_frame: \u0001"; // #134 at 0x04FD + String #136; // #135 at 0x0514 + Utf8 "\u0001: \u0001\u0001"; // #136 at 0x0517 + MethodHandle 6b #138; // #137 at 0x051F + Method #139 #140; // #138 at 0x0523 + Class #141; // #139 at 0x0528 + NameAndType #47 #142; // #140 at 0x052B + Utf8 "java/lang/invoke/StringConcatFactory"; // #141 at 0x0530 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #142 at 0x0557 + Utf8 "InnerClasses"; // #143 at 0x05F2 + Class #145; // #144 at 0x0601 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #145 at 0x0604 + Class #147; // #146 at 0x062C + Utf8 "java/lang/invoke/MethodHandles"; // #147 at 0x062F + Utf8 "Lookup"; // #148 at 0x0650 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #10; // this_cpx + #2; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [4] { // Fields + { // field at 0x0663 + 0x0018; // access + #115; // name_index : fldI + #116; // descriptor_index : I + [1] { // Attributes + Attr(#117, 2) { // ConstantValue at 0x066B + #118; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field at 0x0673 + 0x0008; // access + #113; // name_index : fldL + #114; // descriptor_index : J + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x067B + 0x0004; // access + #13; // name_index : fldS + #14; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x0683 + 0x0011; // access + #17; // name_index : fldFS + #14; // descriptor_index : Ljava/lang/String; + [1] { // Attributes + Attr(#117, 2) { // ConstantValue at 0x068B + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [6] { // Methods + { // method at 0x0695 + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#119, 29) { // Code at 0x069D + 2; // max_stack + 1; // max_locals + Bytes[17]{ + 0x2A 0xB7 0x00 0x01 0x2A 0x12 0x07 0xB5 0x00 0x09 0x2A 0x12; + 0x07 0xB5 0x00 0x0F 0xB1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x06C0 + 0x0001; // access + #99; // name_index : generateFrames + #100; // descriptor_index : (I)V + [1] { // Attributes + Attr(#119, 724) { // Code at 0x06C8 + 5; // max_stack + 10; // max_locals + Bytes[513]{ + 0x03 0x3D 0x01 0x4E 0x04 0x1C 0x6C 0x3D 0x2D 0xB6 0x00 0x12; + 0x57 0xA7 0x00 0x1F 0x3A 0x04 0xBB 0x00 0x02 0x59 0xB7 0x00; + 0x01 0x4E 0x2D 0xB6 0x00 0x12 0x57 0xA7 0x00 0x0D 0x3A 0x05; + 0x2D 0xB6 0x00 0x12 0x57 0x19 0x05 0xBF 0x1C 0x9A 0x00 0x05; + 0x01 0x4E 0x1C 0xAB 0x00 0x00 0x00 0x24 0x00 0x00 0x00 0x02; + 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x19 0x00 0x00 0x00 0x02; + 0x00 0x00 0x00 0x24 0xBB 0x00 0x02 0x59 0xB7 0x00 0x01 0x4E; + 0xA7 0x00 0x03 0x1B 0x9A 0x00 0x0B 0xB2 0x00 0x18 0x12 0x1E; + 0xB6 0x00 0x20 0x1B 0x04 0xA0 0x00 0x1A 0x10 0x2A 0x36 0x04; + 0xB2 0x00 0x18 0x15 0x04 0x12 0x26 0xB8 0x00 0x27 0x68 0xBA; + 0x00 0x2D 0x00 0x00 0xB6 0x00 0x20 0x1B 0x05 0xA0 0x00 0x37; + 0x03 0x36 0x04 0x03 0x36 0x05 0x15 0x05 0x11 0x0B 0xB8 0xA2; + 0x00 0x1C 0x12 0x31 0x38 0x06 0x15 0x04 0x17 0x06 0x12 0x26; + 0xB8 0x00 0x27 0x86 0x6A 0x8B 0x60 0x36 0x04 0x84 0x05 0x01; + 0xA7 0xFF 0xE2 0xB2 0x00 0x18 0x15 0x04 0xBA 0x00 0x32 0x00; + 0x00 0xB6 0x00 0x20 0x12 0x33 0xB8 0x00 0x27 0x36 0x04 0x1B; + 0x06 0xA0 0x00 0x27 0x12 0x34 0xB8 0x00 0x27 0x36 0x05 0x14; + 0x00 0x35 0xB8 0x00 0x37 0x37 0x06 0xB2 0x00 0x18 0x15 0x05; + 0x85 0x16 0x06 0x61 0x15 0x04 0x85 0x69 0xBA 0x00 0x3A 0x00; + 0x00 0xB6 0x00 0x20 0x1B 0x07 0xA0 0x00 0x27 0x10 0x32 0x15; + 0x04 0x68 0x36 0x05 0x14 0x00 0x3D 0x15 0x04 0x87 0x6B 0x39; + 0x06 0xB2 0x00 0x18 0x15 0x05 0x87 0x18 0x06 0x63 0xBA 0x00; + 0x3F 0x00 0x00 0xB6 0x00 0x20 0xA7 0x00 0x0B 0xB2 0x00 0x18; + 0x12 0x42 0xB6 0x00 0x20 0x1B 0x08 0xA0 0x00 0x60 0x03 0x36; + 0x05 0x03 0x36 0x06 0x15 0x06 0x11 0x09 0xC4 0xA2 0x00 0x1D; + 0x12 0x31 0x38 0x07 0x15 0x05 0x17 0x07 0x15 0x06 0x86 0xB8; + 0x00 0x27 0x86 0x6A 0x8B 0x60 0x36 0x05 0x84 0x06 0x01 0xA7; + 0xFF 0xE1 0x15 0x05 0x10 0x64 0xA4 0x00 0x0E 0xB2 0x00 0x18; + 0x12 0x44 0xB6 0x00 0x20 0xA7 0x00 0x26 0x15 0x05 0x10 0x32; + 0xA2 0x00 0x1F 0x10 0x32 0x15 0x04 0x68 0x36 0x06 0x14 0x00; + 0x3D 0x15 0x04 0x87 0x6B 0x39 0x07 0xB2 0x00 0x18 0x15 0x06; + 0x87 0x18 0x07 0x63 0xB6 0x00 0x46 0x1B 0x10 0x06 0xA0 0x00; + 0x20 0x12 0x49 0x3A 0x05 0x10 0x46 0x36 0x06 0x10 0x64 0x36; + 0x07 0xB2 0x00 0x18 0x19 0x05 0x15 0x06 0x15 0x07 0xBA 0x00; + 0x4B 0x00 0x00 0xB6 0x00 0x20 0x03 0x36 0x05 0x01 0x3A 0x06; + 0x04 0x15 0x05 0x6C 0x36 0x05 0x19 0x06 0xB6 0x00 0x12 0x57; + 0xA7 0x00 0x22 0x3A 0x07 0xBB 0x00 0x02 0x59 0xB7 0x00 0x01; + 0x3A 0x06 0x19 0x06 0xB6 0x00 0x12 0x57 0xA7 0x00 0x0E 0x3A; + 0x09 0x19 0x06 0xB6 0x00 0x12 0x57 0x19 0x09 0xBF 0x15 0x05; + 0x9A 0x00 0x06 0x01 0x3A 0x06 0x1C 0xAB 0x00 0x00 0x00 0x25; + 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x19; + 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x25 0xBB 0x00 0x02 0x59; + 0xB7 0x00 0x01 0x3A 0x06 0xA7 0x00 0x03 0xB1; + } + [8] { // Traps + 4 8 16 22; // at 0x08E1 + 4 8 34 0; // at 0x08E9 + 16 26 34 0; // at 0x08F1 + 34 36 34 0; // at 0x08F9 + 420 426 435 22; // at 0x0901 + 420 426 455 0; // at 0x0909 + 435 446 455 0; // at 0x0911 + 455 457 455 0; // at 0x0919 + } // end of Traps + [1] { // Attributes + Attr(#120, 129) { // StackMapTable at 0x091B + [25] { // + 246b, [2]{#11; #16}, { // early_larval_frame + 255b, 16, [4]{7b,#10; 1b; 1b; 7b,#2}, [1]{7b,#22}; // full_frame + }; + 246b, [2]{#11; #16}, { // early_larval_frame + 81b, [1]z{7b,#121}; // same_locals_1_stack_item_frame + }; + 246b, [2]{#26; #16}, { // early_larval_frame + 9b; // same_frame + }; + 5b; // same_frame + 25b; // same_frame + 10b; // same_frame + 11b; // same_frame + 27b; // same_frame + 246b, [0]{}, { // early_larval_frame + 253b, 10, [2]z{1b; 1b}; // append_frame 2 + }; + 250b, 32; // chop_frame 1 + 250b, 12; // chop_frame 1 + 252b, 47, [1]z{1b}; // append_frame 1 + 40b; // same_frame + 7b; // same_frame + 253b, 10, [2]z{1b; 1b}; // append_frame 2 + 246b, [0]{}, { // early_larval_frame + 250b, 33; // chop_frame 1 + }; + 17b; // same_frame + 250b, 34; // chop_frame 1 + 34b; // same_frame + 255b, 20, [7]{7b,#10; 1b; 1b; 7b,#2; 1b; 1b; 7b,#2}, [1]{7b,#22}; // full_frame + 83b, [1]z{7b,#121}; // same_locals_1_stack_item_frame + 10b; // same_frame + 7b; // same_frame + 25b; // same_frame + 246b, [4]{#11; #16; #26; #112}, { // early_larval_frame + 11b; // same_frame + }; + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x09A2 + 0x0001; // access + #105; // name_index : complexMethod + #106; // descriptor_index : (ILjava/lang/Object;)I + [1] { // Attributes + Attr(#119, 204) { // Code at 0x09AA + 3; // max_stack + 7; // max_locals + Bytes[123]{ + 0x03 0x3E 0x04 0x36 0x04 0x01 0x3A 0x05 0x1B 0x9E 0x00 0x26; + 0x1B 0x04 0x60 0x3E 0x2C 0xC1 0x00 0x4E 0x99 0x00 0x13 0x2C; + 0xC0 0x00 0x4E 0x3A 0x05 0x19 0x05 0xB6 0x00 0x50 0x36 0x04; + 0x15 0x04 0xAC 0x1D 0x05 0x68 0x36 0x04 0xA7 0x00 0x3C 0x1B; + 0x02 0xA0 0x00 0x15 0x1B 0x74 0x3E 0x1D 0x06 0x60 0x36 0x04; + 0xBB 0x00 0x54 0x59 0x12 0x56 0xB7 0x00 0x58 0xBF 0x03 0x36; + 0x06 0x15 0x06 0x05 0xA2 0x00 0x1C 0x1D 0x15 0x06 0x60 0x3E; + 0x1D 0x04 0xA4 0x00 0x0C 0x1D 0x15 0x06 0x64 0x36 0x04 0xA7; + 0x00 0x09 0x84 0x06 0x01 0xA7 0xFF 0xE4 0xA7 0x00 0x0E 0x3A; + 0x06 0x19 0x06 0x3A 0x05 0x1D 0x08 0x60 0x36 0x04 0x1D 0x15; + 0x04 0x60 0xAC; + } + [2] { // Traps + 8 38 107 84; // at 0x0A3D + 39 104 107 84; // at 0x0A45 + } // end of Traps + [1] { // Attributes + Attr(#120, 47) { // StackMapTable at 0x0A47 + [8] { // + 254b, 39, [3]z{1b; 1b; 7b,#2}; // append_frame 3 + 7b; // same_frame + 22b; // same_frame + 246b, [4]{#11; #16; #26; #112}, { // early_larval_frame + 252b, 2, [1]z{1b}; // append_frame 1 + }; + 24b; // same_frame + 250b, 5; // chop_frame 1 + 246b, [4]{#11; #16; #26; #112}, { // early_larval_frame + 66b, [1]z{7b,#84}; // same_locals_1_stack_item_frame + }; + 10b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0A7C + 0x0001; // access + #109; // name_index : generateFullFrame + #110; // descriptor_index : (I)I + [1] { // Attributes + Attr(#119, 150) { // Code at 0x0A84 + 3; // max_stack + 6; // max_locals + Bytes[72]{ + 0x03 0x3D 0x01 0x4E 0x03 0x36 0x04 0x1B 0x9E 0x00 0x11 0x12; + 0x5A 0x4E 0x04 0x36 0x04 0x2D 0xB6 0x00 0x50 0x3D 0xA7 0x00; + 0x11 0x1B 0x05 0x68 0x3D 0xBB 0x00 0x54 0x59 0x12 0x5C 0xB7; + 0x00 0x58 0xBF 0xA7 0x00 0x0E 0x3A 0x05 0x19 0x05 0x4E 0x03; + 0x36 0x04 0x1B 0x74 0x3D 0x15 0x04 0x99 0x00 0x07 0x1C 0x04; + 0x60 0xAC 0xB2 0x00 0x18 0x12 0x5E 0xB6 0x00 0x20 0x1C 0xAC; + } + [1] { // Traps + 7 39 42 84; // at 0x0AE4 + } // end of Traps + [1] { // Attributes + Attr(#120, 52) { // StackMapTable at 0x0AE6 + [5] { // + 246b, [4]{#11; #16; #26; #112}, { // early_larval_frame + 254b, 25, [3]z{1b; 7b,#2; 1b}; // append_frame 3 + }; + 246b, [3]{#11; #16; #26}, { // early_larval_frame + 13b; // same_frame + }; + 246b, [2]{#11; #16}, { // early_larval_frame + 66b, [1]z{7b,#84}; // same_locals_1_stack_item_frame + }; + 246b, [1]{#11}, { // early_larval_frame + 10b; // same_frame + }; + 246b, [0]{}, { // early_larval_frame + 8b; // same_frame + }; + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0B20 + 0x0009; // access + #123; // name_index : main + #124; // descriptor_index : ([Ljava/lang/String;)V + [1] { // Attributes + Attr(#119, 76) { // Code at 0x0B28 + 3; // max_stack + 3; // max_locals + Bytes[43]{ + 0xBB 0x00 0x0A 0x59 0xB7 0x00 0x60 0x4C 0x03 0x3D 0x1C 0x10; + 0x06 0xA3 0x00 0x0E 0x2B 0x1C 0xB6 0x00 0x61 0x84 0x02 0x01; + 0xA7 0xFF 0xF2 0x2B 0x03 0x12 0x65 0xB6 0x00 0x67 0x57 0x2B; + 0x10 0x17 0xB6 0x00 0x6B 0x57 0xB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#120, 15) { // StackMapTable at 0x0B65 + [2] { // + 246b, [0]{}, { // early_larval_frame + 253b, 10, [2]z{7b,#10; 1b}; // append_frame 2 + }; + 250b, 16; // chop_frame 1 + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0B7A + 0x0008; // access + #125; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#119, 17) { // Code at 0x0B82 + 2; // max_stack + 0; // max_locals + Bytes[5]{ + 0x0A 0xB3 0x00 0x6F 0xB1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [2] { // Attributes + Attr(#126, 32) { // BootstrapMethods at 0x0B9B + [5] { // bootstrap_methods + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #127; // at 0x0BA9 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #129; // at 0x0BAF + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #131; // at 0x0BB5 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #133; // at 0x0BBB + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #135; // at 0x0BC1 + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#143, 10) { // InnerClasses at 0x0BC1 + [1] { // classes + #144 #146 #148 25; // access [ ACC_PUBLIC, ACC_STATIC, ACC_FINAL ] + } + } // end of InnerClasses + } // end of Attributes +} // end of class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.t.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.t.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.t.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.g.t.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,791 @@ +package org/openjdk/asmtools/attribute/StackMapTable/data; + +public super class #10 /* StackMapData */ version 69:0 +{ + const #1 = Methodref #2.#3; // java/lang/Object."":"()V" + const #2 = Class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = String #8; // "string" + const #8 = Utf8 "string"; + const #9 = Fieldref #10.#11; // StackMapData.fldS:"Ljava/lang/String;" + const #10 = Class #12; // StackMapData + const #11 = NameAndType #13:#14; // fldS:"Ljava/lang/String;" + const #12 = Utf8 "org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData"; + const #13 = Utf8 "fldS"; + const #14 = Utf8 "Ljava/lang/String;"; + const #15 = Fieldref #10.#16; // StackMapData.fldFS:"Ljava/lang/String;" + const #16 = NameAndType #17:#14; // fldFS:"Ljava/lang/String;" + const #17 = Utf8 "fldFS"; + const #18 = Methodref #2.#19; // java/lang/Object.toString:"()Ljava/lang/String;" + const #19 = NameAndType #20:#21; // toString:"()Ljava/lang/String;" + const #20 = Utf8 "toString"; + const #21 = Utf8 "()Ljava/lang/String;"; + const #22 = Class #23; // java/lang/ArithmeticException + const #23 = Utf8 "java/lang/ArithmeticException"; + const #24 = Fieldref #25.#26; // java/lang/System.out:"Ljava/io/PrintStream;" + const #25 = Class #27; // java/lang/System + const #26 = NameAndType #28:#29; // out:"Ljava/io/PrintStream;" + const #27 = Utf8 "java/lang/System"; + const #28 = Utf8 "out"; + const #29 = Utf8 "Ljava/io/PrintStream;"; + const #30 = String #31; // "frame" + const #31 = Utf8 "frame"; + const #32 = Methodref #33.#34; // java/io/PrintStream.println:"(Ljava/lang/String;)V" + const #33 = Class #35; // java/io/PrintStream + const #34 = NameAndType #36:#37; // println:"(Ljava/lang/String;)V" + const #35 = Utf8 "java/io/PrintStream"; + const #36 = Utf8 "println"; + const #37 = Utf8 "(Ljava/lang/String;)V"; + const #38 = Float 100.0f; + const #39 = Methodref #40.#41; // java/lang/Math.round:"(F)I" + const #40 = Class #42; // java/lang/Math + const #41 = NameAndType #43:#44; // round:"(F)I" + const #42 = Utf8 "java/lang/Math"; + const #43 = Utf8 "round"; + const #44 = Utf8 "(F)I"; + const #45 = InvokeDynamic 0:#46; // #0:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #46 = NameAndType #47:#48; // makeConcatWithConstants:"(I)Ljava/lang/String;" + const #47 = Utf8 "makeConcatWithConstants"; + const #48 = Utf8 "(I)Ljava/lang/String;"; + const #49 = Float 3.14f; + const #50 = InvokeDynamic 1:#46; // #1:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #51 = Float 10.0f; + const #52 = Float 110.0f; + const #53 = Double 100.0d; + const #55 = Methodref #40.#56; // java/lang/Math.round:"(D)J" + const #56 = NameAndType #43:#57; // round:"(D)J" + const #57 = Utf8 "(D)J"; + const #58 = InvokeDynamic 2:#59; // #2:makeConcatWithConstants:"(J)Ljava/lang/String;" + const #59 = NameAndType #47:#60; // makeConcatWithConstants:"(J)Ljava/lang/String;" + const #60 = Utf8 "(J)Ljava/lang/String;"; + const #61 = Double 99.99d; + const #63 = InvokeDynamic 3:#64; // #3:makeConcatWithConstants:"(D)Ljava/lang/String;" + const #64 = NameAndType #47:#65; // makeConcatWithConstants:"(D)Ljava/lang/String;" + const #65 = Utf8 "(D)Ljava/lang/String;"; + const #66 = String #67; // "chop_frame" + const #67 = Utf8 "chop_frame"; + const #68 = String #69; // "_frame_" + const #69 = Utf8 "_frame_"; + const #70 = Methodref #33.#71; // java/io/PrintStream.println:"(D)V" + const #71 = NameAndType #36:#72; // println:"(D)V" + const #72 = Utf8 "(D)V"; + const #73 = String #74; // "n_frame" + const #74 = Utf8 "n_frame"; + const #75 = InvokeDynamic 4:#76; // #4:makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #76 = NameAndType #47:#77; // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #77 = Utf8 "(Ljava/lang/String;CI)Ljava/lang/String;"; + const #78 = Class #79; // java/lang/String + const #79 = Utf8 "java/lang/String"; + const #80 = Methodref #2.#81; // java/lang/Object.hashCode:"()I" + const #81 = NameAndType #82:#83; // hashCode:"()I" + const #82 = Utf8 "hashCode"; + const #83 = Utf8 "()I"; + const #84 = Class #85; // java/lang/RuntimeException + const #85 = Utf8 "java/lang/RuntimeException"; + const #86 = String #87; // "Test exception" + const #87 = Utf8 "Test exception"; + const #88 = Methodref #84.#89; // java/lang/RuntimeException."":"(Ljava/lang/String;)V" + const #89 = NameAndType #5:#37; // "":"(Ljava/lang/String;)V" + const #90 = String #91; // "positive" + const #91 = Utf8 "positive"; + const #92 = String #93; // "non-positive" + const #93 = Utf8 "non-positive"; + const #94 = String #95; // "Computing result" + const #95 = Utf8 "Computing result"; + const #96 = Methodref #10.#3; // StackMapData."":"()V" + const #97 = Methodref #10.#98; // StackMapData.generateFrames:"(I)V" + const #98 = NameAndType #99:#100; // generateFrames:"(I)V" + const #99 = Utf8 "generateFrames"; + const #100 = Utf8 "(I)V"; + const #101 = String #102; // "test" + const #102 = Utf8 "test"; + const #103 = Methodref #10.#104; // StackMapData.complexMethod:"(ILjava/lang/Object;)I" + const #104 = NameAndType #105:#106; // complexMethod:"(ILjava/lang/Object;)I" + const #105 = Utf8 "complexMethod"; + const #106 = Utf8 "(ILjava/lang/Object;)I"; + const #107 = Methodref #10.#108; // StackMapData.generateFullFrame:"(I)I" + const #108 = NameAndType #109:#110; // generateFullFrame:"(I)I" + const #109 = Utf8 "generateFullFrame"; + const #110 = Utf8 "(I)I"; + const #111 = Fieldref #10.#112; // StackMapData.fldL:"J" + const #112 = NameAndType #113:#114; // fldL:"J" + const #113 = Utf8 "fldL"; + const #114 = Utf8 "J"; + const #115 = Utf8 "fldI"; + const #116 = Utf8 "I"; + const #117 = Utf8 "ConstantValue"; + const #118 = Integer 0; + const #119 = Utf8 "Code"; + const #120 = Utf8 "StackMapTable"; + const #121 = Class #122; // java/lang/Throwable + const #122 = Utf8 "java/lang/Throwable"; + const #123 = Utf8 "main"; + const #124 = Utf8 "([Ljava/lang/String;)V"; + const #125 = Utf8 ""; + const #126 = Utf8 "BootstrapMethods"; + const #127 = String #128; // "item_frame\u0001" + const #128 = Utf8 "item_frame\u0001"; + const #129 = String #130; // "item_frame_\u0001" + const #130 = Utf8 "item_frame_\u0001"; + const #131 = String #132; // "_frame: \u0001" + const #132 = Utf8 "_frame: \u0001"; + const #133 = String #134; // "Before chop_frame: \u0001" + const #134 = Utf8 "Before chop_frame: \u0001"; + const #135 = String #136; // "\u0001: \u0001\u0001" + const #136 = Utf8 "\u0001: \u0001\u0001"; + const #137 = MethodHandle 6:#138; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #138 = Methodref #139.#140; // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #139 = Class #141; // java/lang/invoke/StringConcatFactory + const #140 = NameAndType #47:#142; // makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #141 = Utf8 "java/lang/invoke/StringConcatFactory"; + const #142 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + const #143 = Utf8 "InnerClasses"; + const #144 = Class #145; // java/lang/invoke/MethodHandles$Lookup + const #145 = Utf8 "java/lang/invoke/MethodHandles$Lookup"; + const #146 = Class #147; // java/lang/invoke/MethodHandles + const #147 = Utf8 "java/lang/invoke/MethodHandles"; + const #148 = Utf8 "Lookup"; + + static final Field #115:#116 = #118; // fldI:I = int 0 + static Field #113:#114; // fldL:J + protected Field #13:#14; // fldS:"Ljava/lang/String;" + public final Field #17:#14 = #7; // fldFS:"Ljava/lang/String;" = String "string" + + public Method #5:#6 // "":"()V" + stack 2 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: aload_0; + 5: ldc #7; // String "string" + 7: putfield #9; // Field fldS:"Ljava/lang/String;" + 10: aload_0; + 11: ldc #7; // String "string" + 13: putfield #15; // Field fldFS:"Ljava/lang/String;" + 16: return; + } + + public Method #99:#100 // generateFrames:"(I)V" + stack 5 locals 10 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + try T0, T1; + 4: iconst_1; + 5: iload_2; + 6: idiv; + 7: istore_2; + endtry T0,T1; + 8: aload_3; + 9: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 12: pop; + 13: goto 44; + catch T0 #22; // java/lang/ArithmeticException + try T2; + 16: astore 4; + 18: new #2; // class java/lang/Object + 21: dup; + 22: invokespecial #1; // Method java/lang/Object."":"()V" + 25: astore_3; + endtry T2; + 26: aload_3; + 27: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 30: pop; + 31: goto 44; + catch T1 #0; // any + catch T2 #0; // any + catch T3 #0; // any + try T3; + 34: astore 5; + endtry T3; + 36: aload_3; + 37: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 40: pop; + 41: aload 5; + 43: athrow; + 44: iload_2; + 45: ifne 50; + 48: aconst_null; + 49: astore_3; + 50: iload_2; + 51: lookupswitch { // 2 + 1: 76; + 2: 87; + default: 87 }; + 76: new #2; // class java/lang/Object + 79: dup; + 80: invokespecial #1; // Method java/lang/Object."":"()V" + 83: astore_3; + 84: goto 87; + 87: iload_1; + 88: ifne 99; + 91: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 94: ldc #30; // String "frame" + 96: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 99: iload_1; + 100: iconst_1; + 101: if_icmpne 127; + 104: bipush 42; + 106: istore 4; + 108: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 111: iload 4; + 113: ldc #38; // float 100.0f + 115: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 118: imul; + 119: invokedynamic #45; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "item_frame\u0001" + // } + 124: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 127: iload_1; + 128: iconst_2; + 129: if_icmpne 184; + 132: iconst_0; + 133: istore 4; + 135: iconst_0; + 136: istore 5; + 138: iload 5; + 140: sipush 3000; + 143: if_icmpge 171; + 146: ldc #49; // float 3.14f + 148: fstore 6; + 150: iload 4; + 152: fload 6; + 154: ldc #38; // float 100.0f + 156: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 159: i2f; + 160: fmul; + 161: f2i; + 162: iadd; + 163: istore 4; + 165: iinc 5, 1; + 168: goto 138; + 171: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 174: iload 4; + 176: invokedynamic #50; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "item_frame_\u0001" + // } + 181: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 184: ldc #51; // float 10.0f + 186: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 189: istore 4; + 191: iload_1; + 192: iconst_3; + 193: if_icmpne 232; + 196: ldc #52; // float 110.0f + 198: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 201: istore 5; + 203: ldc2_w #53; // double 100.0d + 206: invokestatic #55; // Method java/lang/Math.round:"(D)J" + 209: lstore 6; + 211: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 214: iload 5; + 216: i2l; + 217: lload 6; + 219: ladd; + 220: iload 4; + 222: i2l; + 223: lmul; + 224: invokedynamic #58; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(J)Ljava/lang/String;" { + // String "_frame: \u0001" + // } + 229: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 232: iload_1; + 233: iconst_4; + 234: if_icmpne 273; + 237: bipush 50; + 239: iload 4; + 241: imul; + 242: istore 5; + 244: ldc2_w #61; // double 99.99d + 247: iload 4; + 249: i2d; + 250: dmul; + 251: dstore 6; + 253: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 256: iload 5; + 258: i2d; + 259: dload 6; + 261: dadd; + 262: invokedynamic #63; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(D)Ljava/lang/String;" { + // String "Before chop_frame: \u0001" + // } + 267: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 270: goto 281; + 273: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 276: ldc #66; // String "chop_frame" + 278: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 281: iload_1; + 282: iconst_5; + 283: if_icmpne 379; + 286: iconst_0; + 287: istore 5; + 289: iconst_0; + 290: istore 6; + 292: iload 6; + 294: sipush 2500; + 297: if_icmpge 326; + 300: ldc #49; // float 3.14f + 302: fstore 7; + 304: iload 5; + 306: fload 7; + 308: iload 6; + 310: i2f; + 311: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 314: i2f; + 315: fmul; + 316: f2i; + 317: iadd; + 318: istore 5; + 320: iinc 6, 1; + 323: goto 292; + 326: iload 5; + 328: bipush 100; + 330: if_icmple 344; + 333: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 336: ldc #68; // String "_frame_" + 338: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 341: goto 379; + 344: iload 5; + 346: bipush 50; + 348: if_icmpge 379; + 351: bipush 50; + 353: iload 4; + 355: imul; + 356: istore 6; + 358: ldc2_w #61; // double 99.99d + 361: iload 4; + 363: i2d; + 364: dmul; + 365: dstore 7; + 367: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 370: iload 6; + 372: i2d; + 373: dload 7; + 375: dadd; + 376: invokevirtual #70; // Method java/io/PrintStream.println:"(D)V" + 379: iload_1; + 380: bipush 6; + 382: if_icmpne 414; + 385: ldc #73; // String "n_frame" + 387: astore 5; + 389: bipush 70; + 391: istore 6; + 393: bipush 100; + 395: istore 7; + 397: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 400: aload 5; + 402: iload 6; + 404: iload 7; + 406: invokedynamic #75; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 411: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 414: iconst_0; + 415: istore 5; + 417: aconst_null; + 418: astore 6; + try T4, T5; + 420: iconst_1; + 421: iload 5; + 423: idiv; + 424: istore 5; + endtry T4,T5; + 426: aload 6; + 428: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 431: pop; + 432: goto 466; + catch T4 #22; // java/lang/ArithmeticException + try T6; + 435: astore 7; + 437: new #2; // class java/lang/Object + 440: dup; + 441: invokespecial #1; // Method java/lang/Object."":"()V" + 444: astore 6; + endtry T6; + 446: aload 6; + 448: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 451: pop; + 452: goto 466; + catch T5 #0; // any + catch T6 #0; // any + catch T7 #0; // any + try T7; + 455: astore 9; + endtry T7; + 457: aload 6; + 459: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 462: pop; + 463: aload 9; + 465: athrow; + 466: iload 5; + 468: ifne 474; + 471: aconst_null; + 472: astore 6; + 474: iload_2; + 475: lookupswitch { // 2 + 1: 500; + 2: 512; + default: 512 }; + 500: new #2; // class java/lang/Object + 503: dup; + 504: invokespecial #1; // Method java/lang/Object."":"()V" + 507: astore 6; + 509: goto 512; + 512: return; + StackMapTable: number_of_entries = 25 + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 255 // full + offset_delta = 16 + stack_map = [ #22; ] // class java/lang/ArithmeticException; + locals_map = [ #10, 1, 1, #2; ] // class StackMapData, int, int, class java/lang/Object; + } + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 81 // same_locals_1_stack_item + stack_map = [ #121; ] // class java/lang/Throwable; + } + frame_type = 246 // early_larval + unset_fields = [ #26, // out:"Ljava/io/PrintStream;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 9 // same + } + frame_type = 5 // same + frame_type = 25 // same + frame_type = 10 // same + frame_type = 11 // same + frame_type = 27 // same + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 253 // append + offset_delta = 10 + locals_map = [ 1, 1; ] // int, int; + } + frame_type = 250 // chop1 + offset_delta = 32 + frame_type = 250 // chop1 + offset_delta = 12 + frame_type = 252 // append + offset_delta = 47 + locals_map = [ 1; ] // int; + frame_type = 40 // same + frame_type = 7 // same + frame_type = 253 // append + offset_delta = 10 + locals_map = [ 1, 1; ] // int, int; + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 250 // chop1 + offset_delta = 33 + } + frame_type = 17 // same + frame_type = 250 // chop1 + offset_delta = 34 + frame_type = 34 // same + frame_type = 255 // full + offset_delta = 20 + stack_map = [ #22; ] // class java/lang/ArithmeticException; + locals_map = [ #10, 1, 1, #2, 1, 1, #2; ] // class StackMapData, int, int, class java/lang/Object, int, int, class java/lang/Object; + frame_type = 83 // same_locals_1_stack_item + stack_map = [ #121; ] // class java/lang/Throwable; + frame_type = 10 // same + frame_type = 7 // same + frame_type = 25 // same + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26, // out:"Ljava/io/PrintStream;" + #112; ] { // fldL:"J" + frame_type = 11 // same + } + } + + public Method #105:#106 // complexMethod:"(ILjava/lang/Object;)I" + stack 3 locals 7 + { + 0: iconst_0; + 1: istore_3; + 2: iconst_1; + 3: istore 4; + 5: aconst_null; + 6: astore 5; + try T0; + 8: iload_1; + 9: ifle 47; + 12: iload_1; + 13: iconst_1; + 14: iadd; + 15: istore_3; + 16: aload_2; + 17: instanceof #78; // class java/lang/String + 20: ifeq 39; + 23: aload_2; + 24: checkcast #78; // class java/lang/String + 27: astore 5; + 29: aload 5; + 31: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 34: istore 4; + 36: iload 4; + endtry T0; + 38: ireturn; + try T1; + 39: iload_3; + 40: iconst_2; + 41: imul; + 42: istore 4; + 44: goto 104; + 47: iload_1; + 48: iconst_m1; + 49: if_icmpne 70; + 52: iload_1; + 53: ineg; + 54: istore_3; + 55: iload_3; + 56: iconst_3; + 57: iadd; + 58: istore 4; + 60: new #84; // class java/lang/RuntimeException + 63: dup; + 64: ldc #86; // String "Test exception" + 66: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 69: athrow; + 70: iconst_0; + 71: istore 6; + 73: iload 6; + 75: iconst_2; + 76: if_icmpge 104; + 79: iload_3; + 80: iload 6; + 82: iadd; + 83: istore_3; + 84: iload_3; + 85: iconst_1; + 86: if_icmple 98; + 89: iload_3; + 90: iload 6; + 92: isub; + 93: istore 4; + 95: goto 104; + 98: iinc 6, 1; + 101: goto 73; + endtry T1; + 104: goto 118; + catch T0 #84; // java/lang/RuntimeException + catch T1 #84; // java/lang/RuntimeException + 107: astore 6; + 109: aload 6; + 111: astore 5; + 113: iload_3; + 114: iconst_5; + 115: iadd; + 116: istore 4; + 118: iload_3; + 119: iload 4; + 121: iadd; + 122: ireturn; + StackMapTable: number_of_entries = 8 + frame_type = 254 // append + offset_delta = 39 + locals_map = [ 1, 1, #2; ] // int, int, class java/lang/Object; + frame_type = 7 // same + frame_type = 22 // same + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26, // out:"Ljava/io/PrintStream;" + #112; ] { // fldL:"J" + frame_type = 252 // append + offset_delta = 2 + locals_map = [ 1; ] // int; + } + frame_type = 24 // same + frame_type = 250 // chop1 + offset_delta = 5 + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26, // out:"Ljava/io/PrintStream;" + #112; ] { // fldL:"J" + frame_type = 66 // same_locals_1_stack_item + stack_map = [ #84; ] // class java/lang/RuntimeException; + } + frame_type = 10 // same + } + + public Method #109:#110 // generateFullFrame:"(I)I" + stack 3 locals 6 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + 4: iconst_0; + 5: istore 4; + try T0; + 7: iload_1; + 8: ifle 25; + 11: ldc #90; // String "positive" + 13: astore_3; + 14: iconst_1; + 15: istore 4; + 17: aload_3; + 18: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 21: istore_2; + 22: goto 39; + 25: iload_1; + 26: iconst_2; + 27: imul; + 28: istore_2; + 29: new #84; // class java/lang/RuntimeException + 32: dup; + 33: ldc #92; // String "non-positive" + 35: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 38: athrow; + endtry T0; + 39: goto 53; + catch T0 #84; // java/lang/RuntimeException + 42: astore 5; + 44: aload 5; + 46: astore_3; + 47: iconst_0; + 48: istore 4; + 50: iload_1; + 51: ineg; + 52: istore_2; + 53: iload 4; + 55: ifeq 62; + 58: iload_2; + 59: iconst_1; + 60: iadd; + 61: ireturn; + 62: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 65: ldc #94; // String "Computing result" + 67: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 70: iload_2; + 71: ireturn; + StackMapTable: number_of_entries = 5 + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26, // out:"Ljava/io/PrintStream;" + #112; ] { // fldL:"J" + frame_type = 254 // append + offset_delta = 25 + locals_map = [ 1, #2, 1; ] // int, class java/lang/Object, int; + } + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26; ] { // out:"Ljava/io/PrintStream;" + frame_type = 13 // same + } + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 66 // same_locals_1_stack_item + stack_map = [ #84; ] // class java/lang/RuntimeException; + } + frame_type = 246 // early_larval + unset_fields = [ #11; ] { //fldS:"Ljava/lang/String;"; + frame_type = 10 // same + } + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 8 // same + } + } + + public static Method #123:#124 // main:"([Ljava/lang/String;)V" + stack 3 locals 3 + { + 0: new #10; // class StackMapData + 3: dup; + 4: invokespecial #96; // Method "":"()V" + 7: astore_1; + 8: iconst_0; + 9: istore_2; + 10: iload_2; + 11: bipush 6; + 13: if_icmpgt 27; + 16: aload_1; + 17: iload_2; + 18: invokevirtual #97; // Method generateFrames:"(I)V" + 21: iinc 2, 1; + 24: goto 10; + 27: aload_1; + 28: iconst_0; + 29: ldc #101; // String "test" + 31: invokevirtual #103; // Method complexMethod:"(ILjava/lang/Object;)I" + 34: pop; + 35: aload_1; + 36: bipush 23; + 38: invokevirtual #107; // Method generateFullFrame:"(I)I" + 41: pop; + 42: return; + StackMapTable: number_of_entries = 2 + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 253 // append + offset_delta = 10 + locals_map = [ #10, 1; ] // class StackMapData, int; + } + frame_type = 250 // chop1 + offset_delta = 16 + } + + static Method #125:#6 // "":"()V" + stack 2 locals 0 + { + 0: lconst_1; + 1: putstatic #111; // Field fldL:"J" + 4: return; + } + + InnerClasses { + public static final #148 = #144 of #146; // Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + } + + BootstrapMethods { + 0: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #127; // String "item_frame\u0001" + + 1: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #129; // String "item_frame_\u0001" + + 2: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #131; // String "_frame: \u0001" + + 3: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #133; // String "Before chop_frame: \u0001" + + 4: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #135; // String "\u0001: \u0001\u0001" + } +} // end Class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,612 @@ +package org/openjdk/asmtools/attribute/StackMapTable/data; + +public super class StackMapData version 69:0 +{ + static final Field fldI:I = int 0; + static Field fldL:J; + protected Field fldS:"Ljava/lang/String;"; + public final Field fldFS:"Ljava/lang/String;" = String "string"; + + public Method "":"()V" + stack 2 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + aload_0; + ldc String "string"; + putfield Field fldS:"Ljava/lang/String;"; + aload_0; + ldc String "string"; + putfield Field fldFS:"Ljava/lang/String;"; + return; + } + + public Method generateFrames:"(I)V" + stack 5 locals 10 + { + iconst_0; + istore_2; + aconst_null; + astore_3; + try T0, T1; + iconst_1; + iload_2; + idiv; + istore_2; + endtry T0,T1; + aload_3; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L44; + catch T0 java/lang/ArithmeticException; + try T2; + stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;"; + frame_type full; + locals_map class StackMapData, int, int, class java/lang/Object; + stack_map class java/lang/ArithmeticException; + astore 4; + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_3; + endtry T2; + aload_3; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L44; + catch T1 #0; + catch T2 #0; + catch T3 #0; + try T3; + stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;"; + frame_type stack1; + stack_map class java/lang/Throwable; + astore 5; + endtry T3; + aload_3; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + aload 5; + athrow; + L44: stack_frame_type early_larval; + unset_fields out:"Ljava/io/PrintStream;", + fldFS:"Ljava/lang/String;"; + frame_type same; + iload_2; + ifne L50; + aconst_null; + astore_3; + L50: stack_frame_type same; + iload_2; + lookupswitch { + 1: L76; + 2: L87; + default: L87 }; + L76: stack_frame_type same; + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_3; + goto L87; + L87: stack_frame_type same; + iload_1; + ifne L99; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "frame"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L99: stack_frame_type same; + iload_1; + iconst_1; + if_icmpne L127; + bipush 42; + istore 4; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 4; + ldc float 100.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + imul; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(I)Ljava/lang/String;" { + String "item_frame\u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L127: stack_frame_type same; + iload_1; + iconst_2; + if_icmpne L184; + iconst_0; + istore 4; + iconst_0; + istore 5; + L138: stack_frame_type early_larval; + unset_fields; + frame_type append; + locals_map int, int; + iload 5; + sipush 3000; + if_icmpge L171; + ldc float 3.14f; + fstore 6; + iload 4; + fload 6; + ldc float 100.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + i2f; + fmul; + f2i; + iadd; + istore 4; + iinc 5, 1; + goto L138; + L171: stack_frame_type chop1; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 4; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(I)Ljava/lang/String;" { + String "item_frame_\u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L184: stack_frame_type chop1; + ldc float 10.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + istore 4; + iload_1; + iconst_3; + if_icmpne L232; + ldc float 110.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + istore 5; + ldc2_w double 100.0d; + invokestatic Method java/lang/Math.round:"(D)J"; + lstore 6; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 5; + i2l; + lload 6; + ladd; + iload 4; + i2l; + lmul; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(J)Ljava/lang/String;" { + String "_frame: \u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L232: stack_frame_type append; + locals_map int; + iload_1; + iconst_4; + if_icmpne L273; + bipush 50; + iload 4; + imul; + istore 5; + ldc2_w double 99.99d; + iload 4; + i2d; + dmul; + dstore 6; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 5; + i2d; + dload 6; + dadd; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(D)Ljava/lang/String;" { + String "Before chop_frame: \u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + goto L281; + L273: stack_frame_type same; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "chop_frame"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L281: stack_frame_type same; + iload_1; + iconst_5; + if_icmpne L379; + iconst_0; + istore 5; + iconst_0; + istore 6; + L292: stack_frame_type append; + locals_map int, int; + iload 6; + sipush 2500; + if_icmpge L326; + ldc float 3.14f; + fstore 7; + iload 5; + fload 7; + iload 6; + i2f; + invokestatic Method java/lang/Math.round:"(F)I"; + i2f; + fmul; + f2i; + iadd; + istore 5; + iinc 6, 1; + goto L292; + L326: stack_frame_type early_larval; + unset_fields; + frame_type chop1; + iload 5; + bipush 100; + if_icmple L344; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "_frame_"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + goto L379; + L344: stack_frame_type same; + iload 5; + bipush 50; + if_icmpge L379; + bipush 50; + iload 4; + imul; + istore 6; + ldc2_w double 99.99d; + iload 4; + i2d; + dmul; + dstore 7; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 6; + i2d; + dload 7; + dadd; + invokevirtual Method java/io/PrintStream.println:"(D)V"; + L379: stack_frame_type chop1; + iload_1; + bipush 6; + if_icmpne L414; + ldc String "n_frame"; + astore 5; + bipush 70; + istore 6; + bipush 100; + istore 7; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + aload 5; + iload 6; + iload 7; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" { + String "\u0001: \u0001\u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L414: stack_frame_type same; + iconst_0; + istore 5; + aconst_null; + astore 6; + try T4, T5; + iconst_1; + iload 5; + idiv; + istore 5; + endtry T4,T5; + aload 6; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L466; + catch T4 java/lang/ArithmeticException; + try T6; + stack_frame_type full; + locals_map class StackMapData, int, int, class java/lang/Object, int, int, class java/lang/Object; + stack_map class java/lang/ArithmeticException; + astore 7; + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore 6; + endtry T6; + aload 6; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L466; + catch T5 #0; + catch T6 #0; + catch T7 #0; + try T7; + stack_frame_type stack1; + stack_map class java/lang/Throwable; + astore 9; + endtry T7; + aload 6; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + aload 9; + athrow; + L466: stack_frame_type same; + iload 5; + ifne L474; + aconst_null; + astore 6; + L474: stack_frame_type same; + iload_2; + lookupswitch { + 1: L500; + 2: L512; + default: L512 }; + L500: stack_frame_type same; + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore 6; + goto L512; + L512: stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; + frame_type same; + return; + } + + public Method complexMethod:"(ILjava/lang/Object;)I" + stack 3 locals 7 + { + iconst_0; + istore_3; + iconst_1; + istore 4; + aconst_null; + astore 5; + try T0; + iload_1; + ifle L47; + iload_1; + iconst_1; + iadd; + istore_3; + aload_2; + instanceof class java/lang/String; + ifeq L39; + aload_2; + checkcast class java/lang/String; + astore 5; + aload 5; + invokevirtual Method java/lang/Object.hashCode:"()I"; + istore 4; + iload 4; + endtry T0; + ireturn; + try T1; + L39: stack_frame_type append; + locals_map int, int, class java/lang/Object; + iload_3; + iconst_2; + imul; + istore 4; + goto L104; + L47: stack_frame_type same; + iload_1; + iconst_m1; + if_icmpne L70; + iload_1; + ineg; + istore_3; + iload_3; + iconst_3; + iadd; + istore 4; + new class java/lang/RuntimeException; + dup; + ldc String "Test exception"; + invokespecial Method java/lang/RuntimeException."":"(Ljava/lang/String;)V"; + athrow; + L70: stack_frame_type same; + iconst_0; + istore 6; + L73: stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; + frame_type append; + locals_map int; + iload 6; + iconst_2; + if_icmpge L104; + iload_3; + iload 6; + iadd; + istore_3; + iload_3; + iconst_1; + if_icmple L98; + iload_3; + iload 6; + isub; + istore 4; + goto L104; + L98: stack_frame_type same; + iinc 6, 1; + goto L73; + endtry T1; + L104: stack_frame_type chop1; + goto L118; + catch T0 java/lang/RuntimeException; + catch T1 java/lang/RuntimeException; + stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; + frame_type stack1; + stack_map class java/lang/RuntimeException; + astore 6; + aload 6; + astore 5; + iload_3; + iconst_5; + iadd; + istore 4; + L118: stack_frame_type same; + iload_3; + iload 4; + iadd; + ireturn; + } + + public Method generateFullFrame:"(I)I" + stack 3 locals 6 + { + iconst_0; + istore_2; + aconst_null; + astore_3; + iconst_0; + istore 4; + try T0; + iload_1; + ifle L25; + ldc String "positive"; + astore_3; + iconst_1; + istore 4; + aload_3; + invokevirtual Method java/lang/Object.hashCode:"()I"; + istore_2; + goto L39; + L25: stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; + frame_type append; + locals_map int, class java/lang/Object, int; + iload_1; + iconst_2; + imul; + istore_2; + new class java/lang/RuntimeException; + dup; + ldc String "non-positive"; + invokespecial Method java/lang/RuntimeException."":"(Ljava/lang/String;)V"; + athrow; + endtry T0; + L39: stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;"; + frame_type same; + goto L53; + catch T0 java/lang/RuntimeException; + stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;"; + frame_type stack1; + stack_map class java/lang/RuntimeException; + astore 5; + aload 5; + astore_3; + iconst_0; + istore 4; + iload_1; + ineg; + istore_2; + L53: stack_frame_type early_larval; + unset_fields fldS:"Ljava/lang/String;"; + frame_type same; + iload 4; + ifeq L62; + iload_2; + iconst_1; + iadd; + ireturn; + L62: stack_frame_type early_larval; + unset_fields; + frame_type same; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "Computing result"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + iload_2; + ireturn; + } + + public static Method main:"([Ljava/lang/String;)V" + stack 3 locals 3 + { + new class StackMapData; + dup; + invokespecial Method "":"()V"; + astore_1; + iconst_0; + istore_2; + L10: stack_frame_type early_larval; + unset_fields; + frame_type append; + locals_map class StackMapData, int; + iload_2; + bipush 6; + if_icmpgt L27; + aload_1; + iload_2; + invokevirtual Method generateFrames:"(I)V"; + iinc 2, 1; + goto L10; + L27: stack_frame_type chop1; + aload_1; + iconst_0; + ldc String "test"; + invokevirtual Method complexMethod:"(ILjava/lang/Object;)I"; + pop; + aload_1; + bipush 23; + invokevirtual Method generateFullFrame:"(I)I"; + pop; + return; + } + + static Method "":"()V" + stack 2 locals 0 + { + lconst_1; + putstatic Field fldL:"J"; + return; + } + + InnerClass public static final Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + + BootstrapMethod REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + String "item_frame\u0001" + } + + BootstrapMethod REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + String "item_frame_\u0001" + } + + BootstrapMethod REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + String "_frame: \u0001" + } + + BootstrapMethod REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + String "Before chop_frame: \u0001" + } + + BootstrapMethod REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + String "\u0001: \u0001\u0001" + } +} // end Class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,520 @@ +class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData { + 0xCAFEBABE; + 0; // minor version + 69; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "string"; // #8 + Field #10 #11; // #9 + Class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData"; // #12 + Utf8 "fldS"; // #13 + Utf8 "Ljava/lang/String;"; // #14 + Field #10 #16; // #15 + NameAndType #17 #14; // #16 + Utf8 "fldFS"; // #17 + Method #2 #19; // #18 + NameAndType #20 #21; // #19 + Utf8 "toString"; // #20 + Utf8 "()Ljava/lang/String;"; // #21 + Class #23; // #22 + Utf8 "java/lang/ArithmeticException"; // #23 + Field #25 #26; // #24 + Class #27; // #25 + NameAndType #28 #29; // #26 + Utf8 "java/lang/System"; // #27 + Utf8 "out"; // #28 + Utf8 "Ljava/io/PrintStream;"; // #29 + String #31; // #30 + Utf8 "frame"; // #31 + Method #33 #34; // #32 + Class #35; // #33 + NameAndType #36 #37; // #34 + Utf8 "java/io/PrintStream"; // #35 + Utf8 "println"; // #36 + Utf8 "(Ljava/lang/String;)V"; // #37 + Float 0x42C80000; // #38 + Method #40 #41; // #39 + Class #42; // #40 + NameAndType #43 #44; // #41 + Utf8 "java/lang/Math"; // #42 + Utf8 "round"; // #43 + Utf8 "(F)I"; // #44 + InvokeDynamic 0s #46; // #45 + NameAndType #47 #48; // #46 + Utf8 "makeConcatWithConstants"; // #47 + Utf8 "(I)Ljava/lang/String;"; // #48 + Float 0x4048F5C3; // #49 + InvokeDynamic 1s #46; // #50 + Float 0x41200000; // #51 + Float 0x42DC0000; // #52 + Double 0x4059000000000000;; // #53 + Method #40 #56; // #55 + NameAndType #43 #57; // #56 + Utf8 "(D)J"; // #57 + InvokeDynamic 2s #59; // #58 + NameAndType #47 #60; // #59 + Utf8 "(J)Ljava/lang/String;"; // #60 + Double 0x4058FF5C28F5C28F;; // #61 + InvokeDynamic 3s #64; // #63 + NameAndType #47 #65; // #64 + Utf8 "(D)Ljava/lang/String;"; // #65 + String #67; // #66 + Utf8 "chop_frame"; // #67 + String #69; // #68 + Utf8 "_frame_"; // #69 + Method #33 #71; // #70 + NameAndType #36 #72; // #71 + Utf8 "(D)V"; // #72 + String #74; // #73 + Utf8 "n_frame"; // #74 + InvokeDynamic 4s #76; // #75 + NameAndType #47 #77; // #76 + Utf8 "(Ljava/lang/String;CI)Ljava/lang/String;"; // #77 + Class #79; // #78 + Utf8 "java/lang/String"; // #79 + Method #2 #81; // #80 + NameAndType #82 #83; // #81 + Utf8 "hashCode"; // #82 + Utf8 "()I"; // #83 + Class #85; // #84 + Utf8 "java/lang/RuntimeException"; // #85 + String #87; // #86 + Utf8 "Test exception"; // #87 + Method #84 #89; // #88 + NameAndType #5 #37; // #89 + String #91; // #90 + Utf8 "positive"; // #91 + String #93; // #92 + Utf8 "non-positive"; // #93 + String #95; // #94 + Utf8 "Computing result"; // #95 + Method #10 #3; // #96 + Method #10 #98; // #97 + NameAndType #99 #100; // #98 + Utf8 "generateFrames"; // #99 + Utf8 "(I)V"; // #100 + String #102; // #101 + Utf8 "test"; // #102 + Method #10 #104; // #103 + NameAndType #105 #106; // #104 + Utf8 "complexMethod"; // #105 + Utf8 "(ILjava/lang/Object;)I"; // #106 + Method #10 #108; // #107 + NameAndType #109 #110; // #108 + Utf8 "generateFullFrame"; // #109 + Utf8 "(I)I"; // #110 + Field #10 #112; // #111 + NameAndType #113 #114; // #112 + Utf8 "fldL"; // #113 + Utf8 "J"; // #114 + Utf8 "fldI"; // #115 + Utf8 "I"; // #116 + Utf8 "ConstantValue"; // #117 + Integer 0x00000000; // #118 + Utf8 "Code"; // #119 + Utf8 "StackMapTable"; // #120 + Class #122; // #121 + Utf8 "java/lang/Throwable"; // #122 + Utf8 "main"; // #123 + Utf8 "([Ljava/lang/String;)V"; // #124 + Utf8 ""; // #125 + Utf8 "BootstrapMethods"; // #126 + String #128; // #127 + Utf8 "item_frame\u0001"; // #128 + String #130; // #129 + Utf8 "item_frame_\u0001"; // #130 + String #132; // #131 + Utf8 "_frame: \u0001"; // #132 + String #134; // #133 + Utf8 "Before chop_frame: \u0001"; // #134 + String #136; // #135 + Utf8 "\u0001: \u0001\u0001"; // #136 + MethodHandle 6b #138; // #137 + Method #139 #140; // #138 + Class #141; // #139 + NameAndType #47 #142; // #140 + Utf8 "java/lang/invoke/StringConcatFactory"; // #141 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #142 + Utf8 "InnerClasses"; // #143 + Class #145; // #144 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #145 + Class #147; // #146 + Utf8 "java/lang/invoke/MethodHandles"; // #147 + Utf8 "Lookup"; // #148 + } + + 0x0021; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0018; // access + #115; // name_index + #116; // descriptor_index + [] { // Attributes + Attr(#117) { // ConstantValue + #118; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field + 0x0008; // access + #113; // name_index + #114; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0004; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0011; // access + #17; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#117) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#119) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0x2A 0x12 0x07 0xB5 0x00 0x09 0x2A 0x12; + 0x07 0xB5 0x00 0x0F 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #99; // name_index + #100; // descriptor_index + [] { // Attributes + Attr(#119) { // Code + 5; // max_stack + 10; // max_locals + Bytes[]{ + 0x03 0x3D 0x01 0x4E 0x04 0x1C 0x6C 0x3D 0x2D 0xB6 0x00 0x12; + 0x57 0xA7 0x00 0x1F 0x3A 0x04 0xBB 0x00 0x02 0x59 0xB7 0x00; + 0x01 0x4E 0x2D 0xB6 0x00 0x12 0x57 0xA7 0x00 0x0D 0x3A 0x05; + 0x2D 0xB6 0x00 0x12 0x57 0x19 0x05 0xBF 0x1C 0x9A 0x00 0x05; + 0x01 0x4E 0x1C 0xAB 0x00 0x00 0x00 0x24 0x00 0x00 0x00 0x02; + 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x19 0x00 0x00 0x00 0x02; + 0x00 0x00 0x00 0x24 0xBB 0x00 0x02 0x59 0xB7 0x00 0x01 0x4E; + 0xA7 0x00 0x03 0x1B 0x9A 0x00 0x0B 0xB2 0x00 0x18 0x12 0x1E; + 0xB6 0x00 0x20 0x1B 0x04 0xA0 0x00 0x1A 0x10 0x2A 0x36 0x04; + 0xB2 0x00 0x18 0x15 0x04 0x12 0x26 0xB8 0x00 0x27 0x68 0xBA; + 0x00 0x2D 0x00 0x00 0xB6 0x00 0x20 0x1B 0x05 0xA0 0x00 0x37; + 0x03 0x36 0x04 0x03 0x36 0x05 0x15 0x05 0x11 0x0B 0xB8 0xA2; + 0x00 0x1C 0x12 0x31 0x38 0x06 0x15 0x04 0x17 0x06 0x12 0x26; + 0xB8 0x00 0x27 0x86 0x6A 0x8B 0x60 0x36 0x04 0x84 0x05 0x01; + 0xA7 0xFF 0xE2 0xB2 0x00 0x18 0x15 0x04 0xBA 0x00 0x32 0x00; + 0x00 0xB6 0x00 0x20 0x12 0x33 0xB8 0x00 0x27 0x36 0x04 0x1B; + 0x06 0xA0 0x00 0x27 0x12 0x34 0xB8 0x00 0x27 0x36 0x05 0x14; + 0x00 0x35 0xB8 0x00 0x37 0x37 0x06 0xB2 0x00 0x18 0x15 0x05; + 0x85 0x16 0x06 0x61 0x15 0x04 0x85 0x69 0xBA 0x00 0x3A 0x00; + 0x00 0xB6 0x00 0x20 0x1B 0x07 0xA0 0x00 0x27 0x10 0x32 0x15; + 0x04 0x68 0x36 0x05 0x14 0x00 0x3D 0x15 0x04 0x87 0x6B 0x39; + 0x06 0xB2 0x00 0x18 0x15 0x05 0x87 0x18 0x06 0x63 0xBA 0x00; + 0x3F 0x00 0x00 0xB6 0x00 0x20 0xA7 0x00 0x0B 0xB2 0x00 0x18; + 0x12 0x42 0xB6 0x00 0x20 0x1B 0x08 0xA0 0x00 0x60 0x03 0x36; + 0x05 0x03 0x36 0x06 0x15 0x06 0x11 0x09 0xC4 0xA2 0x00 0x1D; + 0x12 0x31 0x38 0x07 0x15 0x05 0x17 0x07 0x15 0x06 0x86 0xB8; + 0x00 0x27 0x86 0x6A 0x8B 0x60 0x36 0x05 0x84 0x06 0x01 0xA7; + 0xFF 0xE1 0x15 0x05 0x10 0x64 0xA4 0x00 0x0E 0xB2 0x00 0x18; + 0x12 0x44 0xB6 0x00 0x20 0xA7 0x00 0x26 0x15 0x05 0x10 0x32; + 0xA2 0x00 0x1F 0x10 0x32 0x15 0x04 0x68 0x36 0x06 0x14 0x00; + 0x3D 0x15 0x04 0x87 0x6B 0x39 0x07 0xB2 0x00 0x18 0x15 0x06; + 0x87 0x18 0x07 0x63 0xB6 0x00 0x46 0x1B 0x10 0x06 0xA0 0x00; + 0x20 0x12 0x49 0x3A 0x05 0x10 0x46 0x36 0x06 0x10 0x64 0x36; + 0x07 0xB2 0x00 0x18 0x19 0x05 0x15 0x06 0x15 0x07 0xBA 0x00; + 0x4B 0x00 0x00 0xB6 0x00 0x20 0x03 0x36 0x05 0x01 0x3A 0x06; + 0x04 0x15 0x05 0x6C 0x36 0x05 0x19 0x06 0xB6 0x00 0x12 0x57; + 0xA7 0x00 0x22 0x3A 0x07 0xBB 0x00 0x02 0x59 0xB7 0x00 0x01; + 0x3A 0x06 0x19 0x06 0xB6 0x00 0x12 0x57 0xA7 0x00 0x0E 0x3A; + 0x09 0x19 0x06 0xB6 0x00 0x12 0x57 0x19 0x09 0xBF 0x15 0x05; + 0x9A 0x00 0x06 0x01 0x3A 0x06 0x1C 0xAB 0x00 0x00 0x00 0x25; + 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x19; + 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x25 0xBB 0x00 0x02 0x59; + 0xB7 0x00 0x01 0x3A 0x06 0xA7 0x00 0x03 0xB1; + } + [] { // Traps + 4 8 16 22; + 4 8 34 0; + 16 26 34 0; + 34 36 34 0; + 420 426 435 22; + 420 426 455 0; + 435 446 455 0; + 455 457 455 0; + } // end of Traps + [] { // Attributes + Attr(#120) { // StackMapTable + [] { // + 246b, []{#11; #16}, { // early_larval_frame + 255b, 16, []{O,#10; I; I; O,#2}, []{O,#22}; // full_frame + }; + 246b, []{#11; #16}, { // early_larval_frame + 81b, []z{O,#121}; // same_locals_1_stack_item_frame + }; + 246b, []{#26; #16}, { // early_larval_frame + 9b; // same_frame + }; + 5b; // same_frame + 25b; // same_frame + 10b; // same_frame + 11b; // same_frame + 27b; // same_frame + 246b, []{}, { // early_larval_frame + 253b, 10, []z{I; I}; // append_frame 2 + }; + 250b, 32; // chop_frame 1 + 250b, 12; // chop_frame 1 + 252b, 47, []z{I}; // append_frame 1 + 40b; // same_frame + 7b; // same_frame + 253b, 10, []z{I; I}; // append_frame 2 + 246b, []{}, { // early_larval_frame + 250b, 33; // chop_frame 1 + }; + 17b; // same_frame + 250b, 34; // chop_frame 1 + 34b; // same_frame + 255b, 20, []{O,#10; I; I; O,#2; I; I; O,#2}, []{O,#22}; // full_frame + 83b, []z{O,#121}; // same_locals_1_stack_item_frame + 10b; // same_frame + 7b; // same_frame + 25b; // same_frame + 246b, []{#11; #16; #26; #112}, { // early_larval_frame + 11b; // same_frame + }; + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #105; // name_index + #106; // descriptor_index + [] { // Attributes + Attr(#119) { // Code + 3; // max_stack + 7; // max_locals + Bytes[]{ + 0x03 0x3E 0x04 0x36 0x04 0x01 0x3A 0x05 0x1B 0x9E 0x00 0x26; + 0x1B 0x04 0x60 0x3E 0x2C 0xC1 0x00 0x4E 0x99 0x00 0x13 0x2C; + 0xC0 0x00 0x4E 0x3A 0x05 0x19 0x05 0xB6 0x00 0x50 0x36 0x04; + 0x15 0x04 0xAC 0x1D 0x05 0x68 0x36 0x04 0xA7 0x00 0x3C 0x1B; + 0x02 0xA0 0x00 0x15 0x1B 0x74 0x3E 0x1D 0x06 0x60 0x36 0x04; + 0xBB 0x00 0x54 0x59 0x12 0x56 0xB7 0x00 0x58 0xBF 0x03 0x36; + 0x06 0x15 0x06 0x05 0xA2 0x00 0x1C 0x1D 0x15 0x06 0x60 0x3E; + 0x1D 0x04 0xA4 0x00 0x0C 0x1D 0x15 0x06 0x64 0x36 0x04 0xA7; + 0x00 0x09 0x84 0x06 0x01 0xA7 0xFF 0xE4 0xA7 0x00 0x0E 0x3A; + 0x06 0x19 0x06 0x3A 0x05 0x1D 0x08 0x60 0x36 0x04 0x1D 0x15; + 0x04 0x60 0xAC; + } + [] { // Traps + 8 38 107 84; + 39 104 107 84; + } // end of Traps + [] { // Attributes + Attr(#120) { // StackMapTable + [] { // + 254b, 39, []z{I; I; O,#2}; // append_frame 3 + 7b; // same_frame + 22b; // same_frame + 246b, []{#11; #16; #26; #112}, { // early_larval_frame + 252b, 2, []z{I}; // append_frame 1 + }; + 24b; // same_frame + 250b, 5; // chop_frame 1 + 246b, []{#11; #16; #26; #112}, { // early_larval_frame + 66b, []z{O,#84}; // same_locals_1_stack_item_frame + }; + 10b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #109; // name_index + #110; // descriptor_index + [] { // Attributes + Attr(#119) { // Code + 3; // max_stack + 6; // max_locals + Bytes[]{ + 0x03 0x3D 0x01 0x4E 0x03 0x36 0x04 0x1B 0x9E 0x00 0x11 0x12; + 0x5A 0x4E 0x04 0x36 0x04 0x2D 0xB6 0x00 0x50 0x3D 0xA7 0x00; + 0x11 0x1B 0x05 0x68 0x3D 0xBB 0x00 0x54 0x59 0x12 0x5C 0xB7; + 0x00 0x58 0xBF 0xA7 0x00 0x0E 0x3A 0x05 0x19 0x05 0x4E 0x03; + 0x36 0x04 0x1B 0x74 0x3D 0x15 0x04 0x99 0x00 0x07 0x1C 0x04; + 0x60 0xAC 0xB2 0x00 0x18 0x12 0x5E 0xB6 0x00 0x20 0x1C 0xAC; + } + [] { // Traps + 7 39 42 84; + } // end of Traps + [] { // Attributes + Attr(#120) { // StackMapTable + [] { // + 246b, []{#11; #16; #26; #112}, { // early_larval_frame + 254b, 25, []z{I; O,#2; I}; // append_frame 3 + }; + 246b, []{#11; #16; #26}, { // early_larval_frame + 13b; // same_frame + }; + 246b, []{#11; #16}, { // early_larval_frame + 66b, []z{O,#84}; // same_locals_1_stack_item_frame + }; + 246b, []{#11}, { // early_larval_frame + 10b; // same_frame + }; + 246b, []{}, { // early_larval_frame + 8b; // same_frame + }; + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0009; // access + #123; // name_index + #124; // descriptor_index + [] { // Attributes + Attr(#119) { // Code + 3; // max_stack + 3; // max_locals + Bytes[]{ + 0xBB 0x00 0x0A 0x59 0xB7 0x00 0x60 0x4C 0x03 0x3D 0x1C 0x10; + 0x06 0xA3 0x00 0x0E 0x2B 0x1C 0xB6 0x00 0x61 0x84 0x02 0x01; + 0xA7 0xFF 0xF2 0x2B 0x03 0x12 0x65 0xB6 0x00 0x67 0x57 0x2B; + 0x10 0x17 0xB6 0x00 0x6B 0x57 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#120) { // StackMapTable + [] { // + 246b, []{}, { // early_larval_frame + 253b, 10, []z{O,#10; I}; // append_frame 2 + }; + 250b, 16; // chop_frame 1 + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0008; // access + #125; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#119) { // Code + 2; // max_stack + 0; // max_locals + Bytes[]{ + 0x0A 0xB3 0x00 0x6F 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#126) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #137; // bootstrap_method_ref + [] { // bootstrap_arguments + #127; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [] { // bootstrap_arguments + #129; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [] { // bootstrap_arguments + #131; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [] { // bootstrap_arguments + #133; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [] { // bootstrap_arguments + #135; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#143) { // InnerClasses + [] { // classes + #144 #146 #148 25; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.t.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.t.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.t.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData.t.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,644 @@ +package org/openjdk/asmtools/attribute/StackMapTable/data; + +public super class StackMapData version 69:0 +{ + static final Field fldI:I = int 0; + static Field fldL:J; + protected Field fldS:"Ljava/lang/String;"; + public final Field fldFS:"Ljava/lang/String;" = String "string"; + + public Method "":"()V" + stack 2 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + aload_0; + ldc String "string"; + putfield Field fldS:"Ljava/lang/String;"; + aload_0; + ldc String "string"; + putfield Field fldFS:"Ljava/lang/String;"; + return; + } + + public Method generateFrames:"(I)V" + stack 5 locals 10 + { + iconst_0; + istore_2; + aconst_null; + astore_3; + try T0, T1; + iconst_1; + iload_2; + idiv; + istore_2; + endtry T0,T1; + aload_3; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L44; + catch T0 java/lang/ArithmeticException; + try T2; + astore 4; + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_3; + endtry T2; + aload_3; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L44; + catch T1 #0; + catch T2 #0; + catch T3 #0; + try T3; + astore 5; + endtry T3; + aload_3; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + aload 5; + athrow; + L44: iload_2; + ifne L50; + aconst_null; + astore_3; + L50: iload_2; + lookupswitch { + 1: L76; + 2: L87; + default: L87 }; + L76: new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_3; + goto L87; + L87: iload_1; + ifne L99; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "frame"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L99: iload_1; + iconst_1; + if_icmpne L127; + bipush 42; + istore 4; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 4; + ldc float 100.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + imul; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(I)Ljava/lang/String;" { + String "item_frame\u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L127: iload_1; + iconst_2; + if_icmpne L184; + iconst_0; + istore 4; + iconst_0; + istore 5; + L138: iload 5; + sipush 3000; + if_icmpge L171; + ldc float 3.14f; + fstore 6; + iload 4; + fload 6; + ldc float 100.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + i2f; + fmul; + f2i; + iadd; + istore 4; + iinc 5, 1; + goto L138; + L171: getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 4; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(I)Ljava/lang/String;" { + String "item_frame_\u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L184: ldc float 10.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + istore 4; + iload_1; + iconst_3; + if_icmpne L232; + ldc float 110.0f; + invokestatic Method java/lang/Math.round:"(F)I"; + istore 5; + ldc2_w double 100.0d; + invokestatic Method java/lang/Math.round:"(D)J"; + lstore 6; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 5; + i2l; + lload 6; + ladd; + iload 4; + i2l; + lmul; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(J)Ljava/lang/String;" { + String "_frame: \u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L232: iload_1; + iconst_4; + if_icmpne L273; + bipush 50; + iload 4; + imul; + istore 5; + ldc2_w double 99.99d; + iload 4; + i2d; + dmul; + dstore 6; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 5; + i2d; + dload 6; + dadd; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(D)Ljava/lang/String;" { + String "Before chop_frame: \u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + goto L281; + L273: getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "chop_frame"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L281: iload_1; + iconst_5; + if_icmpne L379; + iconst_0; + istore 5; + iconst_0; + istore 6; + L292: iload 6; + sipush 2500; + if_icmpge L326; + ldc float 3.14f; + fstore 7; + iload 5; + fload 7; + iload 6; + i2f; + invokestatic Method java/lang/Math.round:"(F)I"; + i2f; + fmul; + f2i; + iadd; + istore 5; + iinc 6, 1; + goto L292; + L326: iload 5; + bipush 100; + if_icmple L344; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "_frame_"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + goto L379; + L344: iload 5; + bipush 50; + if_icmpge L379; + bipush 50; + iload 4; + imul; + istore 6; + ldc2_w double 99.99d; + iload 4; + i2d; + dmul; + dstore 7; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload 6; + i2d; + dload 7; + dadd; + invokevirtual Method java/io/PrintStream.println:"(D)V"; + L379: iload_1; + bipush 6; + if_icmpne L414; + ldc String "n_frame"; + astore 5; + bipush 70; + istore 6; + bipush 100; + istore 7; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + aload 5; + iload 6; + iload 7; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" { + String "\u0001: \u0001\u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + L414: iconst_0; + istore 5; + aconst_null; + astore 6; + try T4, T5; + iconst_1; + iload 5; + idiv; + istore 5; + endtry T4,T5; + aload 6; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L466; + catch T4 java/lang/ArithmeticException; + try T6; + astore 7; + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore 6; + endtry T6; + aload 6; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + goto L466; + catch T5 #0; + catch T6 #0; + catch T7 #0; + try T7; + astore 9; + endtry T7; + aload 6; + invokevirtual Method java/lang/Object.toString:"()Ljava/lang/String;"; + pop; + aload 9; + athrow; + L466: iload 5; + ifne L474; + aconst_null; + astore 6; + L474: iload_2; + lookupswitch { + 1: L500; + 2: L512; + default: L512 }; + L500: new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore 6; + goto L512; + L512: return; + StackMapTable: number_of_entries = 25 + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;"; ] { + frame_type = 255 // full + offset_delta = 16 + stack_map = [ class java/lang/ArithmeticException; ] + locals_map = [ class StackMapData, int, int, class java/lang/Object; ] + } + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;"; ] { + frame_type = 81 // same_locals_1_stack_item + stack_map = [ class java/lang/Throwable; ] + } + frame_type = 246 // early_larval + unset_fields = [ out:"Ljava/io/PrintStream;", + fldFS:"Ljava/lang/String;"; ] { + frame_type = 9 // same + } + frame_type = 5 // same + frame_type = 25 // same + frame_type = 10 // same + frame_type = 11 // same + frame_type = 27 // same + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 253 // append + offset_delta = 10 + locals_map = [ int, int; ] + } + frame_type = 250 // chop1 + offset_delta = 32 + frame_type = 250 // chop1 + offset_delta = 12 + frame_type = 252 // append + offset_delta = 47 + locals_map = [ int; ] + frame_type = 40 // same + frame_type = 7 // same + frame_type = 253 // append + offset_delta = 10 + locals_map = [ int, int; ] + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 250 // chop1 + offset_delta = 33 + } + frame_type = 17 // same + frame_type = 250 // chop1 + offset_delta = 34 + frame_type = 34 // same + frame_type = 255 // full + offset_delta = 20 + stack_map = [ class java/lang/ArithmeticException; ] + locals_map = [ class StackMapData, int, int, class java/lang/Object, int, int, class java/lang/Object; ] + frame_type = 83 // same_locals_1_stack_item + stack_map = [ class java/lang/Throwable; ] + frame_type = 10 // same + frame_type = 7 // same + frame_type = 25 // same + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; ] { + frame_type = 11 // same + } + } + + public Method complexMethod:"(ILjava/lang/Object;)I" + stack 3 locals 7 + { + iconst_0; + istore_3; + iconst_1; + istore 4; + aconst_null; + astore 5; + try T0; + iload_1; + ifle L47; + iload_1; + iconst_1; + iadd; + istore_3; + aload_2; + instanceof class java/lang/String; + ifeq L39; + aload_2; + checkcast class java/lang/String; + astore 5; + aload 5; + invokevirtual Method java/lang/Object.hashCode:"()I"; + istore 4; + iload 4; + endtry T0; + ireturn; + try T1; + L39: iload_3; + iconst_2; + imul; + istore 4; + goto L104; + L47: iload_1; + iconst_m1; + if_icmpne L70; + iload_1; + ineg; + istore_3; + iload_3; + iconst_3; + iadd; + istore 4; + new class java/lang/RuntimeException; + dup; + ldc String "Test exception"; + invokespecial Method java/lang/RuntimeException."":"(Ljava/lang/String;)V"; + athrow; + L70: iconst_0; + istore 6; + L73: iload 6; + iconst_2; + if_icmpge L104; + iload_3; + iload 6; + iadd; + istore_3; + iload_3; + iconst_1; + if_icmple L98; + iload_3; + iload 6; + isub; + istore 4; + goto L104; + L98: iinc 6, 1; + goto L73; + endtry T1; + L104: goto L118; + catch T0 java/lang/RuntimeException; + catch T1 java/lang/RuntimeException; + astore 6; + aload 6; + astore 5; + iload_3; + iconst_5; + iadd; + istore 4; + L118: iload_3; + iload 4; + iadd; + ireturn; + StackMapTable: number_of_entries = 8 + frame_type = 254 // append + offset_delta = 39 + locals_map = [ int, int, class java/lang/Object; ] + frame_type = 7 // same + frame_type = 22 // same + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; ] { + frame_type = 252 // append + offset_delta = 2 + locals_map = [ int; ] + } + frame_type = 24 // same + frame_type = 250 // chop1 + offset_delta = 5 + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; ] { + frame_type = 66 // same_locals_1_stack_item + stack_map = [ class java/lang/RuntimeException; ] + } + frame_type = 10 // same + } + + public Method generateFullFrame:"(I)I" + stack 3 locals 6 + { + iconst_0; + istore_2; + aconst_null; + astore_3; + iconst_0; + istore 4; + try T0; + iload_1; + ifle L25; + ldc String "positive"; + astore_3; + iconst_1; + istore 4; + aload_3; + invokevirtual Method java/lang/Object.hashCode:"()I"; + istore_2; + goto L39; + L25: iload_1; + iconst_2; + imul; + istore_2; + new class java/lang/RuntimeException; + dup; + ldc String "non-positive"; + invokespecial Method java/lang/RuntimeException."":"(Ljava/lang/String;)V"; + athrow; + endtry T0; + L39: goto L53; + catch T0 java/lang/RuntimeException; + astore 5; + aload 5; + astore_3; + iconst_0; + istore 4; + iload_1; + ineg; + istore_2; + L53: iload 4; + ifeq L62; + iload_2; + iconst_1; + iadd; + ireturn; + L62: getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "Computing result"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + iload_2; + ireturn; + StackMapTable: number_of_entries = 5 + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;", + fldL:"J"; ] { + frame_type = 254 // append + offset_delta = 25 + locals_map = [ int, class java/lang/Object, int; ] + } + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;", + out:"Ljava/io/PrintStream;"; ] { + frame_type = 13 // same + } + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;", + fldFS:"Ljava/lang/String;"; ] { + frame_type = 66 // same_locals_1_stack_item + stack_map = [ class java/lang/RuntimeException; ] + } + frame_type = 246 // early_larval + unset_fields = [ fldS:"Ljava/lang/String;"; ] { + frame_type = 10 // same + } + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 8 // same + } + } + + public static Method main:"([Ljava/lang/String;)V" + stack 3 locals 3 + { + new class StackMapData; + dup; + invokespecial Method "":"()V"; + astore_1; + iconst_0; + istore_2; + L10: iload_2; + bipush 6; + if_icmpgt L27; + aload_1; + iload_2; + invokevirtual Method generateFrames:"(I)V"; + iinc 2, 1; + goto L10; + L27: aload_1; + iconst_0; + ldc String "test"; + invokevirtual Method complexMethod:"(ILjava/lang/Object;)I"; + pop; + aload_1; + bipush 23; + invokevirtual Method generateFullFrame:"(I)I"; + pop; + return; + StackMapTable: number_of_entries = 2 + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 253 // append + offset_delta = 10 + locals_map = [ class StackMapData, int; ] + } + frame_type = 250 // chop1 + offset_delta = 16 + } + + static Method "":"()V" + stack 2 locals 0 + { + lconst_1; + putstatic Field fldL:"J"; + return; + } + + InnerClasses { + public static final Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + } + + BootstrapMethods { + 0: REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + String "item_frame\u0001"; + + 1: REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + String "item_frame_\u0001"; + + 2: REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + String "_frame: \u0001"; + + 3: REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + String "Before chop_frame: \u0001"; + + 4: REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + String "\u0001: \u0001\u0001"; + } +} // end Class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData01.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData01.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData01.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData01.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,759 @@ +package org/openjdk/asmtools/attribute/StackMapTable/data; + +public super class #10 /* StackMapData01 */ version 69:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = String #8; // "string" + const #8 = Utf8 "string"; + const #9 = Field #10.#11; // StackMapData01.fldS:"Ljava/lang/String;" + const #10 = class #12; // StackMapData01 + const #11 = NameAndType #13:#14; // fldS:"Ljava/lang/String;" + const #12 = Utf8 "org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData01"; + const #13 = Utf8 "fldS"; + const #14 = Utf8 "Ljava/lang/String;"; + const #15 = Field #10.#16; // StackMapData01.fldFS:"Ljava/lang/String;" + const #16 = NameAndType #17:#14; // fldFS:"Ljava/lang/String;" + const #17 = Utf8 "fldFS"; + const #18 = Method #2.#19; // java/lang/Object.toString:"()Ljava/lang/String;" + const #19 = NameAndType #20:#21; // toString:"()Ljava/lang/String;" + const #20 = Utf8 "toString"; + const #21 = Utf8 "()Ljava/lang/String;"; + const #22 = class #23; // java/lang/ArithmeticException + const #23 = Utf8 "java/lang/ArithmeticException"; + const #24 = Field #25.#26; // java/lang/System.out:"Ljava/io/PrintStream;" + const #25 = class #27; // java/lang/System + const #26 = NameAndType #28:#29; // out:"Ljava/io/PrintStream;" + const #27 = Utf8 "java/lang/System"; + const #28 = Utf8 "out"; + const #29 = Utf8 "Ljava/io/PrintStream;"; + const #30 = String #31; // "frame" + const #31 = Utf8 "frame"; + const #32 = Method #33.#34; // java/io/PrintStream.println:"(Ljava/lang/String;)V" + const #33 = class #35; // java/io/PrintStream + const #34 = NameAndType #36:#37; // println:"(Ljava/lang/String;)V" + const #35 = Utf8 "java/io/PrintStream"; + const #36 = Utf8 "println"; + const #37 = Utf8 "(Ljava/lang/String;)V"; + const #38 = float 100.0f; + const #39 = Method #40.#41; // java/lang/Math.round:"(F)I" + const #40 = class #42; // java/lang/Math + const #41 = NameAndType #43:#44; // round:"(F)I" + const #42 = Utf8 "java/lang/Math"; + const #43 = Utf8 "round"; + const #44 = Utf8 "(F)I"; + const #45 = InvokeDynamic 0:#46; // #0:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #46 = NameAndType #47:#48; // makeConcatWithConstants:"(I)Ljava/lang/String;" + const #47 = Utf8 "makeConcatWithConstants"; + const #48 = Utf8 "(I)Ljava/lang/String;"; + const #49 = float 3.14f; + const #50 = InvokeDynamic 1:#46; // #1:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #51 = float 10.0f; + const #52 = float 110.0f; + const #53 = double 100.0d; + const #55 = Method #40.#56; // java/lang/Math.round:"(D)J" + const #56 = NameAndType #43:#57; // round:"(D)J" + const #57 = Utf8 "(D)J"; + const #58 = InvokeDynamic 2:#59; // #2:makeConcatWithConstants:"(J)Ljava/lang/String;" + const #59 = NameAndType #47:#60; // makeConcatWithConstants:"(J)Ljava/lang/String;" + const #60 = Utf8 "(J)Ljava/lang/String;"; + const #61 = double 99.99d; + const #63 = InvokeDynamic 3:#64; // #3:makeConcatWithConstants:"(D)Ljava/lang/String;" + const #64 = NameAndType #47:#65; // makeConcatWithConstants:"(D)Ljava/lang/String;" + const #65 = Utf8 "(D)Ljava/lang/String;"; + const #66 = String #67; // "chop_frame" + const #67 = Utf8 "chop_frame"; + const #68 = String #69; // "_frame_" + const #69 = Utf8 "_frame_"; + const #70 = Method #33.#71; // java/io/PrintStream.println:"(D)V" + const #71 = NameAndType #36:#72; // println:"(D)V" + const #72 = Utf8 "(D)V"; + const #73 = String #74; // "n_frame" + const #74 = Utf8 "n_frame"; + const #75 = InvokeDynamic 4:#76; // #4:makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #76 = NameAndType #47:#77; // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #77 = Utf8 "(Ljava/lang/String;CI)Ljava/lang/String;"; + const #78 = class #79; // java/lang/String + const #79 = Utf8 "java/lang/String"; + const #80 = Method #2.#81; // java/lang/Object.hashCode:"()I" + const #81 = NameAndType #82:#83; // hashCode:"()I" + const #82 = Utf8 "hashCode"; + const #83 = Utf8 "()I"; + const #84 = class #85; // java/lang/RuntimeException + const #85 = Utf8 "java/lang/RuntimeException"; + const #86 = String #87; // "Test exception" + const #87 = Utf8 "Test exception"; + const #88 = Method #84.#89; // java/lang/RuntimeException."":"(Ljava/lang/String;)V" + const #89 = NameAndType #5:#37; // "":"(Ljava/lang/String;)V" + const #90 = String #91; // "positive" + const #91 = Utf8 "positive"; + const #92 = String #93; // "non-positive" + const #93 = Utf8 "non-positive"; + const #94 = String #95; // "Computing result" + const #95 = Utf8 "Computing result"; + const #96 = Method #10.#3; // StackMapData01."":"()V" + const #97 = Method #10.#98; // StackMapData01.generateFrames:"(I)V" + const #98 = NameAndType #99:#100; // generateFrames:"(I)V" + const #99 = Utf8 "generateFrames"; + const #100 = Utf8 "(I)V"; + const #101 = String #102; // "test" + const #102 = Utf8 "test"; + const #103 = Method #10.#104; // StackMapData01.complexMethod:"(ILjava/lang/Object;)I" + const #104 = NameAndType #105:#106; // complexMethod:"(ILjava/lang/Object;)I" + const #105 = Utf8 "complexMethod"; + const #106 = Utf8 "(ILjava/lang/Object;)I"; + const #107 = Method #10.#108; // StackMapData01.generateFullFrame:"(I)I" + const #108 = NameAndType #109:#110; // generateFullFrame:"(I)I" + const #109 = Utf8 "generateFullFrame"; + const #110 = Utf8 "(I)I"; + const #111 = Field #10.#112; // StackMapData01.fldL:"J" + const #112 = NameAndType #113:#114; // fldL:"J" + const #113 = Utf8 "fldL"; + const #114 = Utf8 "J"; + const #115 = Utf8 "fldI"; + const #116 = Utf8 "I"; + const #117 = Utf8 "ConstantValue"; + const #118 = int 0; + const #119 = Utf8 "Code"; + const #120 = Utf8 "StackMapTable"; + const #121 = class #122; // java/lang/Throwable + const #122 = Utf8 "java/lang/Throwable"; + const #123 = Utf8 "main"; + const #124 = Utf8 "([Ljava/lang/String;)V"; + const #125 = Utf8 ""; + const #126 = Utf8 "BootstrapMethods"; + const #127 = String #128; // "item_frame\u0001" + const #128 = Utf8 "item_frame\u0001"; + const #129 = String #130; // "item_frame_\u0001" + const #130 = Utf8 "item_frame_\u0001"; + const #131 = String #132; // "_frame: \u0001" + const #132 = Utf8 "_frame: \u0001"; + const #133 = String #134; // "Before chop_frame: \u0001" + const #134 = Utf8 "Before chop_frame: \u0001"; + const #135 = String #136; // "\u0001: \u0001\u0001" + const #136 = Utf8 "\u0001: \u0001\u0001"; + const #137 = MethodHandle 6:#138; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #138 = Method #139.#140; // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #139 = class #141; // java/lang/invoke/StringConcatFactory + const #140 = NameAndType #47:#142; // makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #141 = Utf8 "java/lang/invoke/StringConcatFactory"; + const #142 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + const #143 = Utf8 "InnerClasses"; + const #144 = class #145; // java/lang/invoke/MethodHandles$Lookup + const #145 = Utf8 "java/lang/invoke/MethodHandles$Lookup"; + const #146 = class #147; // java/lang/invoke/MethodHandles + const #147 = Utf8 "java/lang/invoke/MethodHandles"; + const #148 = Utf8 "Lookup"; + + static final Field #115:#116 = #118; // fldI:I = int 0 + static Field #113:#114; // fldL:J + protected Field #13:#14; // fldS:"Ljava/lang/String;" + public final Field #17:#14 = #7; // fldFS:"Ljava/lang/String;" = String "string" + + public Method #5:#6 // "":"()V" + stack 2 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: aload_0; + 5: ldc #7; // String "string" + 7: putfield #9; // Field fldS:"Ljava/lang/String;" + 10: aload_0; + 11: ldc #7; // String "string" + 13: putfield #15; // Field fldFS:"Ljava/lang/String;" + 16: return; + } + + public Method #99:#100 // generateFrames:"(I)V" + stack 5 locals 10 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + try T0, T1; + 4: iconst_1; + 5: iload_2; + 6: idiv; + 7: istore_2; + endtry T0,T1; + 8: aload_3; + 9: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 12: pop; + 13: goto 44; + catch T0 #22; // java/lang/ArithmeticException + try T2; + 16: stack_frame_type early_larval; // frame_type 246 + unset_fields #15, // Field #10.#16, + #16; // fldFS:"Ljava/lang/String;"; + frame_type full; // frame_type 255 + locals_map #10, 1, 1, #2; // class StackMapData01, int, int, class java/lang/Object; + stack_map #22; // class java/lang/ArithmeticException; + astore 4; + 18: new #2; // class java/lang/Object + 21: dup; + 22: invokespecial #1; // Method java/lang/Object."":"()V" + 25: astore_3; + endtry T2; + 26: aload_3; + 27: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 30: pop; + 31: goto 44; + catch T1 #0; // any + catch T2 #0; // any + catch T3 #0; // any + try T3; + 34: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16; // fldFS:"Ljava/lang/String;"; + frame_type stack1; // frame_type 81 + stack_map #121; // class java/lang/Throwable; + astore 5; + endtry T3; + 36: aload_3; + 37: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 40: pop; + 41: aload 5; + 43: athrow; + 44: stack_frame_type early_larval; // frame_type 246 + unset_fields #26, // out:"Ljava/io/PrintStream;", + #16; // fldFS:"Ljava/lang/String;"; + frame_type same; // frame_type 9 + iload_2; + 45: ifne 50; + 48: aconst_null; + 49: astore_3; + 50: stack_frame_type same; // frame_type 5 + iload_2; + 51: lookupswitch { // 2 + 1: 76; + 2: 87; + default: 87 }; + 76: stack_frame_type same; // frame_type 25 + new #2; // class java/lang/Object + 79: dup; + 80: invokespecial #1; // Method java/lang/Object."":"()V" + 83: astore_3; + 84: goto 87; + 87: stack_frame_type same; // frame_type 10 + iload_1; + 88: ifne 99; + 91: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 94: ldc #30; // String "frame" + 96: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 99: stack_frame_type same; // frame_type 11 + iload_1; + 100: iconst_1; + 101: if_icmpne 127; + 104: bipush 42; + 106: istore 4; + 108: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 111: iload 4; + 113: ldc #38; // float 100.0f + 115: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 118: imul; + 119: invokedynamic #45; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "item_frame\u0001" + // } + 124: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 127: stack_frame_type same; // frame_type 27 + iload_1; + 128: iconst_2; + 129: if_icmpne 184; + 132: iconst_0; + 133: istore 4; + 135: iconst_0; + 136: istore 5; + 138: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type append; // frame_type 253 + locals_map 1, 1; // int, int; + iload 5; + 140: sipush 3000; + 143: if_icmpge 171; + 146: ldc #49; // float 3.14f + 148: fstore 6; + 150: iload 4; + 152: fload 6; + 154: ldc #38; // float 100.0f + 156: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 159: i2f; + 160: fmul; + 161: f2i; + 162: iadd; + 163: istore 4; + 165: iinc 5, 1; + 168: goto 138; + 171: stack_frame_type chop1; // frame_type 250 + getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 174: iload 4; + 176: invokedynamic #50; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "item_frame_\u0001" + // } + 181: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 184: stack_frame_type chop1; // frame_type 250 + ldc #51; // float 10.0f + 186: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 189: istore 4; + 191: iload_1; + 192: iconst_3; + 193: if_icmpne 232; + 196: ldc #52; // float 110.0f + 198: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 201: istore 5; + 203: ldc2_w #53; // double 100.0d + 206: invokestatic #55; // Method java/lang/Math.round:"(D)J" + 209: lstore 6; + 211: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 214: iload 5; + 216: i2l; + 217: lload 6; + 219: ladd; + 220: iload 4; + 222: i2l; + 223: lmul; + 224: invokedynamic #58; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(J)Ljava/lang/String;" { + // String "_frame: \u0001" + // } + 229: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 232: stack_frame_type append; // frame_type 252 + locals_map 1; // int; + iload_1; + 233: iconst_4; + 234: if_icmpne 273; + 237: bipush 50; + 239: iload 4; + 241: imul; + 242: istore 5; + 244: ldc2_w #61; // double 99.99d + 247: iload 4; + 249: i2d; + 250: dmul; + 251: dstore 6; + 253: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 256: iload 5; + 258: i2d; + 259: dload 6; + 261: dadd; + 262: invokedynamic #63; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(D)Ljava/lang/String;" { + // String "Before chop_frame: \u0001" + // } + 267: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 270: goto 281; + 273: stack_frame_type same; // frame_type 40 + getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 276: ldc #66; // String "chop_frame" + 278: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 281: stack_frame_type same; // frame_type 7 + iload_1; + 282: iconst_5; + 283: if_icmpne 379; + 286: iconst_0; + 287: istore 5; + 289: iconst_0; + 290: istore 6; + 292: stack_frame_type append; // frame_type 253 + locals_map 1, 1; // int, int; + iload 6; + 294: sipush 2500; + 297: if_icmpge 326; + 300: ldc #49; // float 3.14f + 302: fstore 7; + 304: iload 5; + 306: fload 7; + 308: iload 6; + 310: i2f; + 311: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 314: i2f; + 315: fmul; + 316: f2i; + 317: iadd; + 318: istore 5; + 320: iinc 6, 1; + 323: goto 292; + 326: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type chop1; // frame_type 250 + iload 5; + 328: bipush 100; + 330: if_icmple 344; + 333: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 336: ldc #68; // String "_frame_" + 338: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 341: goto 379; + 344: stack_frame_type same; // frame_type 17 + iload 5; + 346: bipush 50; + 348: if_icmpge 379; + 351: bipush 50; + 353: iload 4; + 355: imul; + 356: istore 6; + 358: ldc2_w #61; // double 99.99d + 361: iload 4; + 363: i2d; + 364: dmul; + 365: dstore 7; + 367: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 370: iload 6; + 372: i2d; + 373: dload 7; + 375: dadd; + 376: invokevirtual #70; // Method java/io/PrintStream.println:"(D)V" + 379: stack_frame_type chop1; // frame_type 250 + iload_1; + 380: bipush 6; + 382: if_icmpne 414; + 385: ldc #73; // String "n_frame" + 387: astore 5; + 389: bipush 70; + 391: istore 6; + 393: bipush 100; + 395: istore 7; + 397: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 400: aload 5; + 402: iload 6; + 404: iload 7; + 406: invokedynamic #75; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 411: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 414: stack_frame_type same; // frame_type 34 + iconst_0; + 415: istore 5; + 417: aconst_null; + 418: astore 6; + try T4, T5; + 420: iconst_1; + 421: iload 5; + 423: idiv; + 424: istore 5; + endtry T4,T5; + 426: aload 6; + 428: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 431: pop; + 432: goto 466; + catch T4 #22; // java/lang/ArithmeticException + try T6; + 435: stack_frame_type full; // frame_type 255 + locals_map #10, 1, 1, #2, 1, 1, #2; // class StackMapData01, int, int, class java/lang/Object, int, int, class java/lang/Object; + stack_map #22; // class java/lang/ArithmeticException; + astore 7; + 437: new #2; // class java/lang/Object + 440: dup; + 441: invokespecial #1; // Method java/lang/Object."":"()V" + 444: astore 6; + endtry T6; + 446: aload 6; + 448: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 451: pop; + 452: goto 466; + catch T5 #0; // any + catch T6 #0; // any + catch T7 #0; // any + try T7; + 455: stack_frame_type stack1; // frame_type 83 + stack_map #121; // class java/lang/Throwable; + astore 9; + endtry T7; + 457: aload 6; + 459: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 462: pop; + 463: aload 9; + 465: athrow; + 466: stack_frame_type same; // frame_type 10 + iload 5; + 468: ifne 474; + 471: aconst_null; + 472: astore 6; + 474: stack_frame_type same; // frame_type 7 + iload_2; + 475: lookupswitch { // 2 + 1: 500; + 2: 512; + default: 512 }; + 500: stack_frame_type same; // frame_type 25 + new #2; // class java/lang/Object + 503: dup; + 504: invokespecial #1; // Method java/lang/Object."":"()V" + 507: astore 6; + 509: goto 512; + 512: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type same; // frame_type 11 + return; + } + + public Method #105:#106 // complexMethod:"(ILjava/lang/Object;)I" + stack 3 locals 7 + { + 0: iconst_0; + 1: istore_3; + 2: iconst_1; + 3: istore 4; + 5: aconst_null; + 6: astore 5; + try T0; + 8: iload_1; + 9: ifle 47; + 12: iload_1; + 13: iconst_1; + 14: iadd; + 15: istore_3; + 16: aload_2; + 17: instanceof #78; // class java/lang/String + 20: ifeq 39; + 23: aload_2; + 24: checkcast #78; // class java/lang/String + 27: astore 5; + 29: aload 5; + 31: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 34: istore 4; + 36: iload 4; + endtry T0; + 38: ireturn; + try T1; + 39: stack_frame_type append; // frame_type 254 + locals_map 1, 1, #2; // int, int, class java/lang/Object; + iload_3; + 40: iconst_2; + 41: imul; + 42: istore 4; + 44: goto 104; + 47: stack_frame_type same; // frame_type 7 + iload_1; + 48: iconst_m1; + 49: if_icmpne 70; + 52: iload_1; + 53: ineg; + 54: istore_3; + 55: iload_3; + 56: iconst_3; + 57: iadd; + 58: istore 4; + 60: new #84; // class java/lang/RuntimeException + 63: dup; + 64: ldc #86; // String "Test exception" + 66: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 69: athrow; + 70: stack_frame_type same; // frame_type 22 + iconst_0; + 71: istore 6; + 73: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type append; // frame_type 252 + locals_map 1; // int; + iload 6; + 75: iconst_2; + 76: if_icmpge 104; + 79: iload_3; + 80: iload 6; + 82: iadd; + 83: istore_3; + 84: iload_3; + 85: iconst_1; + 86: if_icmple 98; + 89: iload_3; + 90: iload 6; + 92: isub; + 93: istore 4; + 95: goto 104; + 98: stack_frame_type same; // frame_type 24 + iinc 6, 1; + 101: goto 73; + endtry T1; + 104: stack_frame_type chop1; // frame_type 250 + goto 118; + catch T0 #84; // java/lang/RuntimeException + catch T1 #84; // java/lang/RuntimeException + 107: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type stack1; // frame_type 66 + stack_map #84; // class java/lang/RuntimeException; + astore 6; + 109: aload 6; + 111: astore 5; + 113: iload_3; + 114: iconst_5; + 115: iadd; + 116: istore 4; + 118: stack_frame_type same; // frame_type 10 + iload_3; + 119: iload 4; + 121: iadd; + 122: ireturn; + } + + public Method #109:#110 // generateFullFrame:"(I)I" + stack 3 locals 6 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + 4: iconst_0; + 5: istore 4; + try T0; + 7: iload_1; + 8: ifle 25; + 11: ldc #90; // String "positive" + 13: astore_3; + 14: iconst_1; + 15: istore 4; + 17: aload_3; + 18: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 21: istore_2; + 22: goto 39; + 25: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26, // out:"Ljava/io/PrintStream;", + #112; // fldL:"J"; + frame_type append; // frame_type 254 + locals_map 1, #2, 1; // int, class java/lang/Object, int; + iload_1; + 26: iconst_2; + 27: imul; + 28: istore_2; + 29: new #84; // class java/lang/RuntimeException + 32: dup; + 33: ldc #92; // String "non-positive" + 35: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 38: athrow; + endtry T0; + 39: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16, // fldFS:"Ljava/lang/String;", + #26; // out:"Ljava/io/PrintStream;"; + frame_type same; // frame_type 13 + goto 53; + catch T0 #84; // java/lang/RuntimeException + 42: stack_frame_type early_larval; // frame_type 246 + unset_fields #11, // fldS:"Ljava/lang/String;", + #16; // fldFS:"Ljava/lang/String;"; + frame_type stack1; // frame_type 66 + stack_map #84; // class java/lang/RuntimeException; + astore 5; + 44: aload 5; + 46: astore_3; + 47: iconst_0; + 48: istore 4; + 50: iload_1; + 51: ineg; + 52: istore_2; + 53: stack_frame_type early_larval; // frame_type 246 + unset_fields #11; // fldS:"Ljava/lang/String;"; + frame_type same; // frame_type 10 + iload 4; + 55: ifeq 62; + 58: iload_2; + 59: iconst_1; + 60: iadd; + 61: ireturn; + 62: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type same; // frame_type 8 + getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 65: ldc #94; // String "Computing result" + 67: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 70: iload_2; + 71: ireturn; + } + + public static Method #123:#124 // main:"([Ljava/lang/String;)V" + stack 3 locals 3 + { + 0: new #10; // class StackMapData01 + 3: dup; + 4: invokespecial #96; // Method "":"()V" + 7: astore_1; + 8: iconst_0; + 9: istore_2; + 10: stack_frame_type early_larval; // frame_type 246 + unset_fields; + frame_type append; // frame_type 253 + locals_map #10, 1; // class StackMapData01, int; + iload_2; + 11: bipush 6; + 13: if_icmpgt 27; + 16: aload_1; + 17: iload_2; + 18: invokevirtual #97; // Method generateFrames:"(I)V" + 21: iinc 2, 1; + 24: goto 10; + 27: stack_frame_type chop1; // frame_type 250 + aload_1; + 28: iconst_0; + 29: ldc #101; // String "test" + 31: invokevirtual #103; // Method complexMethod:"(ILjava/lang/Object;)I" + 34: pop; + 35: aload_1; + 36: bipush 23; + 38: invokevirtual #107; // Method generateFullFrame:"(I)I" + 41: pop; + 42: return; + } + + static Method #125:#6 // "":"()V" + stack 2 locals 0 + { + 0: lconst_1; + 1: putstatic #111; // Field fldL:"J" + 4: return; + } + + InnerClass public static final #148 = #144 of #146; // Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #127 // String "item_frame\u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #129 // String "item_frame_\u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #131 // String "_frame: \u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #133 // String "Before chop_frame: \u0001" + } + + BootstrapMethod #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + { + #135 // String "\u0001: \u0001\u0001" + } +} // end Class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,768 @@ +package org/openjdk/asmtools/attribute/StackMapTable/data; + +public super class #10 /* StackMapData02 */ version 69:0 +{ + const #1 = Methodref #2.#3; // java/lang/Object."":"()V" + const #2 = Class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = String #8; // "string" + const #8 = Utf8 "string"; + const #9 = Fieldref #10.#11; // StackMapData02.fldS:"Ljava/lang/String;" + const #10 = Class #12; // StackMapData02 + const #11 = NameAndType #13:#14; // fldS:"Ljava/lang/String;" + const #12 = Utf8 "org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData02"; + const #13 = Utf8 "fldS"; + const #14 = Utf8 "Ljava/lang/String;"; + const #15 = Fieldref #10.#16; // StackMapData02.fldFS:"Ljava/lang/String;" + const #16 = NameAndType #17:#14; // fldFS:"Ljava/lang/String;" + const #17 = Utf8 "fldFS"; + const #18 = Methodref #2.#19; // java/lang/Object.toString:"()Ljava/lang/String;" + const #19 = NameAndType #20:#21; // toString:"()Ljava/lang/String;" + const #20 = Utf8 "toString"; + const #21 = Utf8 "()Ljava/lang/String;"; + const #22 = Class #23; // java/lang/ArithmeticException + const #23 = Utf8 "java/lang/ArithmeticException"; + const #24 = Fieldref #25.#26; // java/lang/System.out:"Ljava/io/PrintStream;" + const #25 = Class #27; // java/lang/System + const #26 = NameAndType #28:#29; // out:"Ljava/io/PrintStream;" + const #27 = Utf8 "java/lang/System"; + const #28 = Utf8 "out"; + const #29 = Utf8 "Ljava/io/PrintStream;"; + const #30 = String #31; // "frame" + const #31 = Utf8 "frame"; + const #32 = Methodref #33.#34; // java/io/PrintStream.println:"(Ljava/lang/String;)V" + const #33 = Class #35; // java/io/PrintStream + const #34 = NameAndType #36:#37; // println:"(Ljava/lang/String;)V" + const #35 = Utf8 "java/io/PrintStream"; + const #36 = Utf8 "println"; + const #37 = Utf8 "(Ljava/lang/String;)V"; + const #38 = Float 100.0f; + const #39 = Methodref #40.#41; // java/lang/Math.round:"(F)I" + const #40 = Class #42; // java/lang/Math + const #41 = NameAndType #43:#44; // round:"(F)I" + const #42 = Utf8 "java/lang/Math"; + const #43 = Utf8 "round"; + const #44 = Utf8 "(F)I"; + const #45 = InvokeDynamic 0:#46; // #0:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #46 = NameAndType #47:#48; // makeConcatWithConstants:"(I)Ljava/lang/String;" + const #47 = Utf8 "makeConcatWithConstants"; + const #48 = Utf8 "(I)Ljava/lang/String;"; + const #49 = Float 3.14f; + const #50 = InvokeDynamic 1:#46; // #1:makeConcatWithConstants:"(I)Ljava/lang/String;" + const #51 = Float 10.0f; + const #52 = Float 110.0f; + const #53 = Double 100.0d; + const #55 = Methodref #40.#56; // java/lang/Math.round:"(D)J" + const #56 = NameAndType #43:#57; // round:"(D)J" + const #57 = Utf8 "(D)J"; + const #58 = InvokeDynamic 2:#59; // #2:makeConcatWithConstants:"(J)Ljava/lang/String;" + const #59 = NameAndType #47:#60; // makeConcatWithConstants:"(J)Ljava/lang/String;" + const #60 = Utf8 "(J)Ljava/lang/String;"; + const #61 = Double 99.99d; + const #63 = InvokeDynamic 3:#64; // #3:makeConcatWithConstants:"(D)Ljava/lang/String;" + const #64 = NameAndType #47:#65; // makeConcatWithConstants:"(D)Ljava/lang/String;" + const #65 = Utf8 "(D)Ljava/lang/String;"; + const #66 = String #67; // "chop_frame" + const #67 = Utf8 "chop_frame"; + const #68 = String #69; // "_frame_" + const #69 = Utf8 "_frame_"; + const #70 = Methodref #33.#71; // java/io/PrintStream.println:"(D)V" + const #71 = NameAndType #36:#72; // println:"(D)V" + const #72 = Utf8 "(D)V"; + const #73 = String #74; // "n_frame" + const #74 = Utf8 "n_frame"; + const #75 = InvokeDynamic 4:#76; // #4:makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #76 = NameAndType #47:#77; // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" + const #77 = Utf8 "(Ljava/lang/String;CI)Ljava/lang/String;"; + const #78 = Class #79; // java/lang/String + const #79 = Utf8 "java/lang/String"; + const #80 = Methodref #2.#81; // java/lang/Object.hashCode:"()I" + const #81 = NameAndType #82:#83; // hashCode:"()I" + const #82 = Utf8 "hashCode"; + const #83 = Utf8 "()I"; + const #84 = Class #85; // java/lang/RuntimeException + const #85 = Utf8 "java/lang/RuntimeException"; + const #86 = String #87; // "Test exception" + const #87 = Utf8 "Test exception"; + const #88 = Methodref #84.#89; // java/lang/RuntimeException."":"(Ljava/lang/String;)V" + const #89 = NameAndType #5:#37; // "":"(Ljava/lang/String;)V" + const #90 = String #91; // "positive" + const #91 = Utf8 "positive"; + const #92 = String #93; // "non-positive" + const #93 = Utf8 "non-positive"; + const #94 = String #95; // "Computing result" + const #95 = Utf8 "Computing result"; + const #96 = Methodref #10.#3; // StackMapData02."":"()V" + const #97 = Methodref #10.#98; // StackMapData02.generateFrames:"(I)V" + const #98 = NameAndType #99:#100; // generateFrames:"(I)V" + const #99 = Utf8 "generateFrames"; + const #100 = Utf8 "(I)V"; + const #101 = String #102; // "test" + const #102 = Utf8 "test"; + const #103 = Methodref #10.#104; // StackMapData02.complexMethod:"(ILjava/lang/Object;)I" + const #104 = NameAndType #105:#106; // complexMethod:"(ILjava/lang/Object;)I" + const #105 = Utf8 "complexMethod"; + const #106 = Utf8 "(ILjava/lang/Object;)I"; + const #107 = Methodref #10.#108; // StackMapData02.generateFullFrame:"(I)I" + const #108 = NameAndType #109:#110; // generateFullFrame:"(I)I" + const #109 = Utf8 "generateFullFrame"; + const #110 = Utf8 "(I)I"; + const #111 = Fieldref #10.#112; // StackMapData02.fldL:"J" + const #112 = NameAndType #113:#114; // fldL:"J" + const #113 = Utf8 "fldL"; + const #114 = Utf8 "J"; + const #115 = Utf8 "fldI"; + const #116 = Utf8 "I"; + const #117 = Utf8 "ConstantValue"; + const #118 = Integer 0; + const #119 = Utf8 "Code"; + const #120 = Utf8 "StackMapTable"; + const #121 = Class #122; // java/lang/Throwable + const #122 = Utf8 "java/lang/Throwable"; + const #123 = Utf8 "main"; + const #124 = Utf8 "([Ljava/lang/String;)V"; + const #125 = Utf8 ""; + const #126 = Utf8 "BootstrapMethods"; + const #127 = String #128; // "item_frame\u0001" + const #128 = Utf8 "item_frame\u0001"; + const #129 = String #130; // "item_frame_\u0001" + const #130 = Utf8 "item_frame_\u0001"; + const #131 = String #132; // "_frame: \u0001" + const #132 = Utf8 "_frame: \u0001"; + const #133 = String #134; // "Before chop_frame: \u0001" + const #134 = Utf8 "Before chop_frame: \u0001"; + const #135 = String #136; // "\u0001: \u0001\u0001" + const #136 = Utf8 "\u0001: \u0001\u0001"; + const #137 = MethodHandle 6:#138; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #138 = Methodref #139.#140; // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #139 = Class #141; // java/lang/invoke/StringConcatFactory + const #140 = NameAndType #47:#142; // makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #141 = Utf8 "java/lang/invoke/StringConcatFactory"; + const #142 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + const #143 = Utf8 "InnerClasses"; + const #144 = Class #145; // java/lang/invoke/MethodHandles$Lookup + const #145 = Utf8 "java/lang/invoke/MethodHandles$Lookup"; + const #146 = Class #147; // java/lang/invoke/MethodHandles + const #147 = Utf8 "java/lang/invoke/MethodHandles"; + const #148 = Utf8 "Lookup"; + const #149 = Utf8 "SourceFile"; + const #150 = Utf8 "StackMapData02.g.t.jasm"; + + static final Field #115:#116 = #118; // fldI:I = int 0 + static Field #113:#114; // fldL:J + protected Field #13:#14; // fldS:"Ljava/lang/String;" + public final Field #17:#14 = #7; // fldFS:"Ljava/lang/String;" = String "string" + + public Method #5:#6 // "":"()V" + stack 2 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: aload_0; + 5: ldc #7; // String "string" + 7: putfield #9; // Field fldS:"Ljava/lang/String;" + 10: aload_0; + 11: ldc #7; // String "string" + 13: putfield #15; // Field fldFS:"Ljava/lang/String;" + 16: return; + } + + public Method #99:#100 // generateFrames:"(I)V" + stack 5 locals 10 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + try T0, T1; + 4: iconst_1; + 5: iload_2; + 6: idiv; + 7: istore_2; + endtry T0,T1; + 8: aload_3; + 9: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 12: pop; + 13: goto 44; + catch T0 #22; // java/lang/ArithmeticException + try T2; + 16: astore 4; + 18: new #2; // class java/lang/Object + 21: dup; + 22: invokespecial #1; // Method java/lang/Object."":"()V" + 25: astore_3; + endtry T2; + 26: aload_3; + 27: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 30: pop; + 31: goto 44; + catch T1 #0; // any + catch T2 #0; // any + catch T3 #0; // any + try T3; + 34: astore 5; + endtry T3; + 36: aload_3; + 37: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 40: pop; + 41: aload 5; + 43: athrow; + 44: iload_2; + 45: ifne 50; + 48: aconst_null; + 49: astore_3; + 50: iload_2; + 51: lookupswitch { // 2 + 1: 76; + 2: 87; + default: 87 }; + 76: new #2; // class java/lang/Object + 79: dup; + 80: invokespecial #1; // Method java/lang/Object."":"()V" + 83: astore_3; + 84: goto 87; + 87: iload_1; + 88: ifne 99; + 91: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 94: ldc #30; // String "frame" + 96: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 99: iload_1; + 100: iconst_1; + 101: if_icmpne 127; + 104: bipush 42; + 106: istore 4; + 108: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 111: iload 4; + 113: ldc #38; // float 100.0f + 115: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 118: imul; + 119: invokedynamic #45; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 124: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 127: iload_1; + 128: iconst_2; + 129: if_icmpne 184; + 132: iconst_0; + 133: istore 4; + 135: iconst_0; + 136: istore 5; + 138: iload 5; + 140: sipush 3000; + 143: if_icmpge 171; + 146: ldc #49; // float 3.14f + 148: fstore 6; + 150: iload 4; + 152: fload 6; + 154: ldc #38; // float 100.0f + 156: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 159: i2f; + 160: fmul; + 161: f2i; + 162: iadd; + 163: istore 4; + 165: iinc 5, 1; + 168: goto 138; + 171: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 174: iload 4; + 176: invokedynamic #50; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(I)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 181: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 184: ldc #51; // float 10.0f + 186: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 189: istore 4; + 191: iload_1; + 192: iconst_3; + 193: if_icmpne 232; + 196: ldc #52; // float 110.0f + 198: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 201: istore 5; + 203: ldc2_w #53; // double 100.0d + 206: invokestatic #55; // Method java/lang/Math.round:"(D)J" + 209: lstore 6; + 211: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 214: iload 5; + 216: i2l; + 217: lload 6; + 219: ladd; + 220: iload 4; + 222: i2l; + 223: lmul; + 224: invokedynamic #58; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(J)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 229: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 232: iload_1; + 233: iconst_4; + 234: if_icmpne 273; + 237: bipush 50; + 239: iload 4; + 241: imul; + 242: istore 5; + 244: ldc2_w #61; // double 99.99d + 247: iload 4; + 249: i2d; + 250: dmul; + 251: dstore 6; + 253: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 256: iload 5; + 258: i2d; + 259: dload 6; + 261: dadd; + 262: invokedynamic #63; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(D)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 267: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 270: goto 281; + 273: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 276: ldc #66; // String "chop_frame" + 278: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 281: iload_1; + 282: iconst_5; + 283: if_icmpne 379; + 286: iconst_0; + 287: istore 5; + 289: iconst_0; + 290: istore 6; + 292: iload 6; + 294: sipush 2500; + 297: if_icmpge 326; + 300: ldc #49; // float 3.14f + 302: fstore 7; + 304: iload 5; + 306: fload 7; + 308: iload 6; + 310: i2f; + 311: invokestatic #39; // Method java/lang/Math.round:"(F)I" + 314: i2f; + 315: fmul; + 316: f2i; + 317: iadd; + 318: istore 5; + 320: iinc 6, 1; + 323: goto 292; + 326: iload 5; + 328: bipush 100; + 330: if_icmple 344; + 333: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 336: ldc #68; // String "_frame_" + 338: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 341: goto 379; + 344: iload 5; + 346: bipush 50; + 348: if_icmpge 379; + 351: bipush 50; + 353: iload 4; + 355: imul; + 356: istore 6; + 358: ldc2_w #61; // double 99.99d + 361: iload 4; + 363: i2d; + 364: dmul; + 365: dstore 7; + 367: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 370: iload 6; + 372: i2d; + 373: dload 7; + 375: dadd; + 376: invokevirtual #70; // Method java/io/PrintStream.println:"(D)V" + 379: iload_1; + 380: bipush 6; + 382: if_icmpne 414; + 385: ldc #73; // String "n_frame" + 387: astore 5; + 389: bipush 70; + 391: istore 6; + 393: bipush 100; + 395: istore 7; + 397: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 400: aload 5; + 402: iload 6; + 404: iload 7; + 406: invokedynamic #75; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/String;CI)Ljava/lang/String;" { + // String "\u0001: \u0001\u0001" + // } + 411: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 414: iconst_0; + 415: istore 5; + 417: aconst_null; + 418: astore 6; + try T4, T5; + 420: iconst_1; + 421: iload 5; + 423: idiv; + 424: istore 5; + endtry T4,T5; + 426: aload 6; + 428: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 431: pop; + 432: goto 466; + catch T4 #22; // java/lang/ArithmeticException + try T6; + 435: astore 7; + 437: new #2; // class java/lang/Object + 440: dup; + 441: invokespecial #1; // Method java/lang/Object."":"()V" + 444: astore 6; + endtry T6; + 446: aload 6; + 448: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 451: pop; + 452: goto 466; + catch T5 #0; // any + catch T6 #0; // any + catch T7 #0; // any + try T7; + 455: astore 9; + endtry T7; + 457: aload 6; + 459: invokevirtual #18; // Method java/lang/Object.toString:"()Ljava/lang/String;" + 462: pop; + 463: aload 9; + 465: athrow; + 466: iload 5; + 468: ifne 474; + 471: aconst_null; + 472: astore 6; + 474: iload_2; + 475: lookupswitch { // 2 + 1: 500; + 2: 512; + default: 512 }; + 500: new #2; // class java/lang/Object + 503: dup; + 504: invokespecial #1; // Method java/lang/Object."":"()V" + 507: astore 6; + 509: goto 512; + 512: return; + StackMapTable: number_of_entries = 11 + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 255 // full + offset_delta = 16 + stack_map = [ #22; ] // class java/lang/ArithmeticException; + locals_map = [ #10, 1, 1, #2; ] // class StackMapData02, int, int, class java/lang/Object; + } + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 81 // same_locals_1_stack_item + stack_map = [ #121; ] // class java/lang/Throwable; + } + frame_type = 246 // early_larval + unset_fields = [ #26, // out:"Ljava/io/PrintStream;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 246 // early_larval + unset_fields = [ #11; ] { // fldS:"Ljava/lang/String;"; + frame_type = 255 // full + offset_delta = 16 + stack_map = [ #22; ] // class java/lang/ArithmeticException; + locals_map = [ #10, 1, 1, #2; ] // class StackMapData02, int, int, class java/lang/Object; + } + } + } + frame_type = 36 // same + frame_type = 11 // same + frame_type = 27 // same + frame_type = 252 // append + offset_delta = 104 + locals_map = [ 1; ] // int; + frame_type = 48 // same + frame_type = 250 // chop1 + offset_delta = 97 + frame_type = 34 // same + frame_type = 59 // same + } + + public Method #105:#106 // complexMethod:"(ILjava/lang/Object;)I" + stack 3 locals 7 + { + 0: iconst_0; + 1: istore_3; + 2: iconst_1; + 3: istore 4; + 5: aconst_null; + 6: astore 5; + try T0; + 8: iload_1; + 9: ifle 47; + 12: iload_1; + 13: iconst_1; + 14: iadd; + 15: istore_3; + 16: aload_2; + 17: instanceof #78; // class java/lang/String + 20: ifeq 39; + 23: aload_2; + 24: checkcast #78; // class java/lang/String + 27: astore 5; + 29: aload 5; + 31: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 34: istore 4; + 36: iload 4; + endtry T0; + 38: ireturn; + try T1; + 39: iload_3; + 40: iconst_2; + 41: imul; + 42: istore 4; + 44: goto 104; + 47: iload_1; + 48: iconst_m1; + 49: if_icmpne 70; + 52: iload_1; + 53: ineg; + 54: istore_3; + 55: iload_3; + 56: iconst_3; + 57: iadd; + 58: istore 4; + 60: new #84; // class java/lang/RuntimeException + 63: dup; + 64: ldc #86; // String "Test exception" + 66: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 69: athrow; + 70: iconst_0; + 71: istore 6; + 73: iload 6; + 75: iconst_2; + 76: if_icmpge 104; + 79: iload_3; + 80: iload 6; + 82: iadd; + 83: istore_3; + 84: iload_3; + 85: iconst_1; + 86: if_icmple 98; + 89: iload_3; + 90: iload 6; + 92: isub; + 93: istore 4; + 95: goto 104; + 98: iinc 6, 1; + 101: goto 73; + endtry T1; + 104: goto 118; + catch T0 #84; // java/lang/RuntimeException + catch T1 #84; // java/lang/RuntimeException + 107: astore 6; + 109: aload 6; + 111: astore 5; + 113: iload_3; + 114: iconst_5; + 115: iadd; + 116: istore 4; + 118: iload_3; + 119: iload 4; + 121: iadd; + 122: ireturn; + StackMapTable: number_of_entries = 8 + frame_type = 254 // append + offset_delta = 39 + locals_map = [ 1, 1, #2; ] // int, int, class java/lang/Object; + frame_type = 7 // same + frame_type = 22 // same + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26, // out:"Ljava/io/PrintStream;" + #112; ] { // fldL:"J" + frame_type = 252 // append + offset_delta = 2 + locals_map = [ 1; ] // int; + } + frame_type = 24 // same + frame_type = 250 // chop1 + offset_delta = 5 + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26, // out:"Ljava/io/PrintStream;" + #112; ] { // fldL:"J" + frame_type = 66 // same_locals_1_stack_item + stack_map = [ #84; ] // class java/lang/RuntimeException; + } + frame_type = 10 // same + } + + public Method #109:#110 // generateFullFrame:"(I)I" + stack 3 locals 6 + { + 0: iconst_0; + 1: istore_2; + 2: aconst_null; + 3: astore_3; + 4: iconst_0; + 5: istore 4; + try T0; + 7: iload_1; + 8: ifle 25; + 11: ldc #90; // String "positive" + 13: astore_3; + 14: iconst_1; + 15: istore 4; + 17: aload_3; + 18: invokevirtual #80; // Method java/lang/Object.hashCode:"()I" + 21: istore_2; + 22: goto 39; + 25: iload_1; + 26: iconst_2; + 27: imul; + 28: istore_2; + 29: new #84; // class java/lang/RuntimeException + 32: dup; + 33: ldc #92; // String "non-positive" + 35: invokespecial #88; // Method java/lang/RuntimeException."":"(Ljava/lang/String;)V" + 38: athrow; + endtry T0; + 39: goto 53; + catch T0 #84; // java/lang/RuntimeException + 42: astore 5; + 44: aload 5; + 46: astore_3; + 47: iconst_0; + 48: istore 4; + 50: iload_1; + 51: ineg; + 52: istore_2; + 53: iload 4; + 55: ifeq 62; + 58: iload_2; + 59: iconst_1; + 60: iadd; + 61: ireturn; + 62: getstatic #24; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 65: ldc #94; // String "Computing result" + 67: invokevirtual #32; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 70: iload_2; + 71: ireturn; + StackMapTable: number_of_entries = 5 + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26, // out:"Ljava/io/PrintStream;" + #112; ] { // fldL:"J" + frame_type = 254 // append + offset_delta = 25 + locals_map = [ 1, #2, 1; ] // int, class java/lang/Object, int; + } + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16, // fldFS:"Ljava/lang/String;" + #26; ] { // out:"Ljava/io/PrintStream;" + frame_type = 13 // same + } + frame_type = 246 // early_larval + unset_fields = [ #11, // fldS:"Ljava/lang/String;" + #16; ] { // fldFS:"Ljava/lang/String;" + frame_type = 66 // same_locals_1_stack_item + stack_map = [ #84; ] // class java/lang/RuntimeException; + } + frame_type = 246 // early_larval + unset_fields = [ #11; ] { // fldS:"Ljava/lang/String;"; + frame_type = 10 // same + } + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 8 // same + } + } + + public static Method #123:#124 // main:"([Ljava/lang/String;)V" + stack 3 locals 3 + { + 0: new #10; // class StackMapData02 + 3: dup; + 4: invokespecial #96; // Method "":"()V" + 7: astore_1; + 8: iconst_0; + 9: istore_2; + 10: iload_2; + 11: bipush 6; + 13: if_icmpgt 27; + 16: aload_1; + 17: iload_2; + 18: invokevirtual #97; // Method generateFrames:"(I)V" + 21: iinc 2, 1; + 24: goto 10; + 27: aload_1; + 28: iconst_0; + 29: ldc #101; // String "test" + 31: invokevirtual #103; // Method complexMethod:"(ILjava/lang/Object;)I" + 34: pop; + 35: aload_1; + 36: bipush 23; + 38: invokevirtual #107; // Method generateFullFrame:"(I)I" + 41: pop; + 42: return; + StackMapTable: number_of_entries = 2 + frame_type = 246 // early_larval + unset_fields = [ ] { + frame_type = 253 // append + offset_delta = 10 + locals_map = [ #10, 1; ] // class StackMapData02, int; + } + frame_type = 250 // chop1 + offset_delta = 16 + } + + static Method #125:#6 // "":"()V" + stack 2 locals 0 + { + 0: lconst_1; + 1: putstatic #111; // Field fldL:"J" + 4: return; + } + + SourceFile #150; // StackMapData02.g.t.jasm + + InnerClasses { + public static final #148 = #144 of #146; // Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + } + + BootstrapMethods { + 0: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #135; // String "\u0001: \u0001\u0001" + + 1: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #135; // String "\u0001: \u0001\u0001" + + 2: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #135; // String "\u0001: \u0001\u0001" + + 3: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #135; // String "\u0001: \u0001\u0001" + + 4: #137; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + Arguments: + #135; // String "\u0001: \u0001\u0001" + } +} // end Class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData02 compiled from "StackMapData02.g.t.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/attribute/StackMapTable/StackMapData02.g.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,510 @@ +class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData02 { + 0xCAFEBABE; + 0; // minor version + 69; // version + [151] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + Class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + String #8; // #7 at 0x39 + Utf8 "string"; // #8 at 0x3C + Field #10 #11; // #9 at 0x45 + Class #12; // #10 at 0x4A + NameAndType #13 #14; // #11 at 0x4D + Utf8 "org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData02"; // #12 at 0x52 + Utf8 "fldS"; // #13 at 0x95 + Utf8 "Ljava/lang/String;"; // #14 at 0x9C + Field #10 #16; // #15 at 0xB1 + NameAndType #17 #14; // #16 at 0xB6 + Utf8 "fldFS"; // #17 at 0xBB + Method #2 #19; // #18 at 0xC3 + NameAndType #20 #21; // #19 at 0xC8 + Utf8 "toString"; // #20 at 0xCD + Utf8 "()Ljava/lang/String;"; // #21 at 0xD8 + Class #23; // #22 at 0xEF + Utf8 "java/lang/ArithmeticException"; // #23 at 0xF2 + Field #25 #26; // #24 at 0x0112 + Class #27; // #25 at 0x0117 + NameAndType #28 #29; // #26 at 0x011A + Utf8 "java/lang/System"; // #27 at 0x011F + Utf8 "out"; // #28 at 0x0132 + Utf8 "Ljava/io/PrintStream;"; // #29 at 0x0138 + String #31; // #30 at 0x0150 + Utf8 "frame"; // #31 at 0x0153 + Method #33 #34; // #32 at 0x015B + Class #35; // #33 at 0x0160 + NameAndType #36 #37; // #34 at 0x0163 + Utf8 "java/io/PrintStream"; // #35 at 0x0168 + Utf8 "println"; // #36 at 0x017E + Utf8 "(Ljava/lang/String;)V"; // #37 at 0x0188 + Float 0x42C80000; // #38 at 0x01A0 + Method #40 #41; // #39 at 0x01A5 + Class #42; // #40 at 0x01AA + NameAndType #43 #44; // #41 at 0x01AD + Utf8 "java/lang/Math"; // #42 at 0x01B2 + Utf8 "round"; // #43 at 0x01C3 + Utf8 "(F)I"; // #44 at 0x01CB + InvokeDynamic 0s #46; // #45 at 0x01D2 + NameAndType #47 #48; // #46 at 0x01D7 + Utf8 "makeConcatWithConstants"; // #47 at 0x01DC + Utf8 "(I)Ljava/lang/String;"; // #48 at 0x01F6 + Float 0x4048F5C3; // #49 at 0x020E + InvokeDynamic 1s #46; // #50 at 0x0213 + Float 0x41200000; // #51 at 0x0218 + Float 0x42DC0000; // #52 at 0x021D + Double 0x4059000000000000;; // #53 at 0x0222 + Method #40 #56; // #55 at 0x022B + NameAndType #43 #57; // #56 at 0x0230 + Utf8 "(D)J"; // #57 at 0x0235 + InvokeDynamic 2s #59; // #58 at 0x023C + NameAndType #47 #60; // #59 at 0x0241 + Utf8 "(J)Ljava/lang/String;"; // #60 at 0x0246 + Double 0x4058FF5C28F5C28F;; // #61 at 0x025E + InvokeDynamic 3s #64; // #63 at 0x0267 + NameAndType #47 #65; // #64 at 0x026C + Utf8 "(D)Ljava/lang/String;"; // #65 at 0x0271 + String #67; // #66 at 0x0289 + Utf8 "chop_frame"; // #67 at 0x028C + String #69; // #68 at 0x0299 + Utf8 "_frame_"; // #69 at 0x029C + Method #33 #71; // #70 at 0x02A6 + NameAndType #36 #72; // #71 at 0x02AB + Utf8 "(D)V"; // #72 at 0x02B0 + String #74; // #73 at 0x02B7 + Utf8 "n_frame"; // #74 at 0x02BA + InvokeDynamic 4s #76; // #75 at 0x02C4 + NameAndType #47 #77; // #76 at 0x02C9 + Utf8 "(Ljava/lang/String;CI)Ljava/lang/String;"; // #77 at 0x02CE + Class #79; // #78 at 0x02F9 + Utf8 "java/lang/String"; // #79 at 0x02FC + Method #2 #81; // #80 at 0x030F + NameAndType #82 #83; // #81 at 0x0314 + Utf8 "hashCode"; // #82 at 0x0319 + Utf8 "()I"; // #83 at 0x0324 + Class #85; // #84 at 0x032A + Utf8 "java/lang/RuntimeException"; // #85 at 0x032D + String #87; // #86 at 0x034A + Utf8 "Test exception"; // #87 at 0x034D + Method #84 #89; // #88 at 0x035E + NameAndType #5 #37; // #89 at 0x0363 + String #91; // #90 at 0x0368 + Utf8 "positive"; // #91 at 0x036B + String #93; // #92 at 0x0376 + Utf8 "non-positive"; // #93 at 0x0379 + String #95; // #94 at 0x0388 + Utf8 "Computing result"; // #95 at 0x038B + Method #10 #3; // #96 at 0x039E + Method #10 #98; // #97 at 0x03A3 + NameAndType #99 #100; // #98 at 0x03A8 + Utf8 "generateFrames"; // #99 at 0x03AD + Utf8 "(I)V"; // #100 at 0x03BE + String #102; // #101 at 0x03C5 + Utf8 "test"; // #102 at 0x03C8 + Method #10 #104; // #103 at 0x03CF + NameAndType #105 #106; // #104 at 0x03D4 + Utf8 "complexMethod"; // #105 at 0x03D9 + Utf8 "(ILjava/lang/Object;)I"; // #106 at 0x03E9 + Method #10 #108; // #107 at 0x0402 + NameAndType #109 #110; // #108 at 0x0407 + Utf8 "generateFullFrame"; // #109 at 0x040C + Utf8 "(I)I"; // #110 at 0x0420 + Field #10 #112; // #111 at 0x0427 + NameAndType #113 #114; // #112 at 0x042C + Utf8 "fldL"; // #113 at 0x0431 + Utf8 "J"; // #114 at 0x0438 + Utf8 "fldI"; // #115 at 0x043C + Utf8 "I"; // #116 at 0x0443 + Utf8 "ConstantValue"; // #117 at 0x0447 + Integer 0x00000000; // #118 at 0x0457 + Utf8 "Code"; // #119 at 0x045C + Utf8 "StackMapTable"; // #120 at 0x0463 + Class #122; // #121 at 0x0473 + Utf8 "java/lang/Throwable"; // #122 at 0x0476 + Utf8 "main"; // #123 at 0x048C + Utf8 "([Ljava/lang/String;)V"; // #124 at 0x0493 + Utf8 ""; // #125 at 0x04AC + Utf8 "BootstrapMethods"; // #126 at 0x04B7 + String #128; // #127 at 0x04CA + Utf8 "item_frame\u0001"; // #128 at 0x04CD + String #130; // #129 at 0x04DB + Utf8 "item_frame_\u0001"; // #130 at 0x04DE + String #132; // #131 at 0x04ED + Utf8 "_frame: \u0001"; // #132 at 0x04F0 + String #134; // #133 at 0x04FC + Utf8 "Before chop_frame: \u0001"; // #134 at 0x04FF + String #136; // #135 at 0x0516 + Utf8 "\u0001: \u0001\u0001"; // #136 at 0x0519 + MethodHandle 6b #138; // #137 at 0x0521 + Method #139 #140; // #138 at 0x0525 + Class #141; // #139 at 0x052A + NameAndType #47 #142; // #140 at 0x052D + Utf8 "java/lang/invoke/StringConcatFactory"; // #141 at 0x0532 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #142 at 0x0559 + Utf8 "InnerClasses"; // #143 at 0x05F4 + Class #145; // #144 at 0x0603 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #145 at 0x0606 + Class #147; // #146 at 0x062E + Utf8 "java/lang/invoke/MethodHandles"; // #147 at 0x0631 + Utf8 "Lookup"; // #148 at 0x0652 + Utf8 "SourceFile"; // #149 at 0x065B + Utf8 "StackMapData02.g.t.jasm"; // #150 at 0x0668 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #10; // this_cpx + #2; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [4] { // Fields + { // field at 0x068C + 0x0018; // access + #115; // name_index : fldI + #116; // descriptor_index : I + [1] { // Attributes + Attr(#117, 2) { // ConstantValue at 0x0694 + #118; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field at 0x069C + 0x0008; // access + #113; // name_index : fldL + #114; // descriptor_index : J + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x06A4 + 0x0004; // access + #13; // name_index : fldS + #14; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x06AC + 0x0011; // access + #17; // name_index : fldFS + #14; // descriptor_index : Ljava/lang/String; + [1] { // Attributes + Attr(#117, 2) { // ConstantValue at 0x06B4 + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [6] { // Methods + { // method at 0x06BE + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#119, 29) { // Code at 0x06C6 + 2; // max_stack + 1; // max_locals + Bytes[17]{ + 0x2A 0xB7 0x00 0x01 0x2A 0x12 0x07 0xB5 0x00 0x09 0x2A 0x12; + 0x07 0xB5 0x00 0x0F 0xB1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x06E9 + 0x0001; // access + #99; // name_index : generateFrames + #100; // descriptor_index : (I)V + [1] { // Attributes + Attr(#119, 683) { // Code at 0x06F1 + 5; // max_stack + 10; // max_locals + Bytes[513]{ + 0x03 0x3D 0x01 0x4E 0x04 0x1C 0x6C 0x3D 0x2D 0xB6 0x00 0x12; + 0x57 0xA7 0x00 0x1F 0x3A 0x04 0xBB 0x00 0x02 0x59 0xB7 0x00; + 0x01 0x4E 0x2D 0xB6 0x00 0x12 0x57 0xA7 0x00 0x0D 0x3A 0x05; + 0x2D 0xB6 0x00 0x12 0x57 0x19 0x05 0xBF 0x1C 0x9A 0x00 0x05; + 0x01 0x4E 0x1C 0xAB 0x00 0x00 0x00 0x24 0x00 0x00 0x00 0x02; + 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x19 0x00 0x00 0x00 0x02; + 0x00 0x00 0x00 0x24 0xBB 0x00 0x02 0x59 0xB7 0x00 0x01 0x4E; + 0xA7 0x00 0x03 0x1B 0x9A 0x00 0x0B 0xB2 0x00 0x18 0x12 0x1E; + 0xB6 0x00 0x20 0x1B 0x04 0xA0 0x00 0x1A 0x10 0x2A 0x36 0x04; + 0xB2 0x00 0x18 0x15 0x04 0x12 0x26 0xB8 0x00 0x27 0x68 0xBA; + 0x00 0x2D 0x00 0x00 0xB6 0x00 0x20 0x1B 0x05 0xA0 0x00 0x37; + 0x03 0x36 0x04 0x03 0x36 0x05 0x15 0x05 0x11 0x0B 0xB8 0xA2; + 0x00 0x1C 0x12 0x31 0x38 0x06 0x15 0x04 0x17 0x06 0x12 0x26; + 0xB8 0x00 0x27 0x86 0x6A 0x8B 0x60 0x36 0x04 0x84 0x05 0x01; + 0xA7 0xFF 0xE2 0xB2 0x00 0x18 0x15 0x04 0xBA 0x00 0x32 0x00; + 0x00 0xB6 0x00 0x20 0x12 0x33 0xB8 0x00 0x27 0x36 0x04 0x1B; + 0x06 0xA0 0x00 0x27 0x12 0x34 0xB8 0x00 0x27 0x36 0x05 0x14; + 0x00 0x35 0xB8 0x00 0x37 0x37 0x06 0xB2 0x00 0x18 0x15 0x05; + 0x85 0x16 0x06 0x61 0x15 0x04 0x85 0x69 0xBA 0x00 0x3A 0x00; + 0x00 0xB6 0x00 0x20 0x1B 0x07 0xA0 0x00 0x27 0x10 0x32 0x15; + 0x04 0x68 0x36 0x05 0x14 0x00 0x3D 0x15 0x04 0x87 0x6B 0x39; + 0x06 0xB2 0x00 0x18 0x15 0x05 0x87 0x18 0x06 0x63 0xBA 0x00; + 0x3F 0x00 0x00 0xB6 0x00 0x20 0xA7 0x00 0x0B 0xB2 0x00 0x18; + 0x12 0x42 0xB6 0x00 0x20 0x1B 0x08 0xA0 0x00 0x60 0x03 0x36; + 0x05 0x03 0x36 0x06 0x15 0x06 0x11 0x09 0xC4 0xA2 0x00 0x1D; + 0x12 0x31 0x38 0x07 0x15 0x05 0x17 0x07 0x15 0x06 0x86 0xB8; + 0x00 0x27 0x86 0x6A 0x8B 0x60 0x36 0x05 0x84 0x06 0x01 0xA7; + 0xFF 0xE1 0x15 0x05 0x10 0x64 0xA4 0x00 0x0E 0xB2 0x00 0x18; + 0x12 0x44 0xB6 0x00 0x20 0xA7 0x00 0x26 0x15 0x05 0x10 0x32; + 0xA2 0x00 0x1F 0x10 0x32 0x15 0x04 0x68 0x36 0x06 0x14 0x00; + 0x3D 0x15 0x04 0x87 0x6B 0x39 0x07 0xB2 0x00 0x18 0x15 0x06; + 0x87 0x18 0x07 0x63 0xB6 0x00 0x46 0x1B 0x10 0x06 0xA0 0x00; + 0x20 0x12 0x49 0x3A 0x05 0x10 0x46 0x36 0x06 0x10 0x64 0x36; + 0x07 0xB2 0x00 0x18 0x19 0x05 0x15 0x06 0x15 0x07 0xBA 0x00; + 0x4B 0x00 0x00 0xB6 0x00 0x20 0x03 0x36 0x05 0x01 0x3A 0x06; + 0x04 0x15 0x05 0x6C 0x36 0x05 0x19 0x06 0xB6 0x00 0x12 0x57; + 0xA7 0x00 0x22 0x3A 0x07 0xBB 0x00 0x02 0x59 0xB7 0x00 0x01; + 0x3A 0x06 0x19 0x06 0xB6 0x00 0x12 0x57 0xA7 0x00 0x0E 0x3A; + 0x09 0x19 0x06 0xB6 0x00 0x12 0x57 0x19 0x09 0xBF 0x15 0x05; + 0x9A 0x00 0x06 0x01 0x3A 0x06 0x1C 0xAB 0x00 0x00 0x00 0x25; + 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x19; + 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x25 0xBB 0x00 0x02 0x59; + 0xB7 0x00 0x01 0x3A 0x06 0xA7 0x00 0x03 0xB1; + } + [8] { // Traps + 4 8 16 22; // at 0x090A + 4 8 34 0; // at 0x0912 + 16 26 34 0; // at 0x091A + 34 36 34 0; // at 0x0922 + 420 426 435 22; // at 0x092A + 420 426 455 0; // at 0x0932 + 435 446 455 0; // at 0x093A + 455 457 455 0; // at 0x0942 + } // end of Traps + [1] { // Attributes + Attr(#120, 88) { // StackMapTable at 0x0944 + [11] { // + 246b, [2]{#11; #16}, { // early_larval_frame + 255b, 16, [4]{7b,#10; 1b; 1b; 7b,#2}, [1]{7b,#22}; // full_frame + }; + 246b, [2]{#11; #16}, { // early_larval_frame + 81b, [1]z{7b,#121}; // same_locals_1_stack_item_frame + }; + 246b, [2]{#26; #16}, { // early_larval_frame + 246b, [2]{#11; #16}, { // early_larval_frame + 246b, [1]{#11}, { // early_larval_frame + 255b, 16, [4]{7b,#10; 1b; 1b; 7b,#2}, [1]{7b,#22}; // full_frame + }; + }; + }; + 36b; // same_frame + 11b; // same_frame + 27b; // same_frame + 252b, 104, [1]z{1b}; // append_frame 1 + 48b; // same_frame + 250b, 97; // chop_frame 1 + 34b; // same_frame + 59b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x09A2 + 0x0001; // access + #105; // name_index : complexMethod + #106; // descriptor_index : (ILjava/lang/Object;)I + [1] { // Attributes + Attr(#119, 204) { // Code at 0x09AA + 3; // max_stack + 7; // max_locals + Bytes[123]{ + 0x03 0x3E 0x04 0x36 0x04 0x01 0x3A 0x05 0x1B 0x9E 0x00 0x26; + 0x1B 0x04 0x60 0x3E 0x2C 0xC1 0x00 0x4E 0x99 0x00 0x13 0x2C; + 0xC0 0x00 0x4E 0x3A 0x05 0x19 0x05 0xB6 0x00 0x50 0x36 0x04; + 0x15 0x04 0xAC 0x1D 0x05 0x68 0x36 0x04 0xA7 0x00 0x3C 0x1B; + 0x02 0xA0 0x00 0x15 0x1B 0x74 0x3E 0x1D 0x06 0x60 0x36 0x04; + 0xBB 0x00 0x54 0x59 0x12 0x56 0xB7 0x00 0x58 0xBF 0x03 0x36; + 0x06 0x15 0x06 0x05 0xA2 0x00 0x1C 0x1D 0x15 0x06 0x60 0x3E; + 0x1D 0x04 0xA4 0x00 0x0C 0x1D 0x15 0x06 0x64 0x36 0x04 0xA7; + 0x00 0x09 0x84 0x06 0x01 0xA7 0xFF 0xE4 0xA7 0x00 0x0E 0x3A; + 0x06 0x19 0x06 0x3A 0x05 0x1D 0x08 0x60 0x36 0x04 0x1D 0x15; + 0x04 0x60 0xAC; + } + [2] { // Traps + 8 38 107 84; // at 0x0A3D + 39 104 107 84; // at 0x0A45 + } // end of Traps + [1] { // Attributes + Attr(#120, 47) { // StackMapTable at 0x0A47 + [8] { // + 254b, 39, [3]z{1b; 1b; 7b,#2}; // append_frame 3 + 7b; // same_frame + 22b; // same_frame + 246b, [4]{#11; #16; #26; #112}, { // early_larval_frame + 252b, 2, [1]z{1b}; // append_frame 1 + }; + 24b; // same_frame + 250b, 5; // chop_frame 1 + 246b, [4]{#11; #16; #26; #112}, { // early_larval_frame + 66b, [1]z{7b,#84}; // same_locals_1_stack_item_frame + }; + 10b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0A7C + 0x0001; // access + #109; // name_index : generateFullFrame + #110; // descriptor_index : (I)I + [1] { // Attributes + Attr(#119, 150) { // Code at 0x0A84 + 3; // max_stack + 6; // max_locals + Bytes[72]{ + 0x03 0x3D 0x01 0x4E 0x03 0x36 0x04 0x1B 0x9E 0x00 0x11 0x12; + 0x5A 0x4E 0x04 0x36 0x04 0x2D 0xB6 0x00 0x50 0x3D 0xA7 0x00; + 0x11 0x1B 0x05 0x68 0x3D 0xBB 0x00 0x54 0x59 0x12 0x5C 0xB7; + 0x00 0x58 0xBF 0xA7 0x00 0x0E 0x3A 0x05 0x19 0x05 0x4E 0x03; + 0x36 0x04 0x1B 0x74 0x3D 0x15 0x04 0x99 0x00 0x07 0x1C 0x04; + 0x60 0xAC 0xB2 0x00 0x18 0x12 0x5E 0xB6 0x00 0x20 0x1C 0xAC; + } + [1] { // Traps + 7 39 42 84; // at 0x0AE4 + } // end of Traps + [1] { // Attributes + Attr(#120, 52) { // StackMapTable at 0x0AE6 + [5] { // + 246b, [4]{#11; #16; #26; #112}, { // early_larval_frame + 254b, 25, [3]z{1b; 7b,#2; 1b}; // append_frame 3 + }; + 246b, [3]{#11; #16; #26}, { // early_larval_frame + 13b; // same_frame + }; + 246b, [2]{#11; #16}, { // early_larval_frame + 66b, [1]z{7b,#84}; // same_locals_1_stack_item_frame + }; + 246b, [1]{#11}, { // early_larval_frame + 10b; // same_frame + }; + 246b, [0]{}, { // early_larval_frame + 8b; // same_frame + }; + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0B20 + 0x0009; // access + #123; // name_index : main + #124; // descriptor_index : ([Ljava/lang/String;)V + [1] { // Attributes + Attr(#119, 76) { // Code at 0x0B28 + 3; // max_stack + 3; // max_locals + Bytes[43]{ + 0xBB 0x00 0x0A 0x59 0xB7 0x00 0x60 0x4C 0x03 0x3D 0x1C 0x10; + 0x06 0xA3 0x00 0x0E 0x2B 0x1C 0xB6 0x00 0x61 0x84 0x02 0x01; + 0xA7 0xFF 0xF2 0x2B 0x03 0x12 0x65 0xB6 0x00 0x67 0x57 0x2B; + 0x10 0x17 0xB6 0x00 0x6B 0x57 0xB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#120, 15) { // StackMapTable at 0x0B65 + [2] { // + 246b, [0]{}, { // early_larval_frame + 253b, 10, [2]z{7b,#10; 1b}; // append_frame 2 + }; + 250b, 16; // chop_frame 1 + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0B7A + 0x0008; // access + #125; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#119, 17) { // Code at 0x0B82 + 2; // max_stack + 0; // max_locals + Bytes[5]{ + 0x0A 0xB3 0x00 0x6F 0xB1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [3] { // Attributes + Attr(#149, 2) { // SourceFile at 0x0B9B + #150; + } // end of SourceFile + ; + Attr(#143, 10) { // InnerClasses at 0x0BA3 + [1] { // classes + #144 #146 #148 25; // access [ ACC_PUBLIC, ACC_STATIC, ACC_FINAL ] + } + } // end of InnerClasses + ; + Attr(#126, 32) { // BootstrapMethods at 0x0BB3 + [5] { // bootstrap_methods + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #135; // at 0x0BC1 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #135; // at 0x0BC7 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #135; // at 0x0BCD + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #135; // at 0x0BD3 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #137; // bootstrap_method_ref + [1] { // bootstrap_arguments + #135; // at 0x0BD9 + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + } // end of Attributes +} // end of class org/openjdk/asmtools/attribute/StackMapTable/data/StackMapData02 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/ConstantPoolTestDummy.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/ConstantPoolTestDummy.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/ConstantPoolTestDummy.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/ConstantPoolTestDummy.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk/internal/reflect/constantPool; + +super public #2; //class ConstantPoolTestDummy + version 52:0 +{ + +// Actually, only first 13 constant pool entries are actually used by the class +// and its methods. All the rest are added just for the testing of getTagAt method +// and getNameAndTypeRefIndexAt method. + +const #1 = Method #3.#10; // java/lang/Object."":"()V" +const #2 = class #11; // ConstantPoolTestDummy +const #3 = class #12; // java/lang/Object +const #4 = Asciz ""; +const #5 = Asciz "()V"; +const #6 = Asciz "Code"; +const #7 = Asciz "LineNumberTable"; +const #8 = Asciz "SourceFile"; +const #9 = Asciz "ConstantPoolTestDummy.java"; +const #10 = NameAndType #4:#5; // "":"()V" +const #11 = Asciz "jdk/internal/reflect/constantPool/ConstantPoolTestDummy"; +const #12 = Asciz "java/lang/Object"; +const #13 = long 6l; +const #15 = int 1; +const #16 = InterfaceMethod #17.#18; // java/lang/Runnable.run:"()V" +const #17 = class #19; // java/lang/Runnable +const #18 = NameAndType #20:#5; // run:"()V" +const #19 = Asciz "java/lang/Runnable"; +const #20 = Asciz "run"; +const #21 = double 1.45d; +const #23 = String #24; // "Hello" +const #24 = Asciz "Hello"; +const #25 = InvokeDynamic 0:#26; // REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":accept:"()Ljava/util/function/Consumer;" MethodType "(Ljava/lang/Object;)V", MethodHandle REF_invokeVirtual:java/lang/Object.toString:"()Ljava/lang/String;", MethodType "(Ljava/lang/Object;)V" +const #26 = NameAndType #27:#28; // accept:"()Ljava/util/function/Consumer;" +const #27 = Asciz "accept"; +const #28 = Asciz "()Ljava/util/function/Consumer;"; +const #29 = MethodHandle 6:#32; // REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +const #30 = MethodType #33; // "(Ljava/lang/Object;)V" +const #31 = MethodHandle 5:#34; // REF_invokeVirtual:java/lang/Object.toString:"()Ljava/lang/String;" +const #32 = Method #35.#36; // java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +const #33 = Asciz "(Ljava/lang/Object;)V"; +const #34 = Method #3.#37; // java/lang/Object.toString:"()Ljava/lang/String;" +const #35 = class #38; // java/lang/invoke/LambdaMetafactory +const #36 = NameAndType #39:#40; // metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +const #37 = NameAndType #41:#42; // toString:"()Ljava/lang/String;" +const #38 = Asciz "java/lang/invoke/LambdaMetafactory"; +const #39 = Asciz "metafactory"; +const #40 = Asciz "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; +const #41 = Asciz "toString"; +const #42 = Asciz "()Ljava/lang/String;"; +const #43 = class #46; // java/lang/invoke/MethodHandles$Lookup +const #44 = Asciz "Lookup"; +const #45 = class #47; // java/lang/invoke/MethodHandles +const #46 = Asciz "java/lang/invoke/MethodHandles$Lookup"; +const #47 = Asciz "java/lang/invoke/MethodHandles"; +const #48 = Field #2.#49; // jdk/internal/reflect/constantPool/ConstantPoolTestDummy.myField:"I" +const #49 = NameAndType #50:#51; // myField:"I" +const #50 = Asciz "myField"; +const #51 = Asciz "I"; +const #52 = float 1.34f; + +public Method #4:#5 // "":"()V" + + stack 1 locals 1 +{ +3 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V"; + 4: return; +} + +public static final InnerClass #44= #43 of #45; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + +BootstrapMethod #29 #30 #31 #30; + +} // end Class ConstantPoolTestDummy diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/EnclMethTest.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/EnclMethTest.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/EnclMethTest.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/EnclMethTest.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This test has a EnclosingMethod attribute with an illegal + * attribute_length field value of 6. This should cause a + * java.lang.ClassFormatError exception to be thrown. + */ + +class EnclMethTest { + 0xCAFEBABE; + 0; // minor version + 52; // version + [22] { // Constant Pool + ; // first element is empty + Field #3 #14; // #1 at 0x0A + Method #4 #15; // #2 at 0x0F + class #16; // #3 at 0x14 + class #19; // #4 at 0x17 + Utf8 "this$0"; // #5 at 0x1A + Utf8 "La;"; // #6 at 0x23 + Utf8 "Synthetic"; // #7 at 0x29 + Utf8 ""; // #8 at 0x35 + Utf8 "(Ljava/lang/Object;)V"; // #9 at 0x3E + Utf8 "Code"; // #10 at 0x56 + Utf8 "LineNumberTable"; // #11 at 0x5D + Utf8 "SourceFile"; // #12 at 0x6F + Utf8 "a.java"; // #13 at 0x7C + NameAndType #5 #6; // #14 at 0x85 + NameAndType #8 #20; // #15 at 0x8A + Utf8 "EnclMethTest"; // #16 at 0x8F + Utf8 "Loc"; // #17 at 0x9E + Utf8 "InnerClasses"; // #18 at 0xA4 + Utf8 "java/lang/Object"; // #19 at 0xB3 + Utf8 "()V"; // #20 at 0xC6 + Utf8 "EnclosingMethod"; // #21 at 0xCC + } // Constant Pool + + 0x0000; // access + #3;// this_cpx + #4;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [1] { // fields + { // Member at 0xE8 + 0x0000; // access + #5; // name_cpx + #6; // sig_cpx + [1] { // Attributes + Attr(#7, 0) { // Synthetic at 0xF0 + } // end Synthetic + } // Attributes + } // Member + } // fields + + [1] { // methods + { // Member at 0xF8 + 0x0001; // access + #8; // name_cpx + #20; // sig_cpx + [1] { // Attributes + Attr(#10, 17) { // Code at 0x0100 + 2; // max_stack + 2; // max_locals + Bytes[5]{ + 0x2AB70002B1; + }; + [0] { // Traps + } // end Traps + [0] { // Attributes + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [3] { // Attributes + Attr(#12, 2) { // SourceFile at 0x0119 + #13; + } // end SourceFile + ; + Attr(#18, 10) { // InnerClasses at 0x0121 + [1] { // InnerClasses + #3 #0 #17 0; // at 0x0131 + } + } // end InnerClasses + ; + Attr(#21, 6) { // EnclosingMethod at 0x0131 + // invalid length of EnclosingMethod attr: 6 (should be 4) !! + 0x0004000F; + } // end EnclosingMethod + } // Attributes +} // end class EnclMethTest diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/TestInterface01n01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/TestInterface01n01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/TestInterface01n01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/TestInterface01n01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + */ +package javasoft/sqe/tests/api/java/lang/invoke/MethodHandles/Lookup; + +interface TestInterface01n01 version 51:0 +{ + public static final Field iField:I = int 255; + + public abstract Method getTestResult:"()I"; + public Method xAA:"()I" + stack 1 locals 1 + { + sipush 170; + ireturn; + } + public static Method xBB:"()I" + stack 1 locals 0 + { + sipush 187; + ireturn; + } + +} // end Class TestInterface01n01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/atrcod00402m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/atrcod00402m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/atrcod00402m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/atrcod00402m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Ident: @(#)atrcod00402m1n.jcod generated from: @(#)atrcod00402m.jmpp 1.8 99/10/07 + * + * Copyright 1999 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + + + +class javasoft/sqe/tests/vm/classfmt/atr/atrcod004/atrcod00402m1/atrcod00402m1n { + 0xCAFEBABE; + 3; // minor version + 45; // version + + [] { // Constant Pool + ; // first element is empty + class #12; // #1 + class #6; // #2 + Method #1 #4; // #3 + NameAndType #14 #15; // #4 + Utf8 "ConstantValue"; // #5 + Utf8 "javasoft/sqe/tests/vm/classfmt/atr/atrcod004/atrcod00402m1/atrcod00402m1n"; // + Utf8 "Exceptions"; // #7 + Utf8 "LineNumberTable"; // #8 + Utf8 "SourceFile"; // #9 + Utf8 "LocalVariables"; // #10 + Utf8 "Code"; // #11 at 0x92 + Utf8 "java/lang/Object"; // #12 + Utf8 "attr003.jcod"; // #13 + Utf8 ""; // #14 + Utf8 "()V"; // #15 + } // Constant Pool + + 0x0001; // access + #2;// this_cpx + #1;// super_cpx + + [] { // Interfaces + } // Interfaces + + [] { // fields + } // fields + + [] { // methods + { // Member at 0xD4 + 0x0001; // access + #14; // name_cpx + #15; // sig_cpx + [] { // Attributes + Attr(#11) { // Code + 1; // max_stack + 1; // max_locals +/* right: + Bytes[5] { +end right */ +// wrong: + Bytes[10] { +// end wrong + 0x2AB70003B1; + }; + [] { // Traps + } // end Traps + [] { // Attributes + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [] { // Attributes + } // Attributes +} + + diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/module-info.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/module-info.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/module-info.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/module-info.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * Ident: @(#)module-info.jcod generated from:%W% %E% + * + * Copyright (c) 1996, 2018 Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +module module-info { + 0xCAFEBABE;// magic + 0;// minor class version + 53;// major class version + []s{ + { };// first element is empty + Utf8 "javasoft/sqe/jck/tests/vm/atrmmc00101m012/Main0012";// #1 + class #1;// #2 + Utf8 "module-info";// #3 + class #3;// #4 + Utf8 "Module";// #5 + Utf8 "module012";// #6 + Module #6;// #7 + Utf8 "java.base";// #8 + Module #8;// #9 + Utf8 "javasoft/sqe/jck/tests/vm/atrmmc00101m012";// #10 + Package #10;// #11 + Utf8 "ModuleMainClass";// #12 + Utf8 "UNUSED_DUMMY_ATTRIBUTE";// #13 + String #13;// #14 + }; + 0x8000;// module + #4;// this_class{"module-info"} + #0;// super_class#0 + // interfaces + []s{ + + }; + // fields + []s{ + + }; + // methods + []s{ + + }; + // class attributes + []s{ + // attribute "Module" + Attr(#5) { + #7;// module_name_index {"module012"} + 0x0000; + #0;// module_version_index #0 + // requires + []s{ + { #9 0x0020 #0 }; + }; + // exports + []s{ + { #11 0x0000 []s{} }; + }; + // opens + []s{ + { #11 0x0000 []s{} }; + }; + // uses + [0]s{ + + }; + // provides + [0]s{ + + }; + }; + //test attribute "ModuleMainClass" + //attribute_length, 1 less + Attr(#12, 1) { + #2;// {"javasoft/sqe/jck/tests/vm/atrmmc00101m012/Main0012"} + }; + + + }; +} // end of module-info diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/nonvoidinit.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/nonvoidinit.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/nonvoidinit.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/nonvoidinit.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org/openjdk/asmtools/sequence; + +// Interface containing non-void method. +public interface nonvoidinit version 50:0 +{ + public abstract Method "":"()I"; + +} // end Class nonvoidinit diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/stackmap00601m1n.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/stackmap00601m1n.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/stackmap00601m1n.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/stackmap00601m1n.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * Ident: @(#)stackmap00601m1n.jcod generated from: @(#)stackmap00601m.jmpp 1.9 06/06/06 + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + + + +class javasoft/sqe/tests/vm/cldc/classfmt/stackmap006/stackmap00601m1/stackmap00601m1n { + 0xCAFEBABE; + 0; + 50; + [] { // Constant Pool + ; // first element is empty + Method #3 #5; // #1 + Utf8 "StackMapTable"; // #2 + class #4; // #3 + Utf8 "java/lang/Object"; // #4 + NameAndType #10 #7; // #5 + Utf8 "SourceFile"; // #6 + Utf8 "()V"; // #7 + Utf8 "Code"; // #8 + Utf8 "a.jasm"; // #9 + Utf8 ""; // #10 + class #12; // #11 + Utf8 "javasoft/sqe/tests/vm/cldc/classfmt/stackmap006/stackmap00601m1/stackmap00601m1n"; // #12 + } // Constant Pool + + 0x0000; // access + #11;// this_cpx + #3;// super_cpx + + [] { // Interfaces + } // Interfaces + + [] { // fields + } // fields + + [] { // methods + { // Member + 0x0001; // access + #10; // name_cpx + #7; // sig_cpx + [] { // Attributes + Attr(#8) { // Code + 1; // max_stack + 1; // max_stack_items + Bytes[]{ + 0x2AB70001B1000000; + 0x0000000000B1; + }; + [] { // Traps + } // end Traps + [] { // Attributes + Attr(#2) { // StackMap + [] { // +/* right: + 255b, 5, []{}, []{B}; +end right */ +// wrong: + 255b, 5, []{}, [0]{B}; +// end wrong + } + } // end StackMap + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [] { // Attributes + Attr(#6) { // SourceFile + #9; + } // end SourceFile + } // Attributes +} // end class javasoft/sqe/tests/vm/cldc/classfmt/stackmap006/stackmap00601m1/stackmap00601m1n + + diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/voidinit.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/voidinit.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/voidinit.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/common/sequence/voidinit.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org/openjdk/asmtools/sequence; + +// Interface containing void method. +public interface voidinit version 50:0 +{ + public abstract Method "":"()V"; + +} // end Class voidinit diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +class #84 /* CondyNestedResolution */ version 55:0 +{ + const #1 = String #22; // "In bsm2arg" + const #2 = String #61; // "In bsm4arg" + const #3 = String #11; // "In bsm1arg" + const #4 = Dynamic 8:#12; // #8:name:"Ljava/lang/String;" + const #5 = Method #51.#10; // java/lang/Object."":"()V" + const #6 = Method #13.#39; // java/io/PrintStream.println:"(Ljava/lang/Object;)V" + const #7 = Field #50.#81; // java/lang/System.out:"Ljava/io/PrintStream;" + const #8 = Method #84.#45; // CondyNestedResolution.test_condy:"()V" + const #9 = Utf8 "java/io/PrintStream"; + const #10 = NameAndType #71:#47; // "":"()V" + const #11 = Utf8 "In bsm1arg"; + const #12 = NameAndType #18:#17; // name:"Ljava/lang/String;" + const #13 = class #9; // java/io/PrintStream + const #14 = Utf8 "SourceFile"; + const #15 = Utf8 "bsm3arg"; + const #16 = Utf8 "CondyNestedResolution.jasm"; + const #17 = Utf8 "Ljava/lang/String;"; + const #18 = Utf8 "name"; + const #19 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #20 = Utf8 "test_condy"; + const #21 = NameAndType #15:#19; // bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #22 = Utf8 "In bsm2arg"; + const #23 = Utf8 "Code"; + const #24 = Utf8 "([Ljava/lang/String;)V"; + const #25 = Utf8 "bsm4arg"; + const #26 = Utf8 "out"; + const #27 = NameAndType #69:#55; // bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #28 = Utf8 "BootstrapMethods"; + const #29 = MethodHandle 6:#44; // REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #30 = Method #84.#63; // CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #31 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #32 = Method #84.#27; // CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #33 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #34 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #35 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #36 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #37 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #38 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #39 = NameAndType #40:#41; // println:"(Ljava/lang/Object;)V" + const #40 = Utf8 "println"; + const #41 = Utf8 "(Ljava/lang/Object;)V"; + const #42 = Utf8 "java/lang/Object"; + const #43 = Utf8 "java/lang/System"; + const #44 = Method #84.#21; // CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #45 = NameAndType #20:#47; // test_condy:"()V" + const #46 = MethodHandle 6:#82; // REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #47 = Utf8 "()V"; + const #48 = String #62; // "hello6" + const #49 = String #64; // "hello5" + const #50 = class #43; // java/lang/System + const #51 = class #42; // java/lang/Object + const #52 = String #65; // "hello4" + const #53 = String #66; // "hello3" + const #54 = String #67; // "hello2" + const #55 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #56 = Utf8 "main"; + const #57 = String #68; // "hello1" + const #58 = MethodHandle 6:#32; // REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #59 = Utf8 "bsm1arg"; + const #60 = NameAndType #25:#83; // bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #61 = Utf8 "In bsm4arg"; + const #62 = Utf8 "hello6"; + const #63 = NameAndType #59:#31; // bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #64 = Utf8 "hello5"; + const #65 = Utf8 "hello4"; + const #66 = Utf8 "hello3"; + const #67 = Utf8 "hello2"; + const #68 = Utf8 "hello1"; + const #69 = Utf8 "bsm2arg"; + const #70 = Utf8 "Ljava/io/PrintStream;"; + const #71 = Utf8 ""; + const #72 = Utf8 "CondyNestedResolution"; + const #73 = Dynamic 7:#12; // #7:name:"Ljava/lang/String;" + const #74 = Dynamic 6:#12; // #6:name:"Ljava/lang/String;" + const #75 = Dynamic 5:#12; // #5:name:"Ljava/lang/String;" + const #76 = Dynamic 4:#12; // #4:name:"Ljava/lang/String;" + const #77 = Dynamic 3:#12; // #3:name:"Ljava/lang/String;" + const #78 = Dynamic 0:#12; // #0:name:"Ljava/lang/String;" + const #79 = Dynamic 1:#12; // #1:name:"Ljava/lang/String;" + const #80 = Dynamic 2:#12; // #2:name:"Ljava/lang/String;" + const #81 = NameAndType #26:#70; // out:"Ljava/io/PrintStream;" + const #82 = Method #84.#60; // CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #83 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #84 = class #72; // CondyNestedResolution + + public Method #71:#47 // "":"()V" + stack 1 locals 1 + { + 0: aload_0; + 1: invokespecial #5; // Method java/lang/Object."":"()V" + 4: return; + } + + public static Method #59:#31 // bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 4 locals 4 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #3; // String "In bsm1arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: aload_3; + 16: areturn; + } + + public static Method #69:#55 // bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 8 locals 8 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #1; // String "In bsm2arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 18: aload 4; + 20: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 23: aload_3; + 24: areturn; + } + + public static Method #15:#19 // bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 19 locals 19 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #2; // String "In bsm4arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 18: aload 4; + 20: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 23: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 26: aload 5; + 28: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 31: aload_3; + 32: areturn; + } + + public static Method #25:#83 // bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 19 locals 19 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #2; // String "In bsm4arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 18: aload 4; + 20: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 23: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 26: aload 5; + 28: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 31: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 34: aload 6; + 36: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 39: aload_3; + 40: areturn; + } + + public static Method #20:#47 // test_condy:"()V" + stack 12 locals 12 + { + 0: ldc #4; // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 0:#12; , + // Dynamic 1:#12; , + // Dynamic 6:#12; , + // Dynamic 7:#12; + // } + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + 2: return; + } + + public static Method #56:#24 // main:"([Ljava/lang/String;)V" + stack 2 locals 2 + { + 0: invokestatic #8; // Method test_condy:"()V" + 3: return; + } + + SourceFile #16; // CondyNestedResolution.jasm + + BootstrapMethod #36; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #57 // String "hello1" + } + + BootstrapMethod #37; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #54 // String "hello2" + } + + BootstrapMethod #38; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #52 // String "hello4" + } + + BootstrapMethod #35; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #48 // String "hello6" + } + + BootstrapMethod #58; // REF_invokeStatic:CondyNestedResolution.bsm2arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #77, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello6" + // } + #4 // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 0:#12; , + // Dynamic 1:#12; , + // Dynamic 6:#12; , + // Dynamic 7:#12; + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + } + + BootstrapMethod #34; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #49 // String "hello5" + } + + BootstrapMethod #29; // REF_invokeStatic:CondyNestedResolution.bsm3arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #80, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // } + #76, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 3:#12; , + // Dynamic 8:#12; + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello5" + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + // } + #75 // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + } + + BootstrapMethod #33; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #53 // String "hello3" + } + + BootstrapMethod #46; // REF_invokeStatic:CondyNestedResolution.bsm4arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + { + #78, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // } + #79, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // } + #74, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 2:#12; , + // Dynamic 4:#12; , + // Dynamic 5:#12; + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + // } + #73 // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + } +} // end Class CondyNestedResolution compiled from "CondyNestedResolution.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.t.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.t.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.t.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902696/CondyNestedResolution.g.t.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +class #84 /* CondyNestedResolution */ version 55:0 +{ + const #1 = String #22; // "In bsm2arg" + const #2 = String #61; // "In bsm4arg" + const #3 = String #11; // "In bsm1arg" + const #4 = Dynamic 8:#12; // #8:name:"Ljava/lang/String;" + const #5 = Methodref #51.#10; // java/lang/Object."":"()V" + const #6 = Methodref #13.#39; // java/io/PrintStream.println:"(Ljava/lang/Object;)V" + const #7 = Fieldref #50.#81; // java/lang/System.out:"Ljava/io/PrintStream;" + const #8 = Methodref #84.#45; // CondyNestedResolution.test_condy:"()V" + const #9 = Utf8 "java/io/PrintStream"; + const #10 = NameAndType #71:#47; // "":"()V" + const #11 = Utf8 "In bsm1arg"; + const #12 = NameAndType #18:#17; // name:"Ljava/lang/String;" + const #13 = Class #9; // java/io/PrintStream + const #14 = Utf8 "SourceFile"; + const #15 = Utf8 "bsm3arg"; + const #16 = Utf8 "CondyNestedResolution.jasm"; + const #17 = Utf8 "Ljava/lang/String;"; + const #18 = Utf8 "name"; + const #19 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #20 = Utf8 "test_condy"; + const #21 = NameAndType #15:#19; // bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #22 = Utf8 "In bsm2arg"; + const #23 = Utf8 "Code"; + const #24 = Utf8 "([Ljava/lang/String;)V"; + const #25 = Utf8 "bsm4arg"; + const #26 = Utf8 "out"; + const #27 = NameAndType #69:#55; // bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #28 = Utf8 "BootstrapMethods"; + const #29 = MethodHandle 6:#44; // REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #30 = Methodref #84.#63; // CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #31 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #32 = Methodref #84.#27; // CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #33 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #34 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #35 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #36 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #37 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #38 = MethodHandle 6:#30; // REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #39 = NameAndType #40:#41; // println:"(Ljava/lang/Object;)V" + const #40 = Utf8 "println"; + const #41 = Utf8 "(Ljava/lang/Object;)V"; + const #42 = Utf8 "java/lang/Object"; + const #43 = Utf8 "java/lang/System"; + const #44 = Methodref #84.#21; // CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #45 = NameAndType #20:#47; // test_condy:"()V" + const #46 = MethodHandle 6:#82; // REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #47 = Utf8 "()V"; + const #48 = String #62; // "hello6" + const #49 = String #64; // "hello5" + const #50 = Class #43; // java/lang/System + const #51 = Class #42; // java/lang/Object + const #52 = String #65; // "hello4" + const #53 = String #66; // "hello3" + const #54 = String #67; // "hello2" + const #55 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #56 = Utf8 "main"; + const #57 = String #68; // "hello1" + const #58 = MethodHandle 6:#32; // REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #59 = Utf8 "bsm1arg"; + const #60 = NameAndType #25:#83; // bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #61 = Utf8 "In bsm4arg"; + const #62 = Utf8 "hello6"; + const #63 = NameAndType #59:#31; // bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #64 = Utf8 "hello5"; + const #65 = Utf8 "hello4"; + const #66 = Utf8 "hello3"; + const #67 = Utf8 "hello2"; + const #68 = Utf8 "hello1"; + const #69 = Utf8 "bsm2arg"; + const #70 = Utf8 "Ljava/io/PrintStream;"; + const #71 = Utf8 ""; + const #72 = Utf8 "CondyNestedResolution"; + const #73 = Dynamic 7:#12; // #7:name:"Ljava/lang/String;" + const #74 = Dynamic 6:#12; // #6:name:"Ljava/lang/String;" + const #75 = Dynamic 5:#12; // #5:name:"Ljava/lang/String;" + const #76 = Dynamic 4:#12; // #4:name:"Ljava/lang/String;" + const #77 = Dynamic 3:#12; // #3:name:"Ljava/lang/String;" + const #78 = Dynamic 0:#12; // #0:name:"Ljava/lang/String;" + const #79 = Dynamic 1:#12; // #1:name:"Ljava/lang/String;" + const #80 = Dynamic 2:#12; // #2:name:"Ljava/lang/String;" + const #81 = NameAndType #26:#70; // out:"Ljava/io/PrintStream;" + const #82 = Methodref #84.#60; // CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + const #83 = Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + const #84 = Class #72; // CondyNestedResolution + + public Method #71:#47 // "":"()V" + stack 1 locals 1 + { + 0: aload_0; + 1: invokespecial #5; // Method java/lang/Object."":"()V" + 4: return; + } + + public static Method #59:#31 // bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 4 locals 4 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #3; // String "In bsm1arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: aload_3; + 16: areturn; + } + + public static Method #69:#55 // bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 8 locals 8 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #1; // String "In bsm2arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 18: aload 4; + 20: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 23: aload_3; + 24: areturn; + } + + public static Method #15:#19 // bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 19 locals 19 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #2; // String "In bsm4arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 18: aload 4; + 20: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 23: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 26: aload 5; + 28: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 31: aload_3; + 32: areturn; + } + + public static Method #25:#83 // bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + stack 19 locals 19 + { + 0: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #2; // String "In bsm4arg" + 5: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 8: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 11: aload_3; + 12: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 15: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 18: aload 4; + 20: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 23: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 26: aload 5; + 28: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 31: getstatic #7; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 34: aload 6; + 36: invokevirtual #6; // Method java/io/PrintStream.println:"(Ljava/lang/Object;)V" + 39: aload_3; + 40: areturn; + } + + public static Method #20:#47 // test_condy:"()V" + stack 12 locals 12 + { + 0: ldc #4; // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 0:#12; , + // Dynamic 1:#12; , + // Dynamic 6:#12; , + // Dynamic 7:#12; + // } + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + // }, + // Dynamic REF_invokeStatic:Method CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + 2: return; + } + + public static Method #56:#24 // main:"([Ljava/lang/String;)V" + stack 2 locals 2 + { + 0: invokestatic #8; // Method test_condy:"()V" + 3: return; + } + + SourceFile #16; // CondyNestedResolution.jasm + + BootstrapMethods { + 0: #36; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #57; // String "hello1" + + 1: #37; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #54; // String "hello2" + + 2: #38; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #52; // String "hello4" + + 3: #35; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #48; // String "hello6" + + 4: #58; // REF_invokeStatic:CondyNestedResolution.bsm2arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #77, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello6" + // } + #4; // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 0:#12; , + // Dynamic 1:#12; , + // Dynamic 6:#12; , + // Dynamic 7:#12; + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + + 5: #34; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #49; // String "hello5" + + 6: #29; // REF_invokeStatic:CondyNestedResolution.bsm3arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #80, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // } + #76, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 3:#12; , + // Dynamic 8:#12; + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello5" + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + // } + #75; // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + + 7: #33; // REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #53; // String "hello3" + + 8: #46; // REF_invokeStatic:CondyNestedResolution.bsm4arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + Arguments: + #78, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello1" + // } + #79, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello2" + // } + #74, // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello4" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm2arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello6" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm4arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello1" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello2" + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm3arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // Dynamic 2:#12; , + // Dynamic 4:#12; , + // Dynamic 5:#12; + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;":name:"Ljava/lang/String;" { + // String "hello3" + // } + // } + // }, + // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello5" + // } + // } + #73; // Dynamic REF_invokeStatic:CondyNestedResolution.bsm1arg: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;": + // name:"Ljava/lang/String;" { + // String "hello3" + // } + } +} // end Class CondyNestedResolution compiled from "CondyNestedResolution.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902820/InvalidSourceDebugExtension.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902820/InvalidSourceDebugExtension.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902820/InvalidSourceDebugExtension.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7902820/InvalidSourceDebugExtension.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +class invalid/InvalidSourceDebugExtension { + 0xCAFEBABE; + 0; // minor version + 55; // version + [15] { // Constant Pool + ; // first element is empty + Utf8 "invalid/InvalidSourceDebugExtension"; // #1 at 0x0A + Class #1; // #2 at 0x30 + Utf8 "java/lang/Object"; // #3 at 0x33 + Class #3; // #4 at 0x46 + Utf8 "InvalidSourceDebugExtension.java"; // #5 at 0x49 + Utf8 ""; // #6 at 0x6C + Utf8 "()V"; // #7 at 0x75 + NameAndType #6 #7; // #8 at 0x7B + Method #4 #8; // #9 at 0x80 + Utf8 "file"; // #10 at 0x85 + Utf8 "Code"; // #11 at 0x8C + Utf8 "LineNumberTable"; // #12 at 0x93 + Utf8 "SourceFile"; // #13 at 0xA5 + Utf8 "SourceDebugExtension"; // #14 at 0xB2 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #2; // this_cpx + #4; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [1] { // Methods + { // method at 0xD5 + 0x0001; // access + #6; // name_index : + #7; // descriptor_index : ()V + [1] { // Attributes + Attr(#11, 29) { // Code at 0xDD + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2A 0xB7 0x00 0x09 0xB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#12, 6) { // LineNumberTable at 0xF4 + [1] { // line_number_table + 0 30; // at 0x0100 + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [2] { // Attributes + Attr(#13, 2) { // SourceFile at 0x0102 + #10; + } // end of SourceFile + ; + Attr(#14, 2147483647) { // SourceDebugExtension at 0x010A + // == The attribute array started at at 0x010A has 2147483647 bytes more than expected. == + } // end of SourceDebugExtension + } // end of Attributes +} // end of class invalid/InvalidSourceDebugExtension diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,926 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +module #6 /* java.base */ version 65:0 +{ + const #1 = class #2; // module-info + const #2 = Utf8 "module-info"; + const #3 = Utf8 "SourceFile"; + const #4 = Utf8 "module-info.java"; + const #5 = Utf8 "Module"; + const #6 = Module #7; // java.base + const #7 = Utf8 "java.base"; + const #8 = Package #9; // java/io + const #9 = Utf8 "java/io"; + const #10 = Package #11; // java/lang + const #11 = Utf8 "java/lang"; + const #12 = Package #13; // java/lang/annotation + const #13 = Utf8 "java/lang/annotation"; + const #14 = Package #15; // java/lang/constant + const #15 = Utf8 "java/lang/constant"; + const #16 = Package #17; // java/lang/foreign + const #17 = Utf8 "java/lang/foreign"; + const #18 = Package #19; // java/lang/invoke + const #19 = Utf8 "java/lang/invoke"; + const #20 = Package #21; // java/lang/module + const #21 = Utf8 "java/lang/module"; + const #22 = Package #23; // java/lang/ref + const #23 = Utf8 "java/lang/ref"; + const #24 = Package #25; // java/lang/reflect + const #25 = Utf8 "java/lang/reflect"; + const #26 = Package #27; // java/lang/runtime + const #27 = Utf8 "java/lang/runtime"; + const #28 = Package #29; // java/math + const #29 = Utf8 "java/math"; + const #30 = Package #31; // java/net + const #31 = Utf8 "java/net"; + const #32 = Package #33; // java/net/spi + const #33 = Utf8 "java/net/spi"; + const #34 = Package #35; // java/nio + const #35 = Utf8 "java/nio"; + const #36 = Package #37; // java/nio/channels + const #37 = Utf8 "java/nio/channels"; + const #38 = Package #39; // java/nio/channels/spi + const #39 = Utf8 "java/nio/channels/spi"; + const #40 = Package #41; // java/nio/charset + const #41 = Utf8 "java/nio/charset"; + const #42 = Package #43; // java/nio/charset/spi + const #43 = Utf8 "java/nio/charset/spi"; + const #44 = Package #45; // java/nio/file + const #45 = Utf8 "java/nio/file"; + const #46 = Package #47; // java/nio/file/attribute + const #47 = Utf8 "java/nio/file/attribute"; + const #48 = Package #49; // java/nio/file/spi + const #49 = Utf8 "java/nio/file/spi"; + const #50 = Package #51; // java/security + const #51 = Utf8 "java/security"; + const #52 = Package #53; // java/security/cert + const #53 = Utf8 "java/security/cert"; + const #54 = Package #55; // java/security/interfaces + const #55 = Utf8 "java/security/interfaces"; + const #56 = Package #57; // java/security/spec + const #57 = Utf8 "java/security/spec"; + const #58 = Package #59; // java/text + const #59 = Utf8 "java/text"; + const #60 = Package #61; // java/text/spi + const #61 = Utf8 "java/text/spi"; + const #62 = Package #63; // java/time + const #63 = Utf8 "java/time"; + const #64 = Package #65; // java/time/chrono + const #65 = Utf8 "java/time/chrono"; + const #66 = Package #67; // java/time/format + const #67 = Utf8 "java/time/format"; + const #68 = Package #69; // java/time/temporal + const #69 = Utf8 "java/time/temporal"; + const #70 = Package #71; // java/time/zone + const #71 = Utf8 "java/time/zone"; + const #72 = Package #73; // java/util + const #73 = Utf8 "java/util"; + const #74 = Package #75; // java/util/concurrent + const #75 = Utf8 "java/util/concurrent"; + const #76 = Package #77; // java/util/concurrent/atomic + const #77 = Utf8 "java/util/concurrent/atomic"; + const #78 = Package #79; // java/util/concurrent/locks + const #79 = Utf8 "java/util/concurrent/locks"; + const #80 = Package #81; // java/util/function + const #81 = Utf8 "java/util/function"; + const #82 = Package #83; // java/util/jar + const #83 = Utf8 "java/util/jar"; + const #84 = Package #85; // java/util/random + const #85 = Utf8 "java/util/random"; + const #86 = Package #87; // java/util/regex + const #87 = Utf8 "java/util/regex"; + const #88 = Package #89; // java/util/spi + const #89 = Utf8 "java/util/spi"; + const #90 = Package #91; // java/util/stream + const #91 = Utf8 "java/util/stream"; + const #92 = Package #93; // java/util/zip + const #93 = Utf8 "java/util/zip"; + const #94 = Package #95; // javax/crypto + const #95 = Utf8 "javax/crypto"; + const #96 = Package #97; // javax/crypto/interfaces + const #97 = Utf8 "javax/crypto/interfaces"; + const #98 = Package #99; // javax/crypto/spec + const #99 = Utf8 "javax/crypto/spec"; + const #100 = Package #101; // javax/net + const #101 = Utf8 "javax/net"; + const #102 = Package #103; // javax/net/ssl + const #103 = Utf8 "javax/net/ssl"; + const #104 = Package #105; // javax/security/auth + const #105 = Utf8 "javax/security/auth"; + const #106 = Package #107; // javax/security/auth/callback + const #107 = Utf8 "javax/security/auth/callback"; + const #108 = Package #109; // javax/security/auth/login + const #109 = Utf8 "javax/security/auth/login"; + const #110 = Package #111; // javax/security/auth/spi + const #111 = Utf8 "javax/security/auth/spi"; + const #112 = Package #113; // javax/security/auth/x500 + const #113 = Utf8 "javax/security/auth/x500"; + const #114 = Package #115; // javax/security/cert + const #115 = Utf8 "javax/security/cert"; + const #116 = Package #117; // com/sun/crypto/provider + const #117 = Utf8 "com/sun/crypto/provider"; + const #118 = Module #119; // jdk.crypto.cryptoki + const #119 = Utf8 "jdk.crypto.cryptoki"; + const #120 = Package #121; // com/sun/security/ntlm + const #121 = Utf8 "com/sun/security/ntlm"; + const #122 = Module #123; // java.security.sasl + const #123 = Utf8 "java.security.sasl"; + const #124 = Package #125; // jdk/internal/access + const #125 = Utf8 "jdk/internal/access"; + const #126 = Module #127; // java.desktop + const #127 = Utf8 "java.desktop"; + const #128 = Module #129; // java.logging + const #129 = Utf8 "java.logging"; + const #130 = Module #131; // java.management + const #131 = Utf8 "java.management"; + const #132 = Module #133; // java.naming + const #133 = Utf8 "java.naming"; + const #134 = Module #135; // java.rmi + const #135 = Utf8 "java.rmi"; + const #136 = Module #137; // jdk.charsets + const #137 = Utf8 "jdk.charsets"; + const #138 = Module #139; // jdk.incubator.concurrent + const #139 = Utf8 "jdk.incubator.concurrent"; + const #140 = Module #141; // jdk.jartool + const #141 = Utf8 "jdk.jartool"; + const #142 = Module #143; // jdk.jfr + const #143 = Utf8 "jdk.jfr"; + const #144 = Module #145; // jdk.jlink + const #145 = Utf8 "jdk.jlink"; + const #146 = Module #147; // jdk.net + const #147 = Utf8 "jdk.net"; + const #148 = Module #149; // jdk.sctp + const #149 = Utf8 "jdk.sctp"; + const #150 = Package #151; // jdk/internal/classfile + const #151 = Utf8 "jdk/internal/classfile"; + const #152 = Module #153; // jdk.jshell + const #153 = Utf8 "jdk.jshell"; + const #154 = Package #155; // jdk/internal/classfile/attribute + const #155 = Utf8 "jdk/internal/classfile/attribute"; + const #156 = Package #157; // jdk/internal/classfile/constantpool + const #157 = Utf8 "jdk/internal/classfile/constantpool"; + const #158 = Package #159; // jdk/internal/classfile/instruction + const #159 = Utf8 "jdk/internal/classfile/instruction"; + const #160 = Package #161; // jdk/internal/event + const #161 = Utf8 "jdk/internal/event"; + const #162 = Package #163; // jdk/internal/foreign + const #163 = Utf8 "jdk/internal/foreign"; + const #164 = Module #165; // jdk.incubator.vector + const #165 = Utf8 "jdk.incubator.vector"; + const #166 = Package #167; // jdk/internal/io + const #167 = Utf8 "jdk/internal/io"; + const #168 = Module #169; // jdk.internal.le + const #169 = Utf8 "jdk.internal.le"; + const #170 = Package #171; // jdk/internal/javac + const #171 = Utf8 "jdk/internal/javac"; + const #172 = Module #173; // java.compiler + const #173 = Utf8 "java.compiler"; + const #174 = Module #175; // jdk.compiler + const #175 = Utf8 "jdk.compiler"; + const #176 = Module #177; // jdk.jdi + const #177 = Utf8 "jdk.jdi"; + const #178 = Module #179; // jdk.management + const #179 = Utf8 "jdk.management"; + const #180 = Package #181; // jdk/internal/jimage + const #181 = Utf8 "jdk/internal/jimage"; + const #182 = Package #183; // jdk/internal/jimage/decompressor + const #183 = Utf8 "jdk/internal/jimage/decompressor"; + const #184 = Package #185; // jdk/internal/jmod + const #185 = Utf8 "jdk/internal/jmod"; + const #186 = Package #187; // jdk/internal/loader + const #187 = Utf8 "jdk/internal/loader"; + const #188 = Module #189; // java.instrument + const #189 = Utf8 "java.instrument"; + const #190 = Package #191; // jdk/internal/logger + const #191 = Utf8 "jdk/internal/logger"; + const #192 = Package #193; // jdk/internal/misc + const #193 = Utf8 "jdk/internal/misc"; + const #194 = Module #195; // java.net.http + const #195 = Utf8 "java.net.http"; + const #196 = Module #197; // java.security.jgss + const #197 = Utf8 "java.security.jgss"; + const #198 = Module #199; // jdk.attach + const #199 = Utf8 "jdk.attach"; + const #200 = Module #201; // jdk.internal.vm.ci + const #201 = Utf8 "jdk.internal.vm.ci"; + const #202 = Module #203; // jdk.nio.mapmode + const #203 = Utf8 "jdk.nio.mapmode"; + const #204 = Module #205; // jdk.unsupported + const #205 = Utf8 "jdk.unsupported"; + const #206 = Package #207; // jdk/internal/module + const #207 = Utf8 "jdk/internal/module"; + const #208 = Module #209; // java.management.rmi + const #209 = Utf8 "java.management.rmi"; + const #210 = Module #211; // jdk.jpackage + const #211 = Utf8 "jdk.jpackage"; + const #212 = Package #213; // jdk/internal/org/objectweb/asm + const #213 = Utf8 "jdk/internal/org/objectweb/asm"; + const #214 = Package #215; // jdk/internal/org/objectweb/asm/commons + const #215 = Utf8 "jdk/internal/org/objectweb/asm/commons"; + const #216 = Package #217; // jdk/internal/org/objectweb/asm/tree + const #217 = Utf8 "jdk/internal/org/objectweb/asm/tree"; + const #218 = Package #219; // jdk/internal/org/objectweb/asm/util + const #219 = Utf8 "jdk/internal/org/objectweb/asm/util"; + const #220 = Package #221; // jdk/internal/org/xml/sax + const #221 = Utf8 "jdk/internal/org/xml/sax"; + const #222 = Package #223; // jdk/internal/org/xml/sax/helpers + const #223 = Utf8 "jdk/internal/org/xml/sax/helpers"; + const #224 = Package #225; // jdk/internal/perf + const #225 = Utf8 "jdk/internal/perf"; + const #226 = Module #227; // jdk.internal.jvmstat + const #227 = Utf8 "jdk.internal.jvmstat"; + const #228 = Module #229; // jdk.management.agent + const #229 = Utf8 "jdk.management.agent"; + const #230 = Package #231; // jdk/internal/platform + const #231 = Utf8 "jdk/internal/platform"; + const #232 = Package #233; // jdk/internal/ref + const #233 = Utf8 "jdk/internal/ref"; + const #234 = Package #235; // jdk/internal/reflect + const #235 = Utf8 "jdk/internal/reflect"; + const #236 = Module #237; // java.sql + const #237 = Utf8 "java.sql"; + const #238 = Module #239; // java.sql.rowset + const #239 = Utf8 "java.sql.rowset"; + const #240 = Module #241; // jdk.dynalink + const #241 = Utf8 "jdk.dynalink"; + const #242 = Package #243; // jdk/internal/util + const #243 = Utf8 "jdk/internal/util"; + const #244 = Package #245; // jdk/internal/util/jar + const #245 = Utf8 "jdk/internal/util/jar"; + const #246 = Package #247; // jdk/internal/util/random + const #247 = Utf8 "jdk/internal/util/random"; + const #248 = Module #249; // jdk.random + const #249 = Utf8 "jdk.random"; + const #250 = Package #251; // jdk/internal/util/xml + const #251 = Utf8 "jdk/internal/util/xml"; + const #252 = Package #253; // jdk/internal/util/xml/impl + const #253 = Utf8 "jdk/internal/util/xml/impl"; + const #254 = Package #255; // jdk/internal/vm + const #255 = Utf8 "jdk/internal/vm"; + const #256 = Package #257; // jdk/internal/vm/annotation + const #257 = Utf8 "jdk/internal/vm/annotation"; + const #258 = Package #259; // jdk/internal/vm/vector + const #259 = Utf8 "jdk/internal/vm/vector"; + const #260 = Package #261; // sun/invoke/util + const #261 = Utf8 "sun/invoke/util"; + const #262 = Package #263; // sun/net + const #263 = Utf8 "sun/net"; + const #264 = Module #265; // jdk.naming.dns + const #265 = Utf8 "jdk.naming.dns"; + const #266 = Package #267; // sun/net/dns + const #267 = Utf8 "sun/net/dns"; + const #268 = Package #269; // sun/net/ext + const #269 = Utf8 "sun/net/ext"; + const #270 = Package #271; // sun/net/util + const #271 = Utf8 "sun/net/util"; + const #272 = Module #273; // jdk.jconsole + const #273 = Utf8 "jdk.jconsole"; + const #274 = Package #275; // sun/net/www + const #275 = Utf8 "sun/net/www"; + const #276 = Package #277; // sun/net/www/protocol/http + const #277 = Utf8 "sun/net/www/protocol/http"; + const #278 = Package #279; // sun/nio/ch + const #279 = Utf8 "sun/nio/ch"; + const #280 = Package #281; // sun/nio/cs + const #281 = Utf8 "sun/nio/cs"; + const #282 = Package #283; // sun/nio/fs + const #283 = Utf8 "sun/nio/fs"; + const #284 = Package #285; // sun/reflect/annotation + const #285 = Utf8 "sun/reflect/annotation"; + const #286 = Package #287; // sun/reflect/generics/reflectiveObjects + const #287 = Utf8 "sun/reflect/generics/reflectiveObjects"; + const #288 = Package #289; // sun/reflect/misc + const #289 = Utf8 "sun/reflect/misc"; + const #290 = Module #291; // java.datatransfer + const #291 = Utf8 "java.datatransfer"; + const #292 = Package #293; // sun/security/action + const #293 = Utf8 "sun/security/action"; + const #294 = Module #295; // jdk.crypto.ec + const #295 = Utf8 "jdk.crypto.ec"; + const #296 = Package #297; // sun/security/internal/interfaces + const #297 = Utf8 "sun/security/internal/interfaces"; + const #298 = Package #299; // sun/security/internal/spec + const #299 = Utf8 "sun/security/internal/spec"; + const #300 = Package #301; // sun/security/jca + const #301 = Utf8 "sun/security/jca"; + const #302 = Module #303; // java.smartcardio + const #303 = Utf8 "java.smartcardio"; + const #304 = Package #305; // sun/security/pkcs + const #305 = Utf8 "sun/security/pkcs"; + const #306 = Package #307; // sun/security/provider + const #307 = Utf8 "sun/security/provider"; + const #308 = Module #309; // jdk.security.auth + const #309 = Utf8 "jdk.security.auth"; + const #310 = Package #311; // sun/security/provider/certpath + const #311 = Utf8 "sun/security/provider/certpath"; + const #312 = Package #313; // sun/security/rsa + const #313 = Utf8 "sun/security/rsa"; + const #314 = Package #315; // sun/security/timestamp + const #315 = Utf8 "sun/security/timestamp"; + const #316 = Package #317; // sun/security/tools + const #317 = Utf8 "sun/security/tools"; + const #318 = Package #319; // sun/security/util + const #319 = Utf8 "sun/security/util"; + const #320 = Module #321; // java.xml.crypto + const #321 = Utf8 "java.xml.crypto"; + const #322 = Module #323; // jdk.security.jgss + const #323 = Utf8 "jdk.security.jgss"; + const #324 = Package #325; // sun/security/util/math + const #325 = Utf8 "sun/security/util/math"; + const #326 = Package #327; // sun/security/util/math/intpoly + const #327 = Utf8 "sun/security/util/math/intpoly"; + const #328 = Package #329; // sun/security/validator + const #329 = Utf8 "sun/security/validator"; + const #330 = Package #331; // sun/security/x509 + const #331 = Utf8 "sun/security/x509"; + const #332 = Package #333; // sun/util/cldr + const #333 = Utf8 "sun/util/cldr"; + const #334 = Package #335; // sun/util/locale/provider + const #335 = Utf8 "sun/util/locale/provider"; + const #336 = Module #337; // jdk.localedata + const #337 = Utf8 "jdk.localedata"; + const #338 = Package #339; // sun/util/logging + const #339 = Utf8 "sun/util/logging"; + const #340 = Module #341; // java.prefs + const #341 = Utf8 "java.prefs"; + const #342 = Package #343; // sun/util/resources + const #343 = Utf8 "sun/util/resources"; + const #344 = class #345; // java/lang/System$LoggerFinder + const #345 = Utf8 "java/lang/System$LoggerFinder"; + const #346 = class #347; // java/net/ContentHandlerFactory + const #347 = Utf8 "java/net/ContentHandlerFactory"; + const #348 = class #349; // java/net/spi/InetAddressResolverProvider + const #349 = Utf8 "java/net/spi/InetAddressResolverProvider"; + const #350 = class #351; // java/net/spi/URLStreamHandlerProvider + const #351 = Utf8 "java/net/spi/URLStreamHandlerProvider"; + const #352 = class #353; // java/nio/channels/spi/AsynchronousChannelProvider + const #353 = Utf8 "java/nio/channels/spi/AsynchronousChannelProvider"; + const #354 = class #355; // java/nio/channels/spi/SelectorProvider + const #355 = Utf8 "java/nio/channels/spi/SelectorProvider"; + const #356 = class #357; // java/nio/charset/spi/CharsetProvider + const #357 = Utf8 "java/nio/charset/spi/CharsetProvider"; + const #358 = class #359; // java/nio/file/spi/FileSystemProvider + const #359 = Utf8 "java/nio/file/spi/FileSystemProvider"; + const #360 = class #361; // java/nio/file/spi/FileTypeDetector + const #361 = Utf8 "java/nio/file/spi/FileTypeDetector"; + const #362 = class #363; // java/security/Provider + const #363 = Utf8 "java/security/Provider"; + const #364 = class #365; // java/text/spi/BreakIteratorProvider + const #365 = Utf8 "java/text/spi/BreakIteratorProvider"; + const #366 = class #367; // java/text/spi/CollatorProvider + const #367 = Utf8 "java/text/spi/CollatorProvider"; + const #368 = class #369; // java/text/spi/DateFormatProvider + const #369 = Utf8 "java/text/spi/DateFormatProvider"; + const #370 = class #371; // java/text/spi/DateFormatSymbolsProvider + const #371 = Utf8 "java/text/spi/DateFormatSymbolsProvider"; + const #372 = class #373; // java/text/spi/DecimalFormatSymbolsProvider + const #373 = Utf8 "java/text/spi/DecimalFormatSymbolsProvider"; + const #374 = class #375; // java/text/spi/NumberFormatProvider + const #375 = Utf8 "java/text/spi/NumberFormatProvider"; + const #376 = class #377; // java/time/chrono/AbstractChronology + const #377 = Utf8 "java/time/chrono/AbstractChronology"; + const #378 = class #379; // java/time/chrono/Chronology + const #379 = Utf8 "java/time/chrono/Chronology"; + const #380 = class #381; // java/time/zone/ZoneRulesProvider + const #381 = Utf8 "java/time/zone/ZoneRulesProvider"; + const #382 = class #383; // java/util/random/RandomGenerator + const #383 = Utf8 "java/util/random/RandomGenerator"; + const #384 = class #385; // java/util/spi/CalendarDataProvider + const #385 = Utf8 "java/util/spi/CalendarDataProvider"; + const #386 = class #387; // java/util/spi/CalendarNameProvider + const #387 = Utf8 "java/util/spi/CalendarNameProvider"; + const #388 = class #389; // java/util/spi/CurrencyNameProvider + const #389 = Utf8 "java/util/spi/CurrencyNameProvider"; + const #390 = class #391; // java/util/spi/LocaleNameProvider + const #391 = Utf8 "java/util/spi/LocaleNameProvider"; + const #392 = class #393; // java/util/spi/ResourceBundleControlProvider + const #393 = Utf8 "java/util/spi/ResourceBundleControlProvider"; + const #394 = class #395; // java/util/spi/ResourceBundleProvider + const #395 = Utf8 "java/util/spi/ResourceBundleProvider"; + const #396 = class #397; // java/util/spi/TimeZoneNameProvider + const #397 = Utf8 "java/util/spi/TimeZoneNameProvider"; + const #398 = class #399; // java/util/spi/ToolProvider + const #399 = Utf8 "java/util/spi/ToolProvider"; + const #400 = class #401; // javax/security/auth/spi/LoginModule + const #401 = Utf8 "javax/security/auth/spi/LoginModule"; + const #402 = class #403; // jdk/internal/io/JdkConsoleProvider + const #403 = Utf8 "jdk/internal/io/JdkConsoleProvider"; + const #404 = class #405; // jdk/internal/logger/DefaultLoggerFinder + const #405 = Utf8 "jdk/internal/logger/DefaultLoggerFinder"; + const #406 = class #407; // sun/text/spi/JavaTimeDateTimePatternProvider + const #407 = Utf8 "sun/text/spi/JavaTimeDateTimePatternProvider"; + const #408 = class #409; // sun/util/locale/provider/LocaleDataMetaInfo + const #409 = Utf8 "sun/util/locale/provider/LocaleDataMetaInfo"; + const #410 = class #411; // sun/util/resources/LocaleData$CommonResourceBundleProvider + const #411 = Utf8 "sun/util/resources/LocaleData$CommonResourceBundleProvider"; + const #412 = class #413; // sun/util/resources/LocaleData$SupplementaryResourceBundleProvider + const #413 = Utf8 "sun/util/resources/LocaleData$SupplementaryResourceBundleProvider"; + const #414 = class #415; // sun/util/spi/CalendarProvider + const #415 = Utf8 "sun/util/spi/CalendarProvider"; + const #416 = class #417; // jdk/internal/jrtfs/JrtFileSystemProvider + const #417 = Utf8 "jdk/internal/jrtfs/JrtFileSystemProvider"; + const #418 = class #419; // java/security/SecureRandom + const #419 = Utf8 "java/security/SecureRandom"; + const #420 = class #421; // java/util/Random + const #421 = Utf8 "java/util/Random"; + const #422 = class #423; // java/util/SplittableRandom + const #423 = Utf8 "java/util/SplittableRandom"; + const #424 = Utf8 "InnerClasses"; + const #425 = class #426; // java/lang/System + const #426 = Utf8 "java/lang/System"; + const #427 = Utf8 "LoggerFinder"; + const #428 = class #429; // sun/util/resources/LocaleData + const #429 = Utf8 "sun/util/resources/LocaleData"; + const #430 = Utf8 "CommonResourceBundleProvider"; + const #431 = Utf8 "SupplementaryResourceBundleProvider"; + const #432 = Utf8 "ModulePackages"; + const #433 = Utf8 "apple/security"; + const #434 = Package #433; // apple/security + const #435 = Utf8 "jdk/internal"; + const #436 = Package #435; // jdk/internal + const #437 = Utf8 "jdk/internal/access/foreign"; + const #438 = Package #437; // jdk/internal/access/foreign + const #439 = Utf8 "jdk/internal/classfile/components"; + const #440 = Package #439; // jdk/internal/classfile/components + const #441 = Utf8 "jdk/internal/classfile/impl"; + const #442 = Package #441; // jdk/internal/classfile/impl + const #443 = Utf8 "jdk/internal/classfile/impl/verifier"; + const #444 = Package #443; // jdk/internal/classfile/impl/verifier + const #445 = Utf8 "jdk/internal/classfile/java/lang/constant"; + const #446 = Package #445; // jdk/internal/classfile/java/lang/constant + const #447 = Utf8 "jdk/internal/foreign/abi"; + const #448 = Package #447; // jdk/internal/foreign/abi + const #449 = Utf8 "jdk/internal/foreign/abi/aarch64"; + const #450 = Package #449; // jdk/internal/foreign/abi/aarch64 + const #451 = Utf8 "jdk/internal/foreign/abi/aarch64/linux"; + const #452 = Package #451; // jdk/internal/foreign/abi/aarch64/linux + const #453 = Utf8 "jdk/internal/foreign/abi/aarch64/macos"; + const #454 = Package #453; // jdk/internal/foreign/abi/aarch64/macos + const #455 = Utf8 "jdk/internal/foreign/abi/aarch64/windows"; + const #456 = Package #455; // jdk/internal/foreign/abi/aarch64/windows + const #457 = Utf8 "jdk/internal/foreign/abi/fallback"; + const #458 = Package #457; // jdk/internal/foreign/abi/fallback + const #459 = Utf8 "jdk/internal/foreign/abi/riscv64"; + const #460 = Package #459; // jdk/internal/foreign/abi/riscv64 + const #461 = Utf8 "jdk/internal/foreign/abi/riscv64/linux"; + const #462 = Package #461; // jdk/internal/foreign/abi/riscv64/linux + const #463 = Utf8 "jdk/internal/foreign/abi/x64"; + const #464 = Package #463; // jdk/internal/foreign/abi/x64 + const #465 = Utf8 "jdk/internal/foreign/abi/x64/sysv"; + const #466 = Package #465; // jdk/internal/foreign/abi/x64/sysv + const #467 = Utf8 "jdk/internal/foreign/abi/x64/windows"; + const #468 = Package #467; // jdk/internal/foreign/abi/x64/windows + const #469 = Utf8 "jdk/internal/foreign/layout"; + const #470 = Package #469; // jdk/internal/foreign/layout + const #471 = Utf8 "jdk/internal/icu/impl"; + const #472 = Package #471; // jdk/internal/icu/impl + const #473 = Utf8 "jdk/internal/icu/impl/data/icudt72b"; + const #474 = Package #473; // jdk/internal/icu/impl/data/icudt72b + const #475 = Utf8 "jdk/internal/icu/lang"; + const #476 = Package #475; // jdk/internal/icu/lang + const #477 = Utf8 "jdk/internal/icu/text"; + const #478 = Package #477; // jdk/internal/icu/text + const #479 = Utf8 "jdk/internal/icu/util"; + const #480 = Package #479; // jdk/internal/icu/util + const #481 = Utf8 "jdk/internal/jrtfs"; + const #482 = Package #481; // jdk/internal/jrtfs + const #483 = Utf8 "jdk/internal/math"; + const #484 = Package #483; // jdk/internal/math + const #485 = Utf8 "jdk/internal/org/objectweb/asm/signature"; + const #486 = Package #485; // jdk/internal/org/objectweb/asm/signature + const #487 = Utf8 "jdk/internal/org/objectweb/asm/tree/analysis"; + const #488 = Package #487; // jdk/internal/org/objectweb/asm/tree/analysis + const #489 = Utf8 "jdk/internal/util/regex"; + const #490 = Package #489; // jdk/internal/util/regex + const #491 = Utf8 "sun/invoke"; + const #492 = Package #491; // sun/invoke + const #493 = Utf8 "sun/invoke/empty"; + const #494 = Package #493; // sun/invoke/empty + const #495 = Utf8 "sun/launcher"; + const #496 = Package #495; // sun/launcher + const #497 = Utf8 "sun/launcher/resources"; + const #498 = Package #497; // sun/launcher/resources + const #499 = Utf8 "sun/net/ftp"; + const #500 = Package #499; // sun/net/ftp + const #501 = Utf8 "sun/net/ftp/impl"; + const #502 = Package #501; // sun/net/ftp/impl + const #503 = Utf8 "sun/net/idn"; + const #504 = Package #503; // sun/net/idn + const #505 = Utf8 "sun/net/sdp"; + const #506 = Package #505; // sun/net/sdp + const #507 = Utf8 "sun/net/smtp"; + const #508 = Package #507; // sun/net/smtp + const #509 = Utf8 "sun/net/spi"; + const #510 = Package #509; // sun/net/spi + const #511 = Utf8 "sun/net/www/content/text"; + const #512 = Package #511; // sun/net/www/content/text + const #513 = Utf8 "sun/net/www/http"; + const #514 = Package #513; // sun/net/www/http + const #515 = Utf8 "sun/net/www/protocol/file"; + const #516 = Package #515; // sun/net/www/protocol/file + const #517 = Utf8 "sun/net/www/protocol/ftp"; + const #518 = Package #517; // sun/net/www/protocol/ftp + const #519 = Utf8 "sun/net/www/protocol/http/ntlm"; + const #520 = Package #519; // sun/net/www/protocol/http/ntlm + const #521 = Utf8 "sun/net/www/protocol/https"; + const #522 = Package #521; // sun/net/www/protocol/https + const #523 = Utf8 "sun/net/www/protocol/jar"; + const #524 = Package #523; // sun/net/www/protocol/jar + const #525 = Utf8 "sun/net/www/protocol/jmod"; + const #526 = Package #525; // sun/net/www/protocol/jmod + const #527 = Utf8 "sun/net/www/protocol/jrt"; + const #528 = Package #527; // sun/net/www/protocol/jrt + const #529 = Utf8 "sun/net/www/protocol/mailto"; + const #530 = Package #529; // sun/net/www/protocol/mailto + const #531 = Utf8 "sun/nio"; + const #532 = Package #531; // sun/nio + const #533 = Utf8 "sun/reflect/generics/factory"; + const #534 = Package #533; // sun/reflect/generics/factory + const #535 = Utf8 "sun/reflect/generics/parser"; + const #536 = Package #535; // sun/reflect/generics/parser + const #537 = Utf8 "sun/reflect/generics/repository"; + const #538 = Package #537; // sun/reflect/generics/repository + const #539 = Utf8 "sun/reflect/generics/scope"; + const #540 = Package #539; // sun/reflect/generics/scope + const #541 = Utf8 "sun/reflect/generics/tree"; + const #542 = Package #541; // sun/reflect/generics/tree + const #543 = Utf8 "sun/reflect/generics/visitor"; + const #544 = Package #543; // sun/reflect/generics/visitor + const #545 = Utf8 "sun/security/pkcs10"; + const #546 = Package #545; // sun/security/pkcs10 + const #547 = Utf8 "sun/security/pkcs12"; + const #548 = Package #547; // sun/security/pkcs12 + const #549 = Utf8 "sun/security/provider/certpath/ssl"; + const #550 = Package #549; // sun/security/provider/certpath/ssl + const #551 = Utf8 "sun/security/ssl"; + const #552 = Package #551; // sun/security/ssl + const #553 = Utf8 "sun/security/tools/keytool"; + const #554 = Package #553; // sun/security/tools/keytool + const #555 = Utf8 "sun/text"; + const #556 = Package #555; // sun/text + const #557 = Utf8 "sun/text/resources"; + const #558 = Package #557; // sun/text/resources + const #559 = Utf8 "sun/text/resources/cldr"; + const #560 = Package #559; // sun/text/resources/cldr + const #561 = Utf8 "sun/text/spi"; + const #562 = Package #561; // sun/text/spi + const #563 = Utf8 "sun/util"; + const #564 = Package #563; // sun/util + const #565 = Utf8 "sun/util/calendar"; + const #566 = Package #565; // sun/util/calendar + const #567 = Utf8 "sun/util/locale"; + const #568 = Package #567; // sun/util/locale + const #569 = Utf8 "sun/util/resources/cldr"; + const #570 = Package #569; // sun/util/resources/cldr + const #571 = Utf8 "sun/util/spi"; + const #572 = Package #571; // sun/util/spi + + exports #88 /* java/util/spi */; + exports #104 /* javax/security/auth */; + exports #72 /* java/util */; + exports #22 /* java/lang/ref */; + exports #48 /* java/nio/file/spi */; + exports #102 /* javax/net/ssl */; + exports #50 /* java/security */; + exports #20 /* java/lang/module */; + exports #98 /* javax/crypto/spec */; + exports #82 /* java/util/jar */; + exports #112 /* javax/security/auth/x500 */; + exports #68 /* java/time/temporal */; + exports #38 /* java/nio/channels/spi */; + exports #110 /* javax/security/auth/spi */; + exports #60 /* java/text/spi */; + exports #54 /* java/security/interfaces */; + exports #90 /* java/util/stream */; + exports #46 /* java/nio/file/attribute */; + exports #24 /* java/lang/reflect */; + exports #100 /* javax/net */; + exports #94 /* javax/crypto */; + exports #96 /* javax/crypto/interfaces */; + exports #74 /* java/util/concurrent */; + exports #34 /* java/nio */; + exports #32 /* java/net/spi */; + exports #108 /* javax/security/auth/login */; + exports #16 /* java/lang/foreign */; + exports #66 /* java/time/format */; + exports #40 /* java/nio/charset */; + exports #56 /* java/security/spec */; + exports #76 /* java/util/concurrent/atomic */; + exports #114 /* javax/security/cert */; + exports #26 /* java/lang/runtime */; + exports #28 /* java/math */; + exports #80 /* java/util/function */; + exports #62 /* java/time */; + exports #78 /* java/util/concurrent/locks */; + exports #52 /* java/security/cert */; + exports #106 /* javax/security/auth/callback */; + exports #44 /* java/nio/file */; + exports #18 /* java/lang/invoke */; + exports #42 /* java/nio/charset/spi */; + exports #70 /* java/time/zone */; + exports #12 /* java/lang/annotation */; + exports #14 /* java/lang/constant */; + exports #84 /* java/util/random */; + exports #58 /* java/text */; + exports #10 /* java/lang */; + exports #30 /* java/net */; + exports #92 /* java/util/zip */; + exports #86 /* java/util/regex */; + exports #8 /* java/io */; + exports #36 /* java/nio/channels */; + exports #64 /* java/time/chrono */; + exports #310 /* sun/security/provider/certpath */ to + #140 /* jdk.jartool */, + #132 /* java.naming */; + exports #326 /* sun/security/util/math/intpoly */ to + #294 /* jdk.crypto.ec */; + exports #316 /* sun/security/tools */ to + #140 /* jdk.jartool */; + exports #218 /* jdk/internal/org/objectweb/asm/util */ to + #142 /* jdk.jfr */; + exports #270 /* sun/net/util */ to + #126 /* java.desktop */, + #194 /* java.net.http */, + #148 /* jdk.sctp */, + #272 /* jdk.jconsole */; + exports #246 /* jdk/internal/util/random */ to + #248 /* jdk.random */; + exports #280 /* sun/nio/cs */ to + #126 /* java.desktop */, + #136 /* jdk.charsets */; + exports #282 /* sun/nio/fs */ to + #146 /* jdk.net */; + exports #328 /* sun/security/validator */ to + #140 /* jdk.jartool */; + exports #244 /* jdk/internal/util/jar */ to + #140 /* jdk.jartool */; + exports #156 /* jdk/internal/classfile/constantpool */ to + #140 /* jdk.jartool */, + #144 /* jdk.jlink */; + exports #158 /* jdk/internal/classfile/instruction */ to + #144 /* jdk.jlink */, + #152 /* jdk.jshell */; + exports #220 /* jdk/internal/org/xml/sax */ to + #142 /* jdk.jfr */; + exports #212 /* jdk/internal/org/objectweb/asm */ to + #142 /* jdk.jfr */; + exports #296 /* sun/security/internal/interfaces */ to + #118 /* jdk.crypto.cryptoki */; + exports #338 /* sun/util/logging */ to + #126 /* java.desktop */, + #128 /* java.logging */, + #340 /* java.prefs */; + exports #182 /* jdk/internal/jimage/decompressor */ to + #144 /* jdk.jlink */; + exports #162 /* jdk/internal/foreign */ to + #164 /* jdk.incubator.vector */; + exports #242 /* jdk/internal/util */ to + #126 /* java.desktop */; + exports #266 /* sun/net/dns */ to + #264 /* jdk.naming.dns */, + #196 /* java.security.jgss */; + exports #306 /* sun/security/provider */ to + #294 /* jdk.crypto.ec */, + #134 /* java.rmi */, + #196 /* java.security.jgss */, + #118 /* jdk.crypto.cryptoki */, + #308 /* jdk.security.auth */; + exports #334 /* sun/util/locale/provider */ to + #126 /* java.desktop */, + #336 /* jdk.localedata */, + #144 /* jdk.jlink */; + exports #300 /* sun/security/jca */ to + #294 /* jdk.crypto.ec */, + #264 /* jdk.naming.dns */, + #302 /* java.smartcardio */, + #118 /* jdk.crypto.cryptoki */; + exports #214 /* jdk/internal/org/objectweb/asm/commons */ to + #142 /* jdk.jfr */; + exports #154 /* jdk/internal/classfile/attribute */ to + #140 /* jdk.jartool */, + #144 /* jdk.jlink */; + exports #288 /* sun/reflect/misc */ to + #290 /* java.datatransfer */, + #126 /* java.desktop */, + #238 /* java.sql.rowset */, + #134 /* java.rmi */, + #208 /* java.management.rmi */, + #130 /* java.management */; + exports #216 /* jdk/internal/org/objectweb/asm/tree */ to + #142 /* jdk.jfr */; + exports #252 /* jdk/internal/util/xml/impl */ to + #142 /* jdk.jfr */; + exports #298 /* sun/security/internal/spec */ to + #118 /* jdk.crypto.cryptoki */; + exports #232 /* jdk/internal/ref */ to + #126 /* java.desktop */, + #194 /* java.net.http */; + exports #234 /* jdk/internal/reflect */ to + #238 /* java.sql.rowset */, + #240 /* jdk.dynalink */, + #200 /* jdk.internal.vm.ci */, + #236 /* java.sql */, + #128 /* java.logging */, + #204 /* jdk.unsupported */; + exports #254 /* jdk/internal/vm */ to + #228 /* jdk.management.agent */, + #226 /* jdk.internal.jvmstat */, + #138 /* jdk.incubator.concurrent */, + #178 /* jdk.management */, + #130 /* java.management */; + exports #184 /* jdk/internal/jmod */ to + #174 /* jdk.compiler */, + #144 /* jdk.jlink */; + exports #206 /* jdk/internal/module */ to + #140 /* jdk.jartool */, + #142 /* jdk.jfr */, + #188 /* java.instrument */, + #144 /* jdk.jlink */, + #208 /* java.management.rmi */, + #210 /* jdk.jpackage */; + exports #120 /* com/sun/security/ntlm */ to + #122 /* java.security.sasl */; + exports #314 /* sun/security/timestamp */ to + #140 /* jdk.jartool */; + exports #304 /* sun/security/pkcs */ to + #140 /* jdk.jartool */, + #294 /* jdk.crypto.ec */; + exports #276 /* sun/net/www/protocol/http */ to + #196 /* java.security.jgss */; + exports #274 /* sun/net/www */ to + #140 /* jdk.jartool */, + #194 /* java.net.http */; + exports #150 /* jdk/internal/classfile */ to + #140 /* jdk.jartool */, + #144 /* jdk.jlink */, + #152 /* jdk.jshell */; + exports #318 /* sun/security/util */ to + #122 /* java.security.sasl */, + #140 /* jdk.jartool */, + #126 /* java.desktop */, + #320 /* java.xml.crypto */, + #294 /* jdk.crypto.ec */, + #134 /* java.rmi */, + #196 /* java.security.jgss */, + #302 /* java.smartcardio */, + #132 /* java.naming */, + #118 /* jdk.crypto.cryptoki */, + #322 /* jdk.security.jgss */, + #308 /* jdk.security.auth */; + exports #256 /* jdk/internal/vm/annotation */ to + #200 /* jdk.internal.vm.ci */, + #142 /* jdk.jfr */, + #188 /* java.instrument */, + #138 /* jdk.incubator.concurrent */, + #164 /* jdk.incubator.vector */, + #204 /* jdk.unsupported */; + exports #332 /* sun/util/cldr */ to + #144 /* jdk.jlink */; + exports #278 /* sun/nio/ch */ to + #148 /* jdk.sctp */, + #146 /* jdk.net */, + #130 /* java.management */, + #118 /* jdk.crypto.cryptoki */; + exports #262 /* sun/net */ to + #194 /* java.net.http */, + #264 /* jdk.naming.dns */; + exports #222 /* jdk/internal/org/xml/sax/helpers */ to + #142 /* jdk.jfr */; + exports #284 /* sun/reflect/annotation */ to + #174 /* jdk.compiler */; + exports #190 /* jdk/internal/logger */ to + #128 /* java.logging */; + exports #312 /* sun/security/rsa */ to + #118 /* jdk.crypto.cryptoki */; + exports #186 /* jdk/internal/loader */ to + #188 /* java.instrument */, + #132 /* java.naming */, + #128 /* java.logging */; + exports #160 /* jdk/internal/event */ to + #142 /* jdk.jfr */; + exports #124 /* jdk/internal/access */ to + #126 /* java.desktop */, + #146 /* jdk.net */, + #134 /* java.rmi */, + #144 /* jdk.jlink */, + #132 /* java.naming */, + #130 /* java.management */, + #140 /* jdk.jartool */, + #148 /* jdk.sctp */, + #142 /* jdk.jfr */, + #138 /* jdk.incubator.concurrent */, + #128 /* java.logging */, + #136 /* jdk.charsets */, + #118 /* jdk.crypto.cryptoki */; + exports #170 /* jdk/internal/javac */ to + #176 /* jdk.jdi */, + #140 /* jdk.jartool */, + #174 /* jdk.compiler */, + #142 /* jdk.jfr */, + #138 /* jdk.incubator.concurrent */, + #172 /* java.compiler */, + #164 /* jdk.incubator.vector */, + #178 /* jdk.management */, + #152 /* jdk.jshell */, + #130 /* java.management */; + exports #230 /* jdk/internal/platform */ to + #142 /* jdk.jfr */, + #178 /* jdk.management */; + exports #192 /* jdk/internal/misc */ to + #202 /* jdk.nio.mapmode */, + #126 /* java.desktop */, + #194 /* java.net.http */, + #174 /* jdk.compiler */, + #200 /* jdk.internal.vm.ci */, + #134 /* java.rmi */, + #196 /* java.security.jgss */, + #198 /* jdk.attach */, + #132 /* java.naming */, + #164 /* jdk.incubator.vector */, + #152 /* jdk.jshell */, + #130 /* java.management */, + #142 /* jdk.jfr */, + #138 /* jdk.incubator.concurrent */, + #128 /* java.logging */, + #136 /* jdk.charsets */, + #204 /* jdk.unsupported */, + #118 /* jdk.crypto.cryptoki */; + exports #250 /* jdk/internal/util/xml */ to + #142 /* jdk.jfr */; + exports #330 /* sun/security/x509 */ to + #140 /* jdk.jartool */, + #294 /* jdk.crypto.ec */, + #118 /* jdk.crypto.cryptoki */; + exports #286 /* sun/reflect/generics/reflectiveObjects */ to + #126 /* java.desktop */; + exports #116 /* com/sun/crypto/provider */ to + #118 /* jdk.crypto.cryptoki */; + exports #258 /* jdk/internal/vm/vector */ to + #164 /* jdk.incubator.vector */; + exports #292 /* sun/security/action */ to + #126 /* java.desktop */, + #294 /* jdk.crypto.ec */, + #196 /* java.security.jgss */, + #138 /* jdk.incubator.concurrent */; + exports #224 /* jdk/internal/perf */ to + #228 /* jdk.management.agent */, + #226 /* jdk.internal.jvmstat */, + #130 /* java.management */; + exports #180 /* jdk/internal/jimage */ to + #144 /* jdk.jlink */; + exports #260 /* sun/invoke/util */ to + #174 /* jdk.compiler */; + exports #166 /* jdk/internal/io */ to + #168 /* jdk.internal.le */, + #152 /* jdk.jshell */; + exports #268 /* sun/net/ext */ to + #146 /* jdk.net */; + exports #324 /* sun/security/util/math */ to + #294 /* jdk.crypto.ec */; + exports #342 /* sun/util/resources */ to + #336 /* jdk.localedata */; + uses #346 /* java/net/ContentHandlerFactory */; + uses #372 /* java/text/spi/DecimalFormatSymbolsProvider */; + uses #392 /* java/util/spi/ResourceBundleControlProvider */; + uses #410 /* sun/util/resources/LocaleData$CommonResourceBundleProvider */; + uses #362 /* java/security/Provider */; + uses #396 /* java/util/spi/TimeZoneNameProvider */; + uses #344 /* java/lang/System$LoggerFinder */; + uses #350 /* java/net/spi/URLStreamHandlerProvider */; + uses #414 /* sun/util/spi/CalendarProvider */; + uses #364 /* java/text/spi/BreakIteratorProvider */; + uses #358 /* java/nio/file/spi/FileSystemProvider */; + uses #394 /* java/util/spi/ResourceBundleProvider */; + uses #370 /* java/text/spi/DateFormatSymbolsProvider */; + uses #400 /* javax/security/auth/spi/LoginModule */; + uses #360 /* java/nio/file/spi/FileTypeDetector */; + uses #374 /* java/text/spi/NumberFormatProvider */; + uses #412 /* sun/util/resources/LocaleData$SupplementaryResourceBundleProvider */; + uses #352 /* java/nio/channels/spi/AsynchronousChannelProvider */; + uses #402 /* jdk/internal/io/JdkConsoleProvider */; + uses #354 /* java/nio/channels/spi/SelectorProvider */; + uses #386 /* java/util/spi/CalendarNameProvider */; + uses #368 /* java/text/spi/DateFormatProvider */; + uses #366 /* java/text/spi/CollatorProvider */; + uses #380 /* java/time/zone/ZoneRulesProvider */; + uses #408 /* sun/util/locale/provider/LocaleDataMetaInfo */; + uses #348 /* java/net/spi/InetAddressResolverProvider */; + uses #376 /* java/time/chrono/AbstractChronology */; + uses #390 /* java/util/spi/LocaleNameProvider */; + uses #398 /* java/util/spi/ToolProvider */; + uses #406 /* sun/text/spi/JavaTimeDateTimePatternProvider */; + uses #378 /* java/time/chrono/Chronology */; + uses #388 /* java/util/spi/CurrencyNameProvider */; + uses #404 /* jdk/internal/logger/DefaultLoggerFinder */; + uses #382 /* java/util/random/RandomGenerator */; + uses #384 /* java/util/spi/CalendarDataProvider */; + uses #356 /* java/nio/charset/spi/CharsetProvider */; + provides #358 /* java/nio/file/spi/FileSystemProvider */ with + #416 /* jdk/internal/jrtfs/JrtFileSystemProvider */; + provides #382 /* java/util/random/RandomGenerator */ with + #418 /* java/security/SecureRandom */, + #422 /* java/util/SplittableRandom */, + #420 /* java/util/Random */; +} // end of module java.base diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903031/module-info.class.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +// Partial ConstantPool +module #6 /* java.base */ version 65:0 +{ + const #1 = class #2; // module-info + const #2 = Utf8 "module-info"; + const #3 = Utf8 "SourceFile"; + const #4 = Utf8 "module-info.java"; + const #5 = Utf8 "Module"; + const #6 = Module #7; // java.base + const #7 = Utf8 "java.base"; + exports java/util/spi; + exports javax/security/auth; + exports java/util; + exports java/lang/ref; + exports java/nio/file/spi; + exports javax/net/ssl; + exports java/security; + exports java/lang/module; + exports javax/crypto/spec; + exports java/util/jar; + exports javax/security/auth/x500; + exports java/time/temporal; + exports java/nio/channels/spi; + exports javax/security/auth/spi; + exports java/text/spi; + exports java/security/interfaces; + exports java/util/stream; + exports java/nio/file/attribute; + exports java/lang/reflect; + exports javax/net; + exports javax/crypto; + exports javax/crypto/interfaces; + exports java/util/concurrent; + exports java/nio; + exports java/net/spi; + exports javax/security/auth/login; + exports java/lang/foreign; + exports java/time/format; + exports java/nio/charset; + exports java/security/spec; + exports java/util/concurrent/atomic; + exports javax/security/cert; + exports java/lang/runtime; + exports java/math; + exports java/util/function; + exports java/time; + exports java/util/concurrent/locks; + exports java/security/cert; + exports javax/security/auth/callback; + exports java/nio/file; + exports java/lang/invoke; + exports java/nio/charset/spi; + exports java/time/zone; + exports java/lang/annotation; + exports java/lang/constant; + exports java/util/random; + exports java/text; + exports java/lang; + exports java/net; + exports java/util/zip; + exports java/util/regex; + exports java/io; + exports java/nio/channels; + exports java/time/chrono; + exports sun/security/provider/certpath to + jdk.jartool, + java.naming; + exports sun/security/util/math/intpoly to + jdk.crypto.ec; + exports sun/security/tools to + jdk.jartool; + exports jdk/internal/org/objectweb/asm/util to + jdk.jfr; + exports sun/net/util to + java.desktop, + java.net.http, + jdk.sctp, + jdk.jconsole; + exports jdk/internal/util/random to + jdk.random; + exports sun/nio/cs to + java.desktop, + jdk.charsets; + exports sun/nio/fs to + jdk.net; + exports sun/security/validator to + jdk.jartool; + exports jdk/internal/util/jar to + jdk.jartool; + exports jdk/internal/classfile/constantpool to + jdk.jartool, + jdk.jlink; + exports jdk/internal/classfile/instruction to + jdk.jlink, + jdk.jshell; + exports jdk/internal/org/xml/sax to + jdk.jfr; + exports jdk/internal/org/objectweb/asm to + jdk.jfr; + exports sun/security/internal/interfaces to + jdk.crypto.cryptoki; + exports sun/util/logging to + java.desktop, + java.logging, + java.prefs; + exports jdk/internal/jimage/decompressor to + jdk.jlink; + exports jdk/internal/foreign to + jdk.incubator.vector; + exports jdk/internal/util to + java.desktop; + exports sun/net/dns to + jdk.naming.dns, + java.security.jgss; + exports sun/security/provider to + jdk.crypto.ec, + java.rmi, + java.security.jgss, + jdk.crypto.cryptoki, + jdk.security.auth; + exports sun/util/locale/provider to + java.desktop, + jdk.localedata, + jdk.jlink; + exports sun/security/jca to + jdk.crypto.ec, + jdk.naming.dns, + java.smartcardio, + jdk.crypto.cryptoki; + exports jdk/internal/org/objectweb/asm/commons to + jdk.jfr; + exports jdk/internal/classfile/attribute to + jdk.jartool, + jdk.jlink; + exports sun/reflect/misc to + java.datatransfer, + java.desktop, + java.sql.rowset, + java.rmi, + java.management.rmi, + java.management; + exports jdk/internal/org/objectweb/asm/tree to + jdk.jfr; + exports jdk/internal/util/xml/impl to + jdk.jfr; + exports sun/security/internal/spec to + jdk.crypto.cryptoki; + exports jdk/internal/ref to + java.desktop, + java.net.http; + exports jdk/internal/reflect to + java.sql.rowset, + jdk.dynalink, + jdk.internal.vm.ci, + java.sql, + java.logging, + jdk.unsupported; + exports jdk/internal/vm to + jdk.management.agent, + jdk.internal.jvmstat, + jdk.incubator.concurrent, + jdk.management, + java.management; + exports jdk/internal/jmod to + jdk.compiler, + jdk.jlink; + exports jdk/internal/module to + jdk.jartool, + jdk.jfr, + java.instrument, + jdk.jlink, + java.management.rmi, + jdk.jpackage; + exports com/sun/security/ntlm to + java.security.sasl; + exports sun/security/timestamp to + jdk.jartool; + exports sun/security/pkcs to + jdk.jartool, + jdk.crypto.ec; + exports sun/net/www/protocol/http to + java.security.jgss; + exports sun/net/www to + jdk.jartool, + java.net.http; + exports jdk/internal/classfile to + jdk.jartool, + jdk.jlink, + jdk.jshell; + exports sun/security/util to + java.security.sasl, + jdk.jartool, + java.desktop, + java.xml.crypto, + jdk.crypto.ec, + java.rmi, + java.security.jgss, + java.smartcardio, + java.naming, + jdk.crypto.cryptoki, + jdk.security.jgss, + jdk.security.auth; + exports jdk/internal/vm/annotation to + jdk.internal.vm.ci, + jdk.jfr, + java.instrument, + jdk.incubator.concurrent, + jdk.incubator.vector, + jdk.unsupported; + exports sun/util/cldr to + jdk.jlink; + exports sun/nio/ch to + jdk.sctp, + jdk.net, + java.management, + jdk.crypto.cryptoki; + exports sun/net to + java.net.http, + jdk.naming.dns; + exports jdk/internal/org/xml/sax/helpers to + jdk.jfr; + exports sun/reflect/annotation to + jdk.compiler; + exports jdk/internal/logger to + java.logging; + exports sun/security/rsa to + jdk.crypto.cryptoki; + exports jdk/internal/loader to + java.instrument, + java.naming, + java.logging; + exports jdk/internal/event to + jdk.jfr; + exports jdk/internal/access to + java.desktop, + jdk.net, + java.rmi, + jdk.jlink, + java.naming, + java.management, + jdk.jartool, + jdk.sctp, + jdk.jfr, + jdk.incubator.concurrent, + java.logging, + jdk.charsets, + jdk.crypto.cryptoki; + exports jdk/internal/javac to + jdk.jdi, + jdk.jartool, + jdk.compiler, + jdk.jfr, + jdk.incubator.concurrent, + java.compiler, + jdk.incubator.vector, + jdk.management, + jdk.jshell, + java.management; + exports jdk/internal/platform to + jdk.jfr, + jdk.management; + exports jdk/internal/misc to + jdk.nio.mapmode, + java.desktop, + java.net.http, + jdk.compiler, + jdk.internal.vm.ci, + java.rmi, + java.security.jgss, + jdk.attach, + java.naming, + jdk.incubator.vector, + jdk.jshell, + java.management, + jdk.jfr, + jdk.incubator.concurrent, + java.logging, + jdk.charsets, + jdk.unsupported, + jdk.crypto.cryptoki; + exports jdk/internal/util/xml to + jdk.jfr; + exports sun/security/x509 to + jdk.jartool, + jdk.crypto.ec, + jdk.crypto.cryptoki; + exports sun/reflect/generics/reflectiveObjects to + java.desktop; + exports com/sun/crypto/provider to + jdk.crypto.cryptoki; + exports jdk/internal/vm/vector to + jdk.incubator.vector; + exports sun/security/action to + java.desktop, + jdk.crypto.ec, + java.security.jgss, + jdk.incubator.concurrent; + exports jdk/internal/perf to + jdk.management.agent, + jdk.internal.jvmstat, + java.management; + exports jdk/internal/jimage to + jdk.jlink; + exports sun/invoke/util to + jdk.compiler; + exports jdk/internal/io to + jdk.internal.le, + jdk.jshell; + exports sun/net/ext to + jdk.net; + exports sun/security/util/math to + jdk.crypto.ec; + exports sun/util/resources to + jdk.localedata; + uses java/net/ContentHandlerFactory; + uses java/text/spi/DecimalFormatSymbolsProvider; + uses java/util/spi/ResourceBundleControlProvider; + uses sun/util/resources/LocaleData$CommonResourceBundleProvider; + uses java/security/Provider; + uses java/util/spi/TimeZoneNameProvider; + uses java/lang/System$LoggerFinder; + uses java/net/spi/URLStreamHandlerProvider; + uses sun/util/spi/CalendarProvider; + uses java/text/spi/BreakIteratorProvider; + uses java/nio/file/spi/FileSystemProvider; + uses java/util/spi/ResourceBundleProvider; + uses java/text/spi/DateFormatSymbolsProvider; + uses javax/security/auth/spi/LoginModule; + uses java/nio/file/spi/FileTypeDetector; + uses java/text/spi/NumberFormatProvider; + uses sun/util/resources/LocaleData$SupplementaryResourceBundleProvider; + uses java/nio/channels/spi/AsynchronousChannelProvider; + uses jdk/internal/io/JdkConsoleProvider; + uses java/nio/channels/spi/SelectorProvider; + uses java/util/spi/CalendarNameProvider; + uses java/text/spi/DateFormatProvider; + uses java/text/spi/CollatorProvider; + uses java/time/zone/ZoneRulesProvider; + uses sun/util/locale/provider/LocaleDataMetaInfo; + uses java/net/spi/InetAddressResolverProvider; + uses java/time/chrono/AbstractChronology; + uses java/util/spi/LocaleNameProvider; + uses java/util/spi/ToolProvider; + uses sun/text/spi/JavaTimeDateTimePatternProvider; + uses java/time/chrono/Chronology; + uses java/util/spi/CurrencyNameProvider; + uses jdk/internal/logger/DefaultLoggerFinder; + uses java/util/random/RandomGenerator; + uses java/util/spi/CalendarDataProvider; + uses java/nio/charset/spi/CharsetProvider; + provides java/nio/file/spi/FileSystemProvider with + jdk/internal/jrtfs/JrtFileSystemProvider; + provides java/util/random/RandomGenerator with + java/security/SecureRandom, + java/util/SplittableRandom, + java/util/Random; +} // end of module java.base diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903405/ifge_overflow.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903405/ifge_overflow.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903405/ifge_overflow.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903405/ifge_overflow.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,1530 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +super public class ifge_overflow +{ + public Method "":"()V" + stack 2 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + public static Method test_1:"()V" + stack 200 locals 200 + { + iconst_0; + ifge SKIP; + + nop; // remove and everything is fine + + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + + + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + + + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + + + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + + + + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; + SKIP: + return; + } + public static Method main:"([Ljava/lang/String;)V" + stack 100 locals 100 + { + invokestatic Method test_1:"()V"; + return; + } +} // class ifge_overflow diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +public super class FileName01.class version 66:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = class #10; // ClassName + const #8 = Utf8 "java/lang/String"; + const #9 = class #8; // java/lang/String + const #10 = Utf8 "ClassName01"; + const #11 = Utf8 "Code"; + const #12 = Utf8 "LineNumberTable"; + const #13 = Utf8 "m"; + const #14 = Utf8 "JasmFile.g.jasm"; + const #15 = Utf8 "SourceFile"; + + this_class: #7; // ClassName01 + super_class #9; // java/lang/String + + public Method #5:#6 // "":"()V" + stack 1 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + } + private static Method #13:#6 // m:"()V" + stack 0 locals 0 + { + 0: return; + } + + SourceFile #14; // JasmFile01.g.jasm +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ +public super class FileName01.class version 66:0 +{ + this_class ClassName01; + super_class java/lang/String; + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + private static Method m:"()V" + stack 0 locals 0 + { + return; + } + + SourceFile "JasmFile.g.jasm"; +} // end Class ClassName01 compiled from "JasmFile.g.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +public super class FileName02.data version 66:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = class #10; // ClassName is not used + const #8 = Utf8 "java/lang/String"; + const #9 = class #8; // java/lang/String + const #10 = Utf8 "ClassName"; + const #11 = Utf8 "Code"; + const #12 = Utf8 "LineNumberTable"; + const #13 = Utf8 "m"; + const #14 = Utf8 "JasmFile.g.jasm"; + const #15 = Utf8 "SourceFile"; + + this_class: ClassName02; + super_class #9; // java/lang/String + + public Method #5:#6 // "":"()V" + stack 1 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + } + private static Method #13:#6 // m:"()V" + stack 0 locals 0 + { + 0: return; + } + + SourceFile #14; // JasmFile02.g.jasm +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ +public super class FileName02.data extends java/lang/String version 66:0 +{ + this_class ClassName02; + super_class java/lang/String; + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + private static Method m:"()V" + stack 0 locals 0 + { + return; + } + + SourceFile "JasmFile.g.jasm"; +} // end Class ClassName01 compiled from "JasmFile.g.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +public super class FileName03 extends package/ClassName version 66:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = class #10; // ClassName03 + const #8 = Utf8 "package/SuperClassName03"; + const #9 = class #8; // package/SuperClassName03 + const #10 = Utf8 "ClassName03"; + const #11 = Utf8 "Code"; + const #12 = Utf8 "LineNumberTable"; + const #13 = Utf8 "m"; + const #14 = Utf8 "JasmFile.g.jasm"; + const #15 = Utf8 "SourceFile"; + + this_class: #7; // ClassName03 + super_class #9; // package/SuperClassName03 + + public Method #5:#6 // "":"()V" + stack 1 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + } + private static Method #13:#6 // m:"()V" + stack 0 locals 0 + { + 0: return; + } + + SourceFile #14; // JasmFile03.g.jasm +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile03.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ +public super class FileName03.class extends java/lang/String version 66:0 +{ + this_class ClassName03; + super_class package/SuperClassName03; + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + private static Method m:"()V" + stack 0 locals 0 + { + return; + } + + SourceFile "JasmFile.g.jasm"; +} // end Class ClassName01 compiled from "JasmFile.g.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.g.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.g.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.g.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.g.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +public super class FileName04.obj extends #2 version 66:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Utf8 "java/lang/Object"; + const #5 = Utf8 ""; + const #6 = Utf8 "()V"; + const #7 = class #10; // ClassName03 -- ignored + const #8 = Utf8 "package/SuperClassName03"; + const #9 = class #8; // package/SuperClassName03 -- ignored + const #10 = Utf8 "ClassName03"; + const #11 = Utf8 "Code"; + const #12 = Utf8 "LineNumberTable"; + const #13 = Utf8 "m"; + const #14 = Utf8 "JasmFile.g.jasm"; + const #15 = Utf8 "SourceFile"; + + this_class: ClassName04; + super_class package/SuperClassName04; + + public Method #5:#6 // "":"()V" + stack 1 locals 1 + { + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + } + private static Method #13:#6 // m:"()V" + stack 0 locals 0 + { + 0: return; + } + + SourceFile #14; // JasmFile03.g.jasm +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903558/JasmFile04.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,21 @@ +public super class FileName04.obj extends package/SuperClassName04 version 66:0 +{ + this_class: ClassName04; + super_class: java/lang/Object; + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + private static Method m:"()V" + stack 0 locals 0 + { + return; + } + + SourceFile "JasmFile.g.jasm"; +} // end Class ClassName04 compiled from "JasmFile.g.jasm" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test00.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test00.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test00.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test00.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"(Ljava/lang/String;)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"(Ljava/lang/String)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test03.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test03.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test03.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test03.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"([X" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test04.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test04.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test04.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test04.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"(X)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test05.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test05.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test05.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test05.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"(Ljava/lang/String)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test06.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test06.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test06.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test06.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"Ljava/lang/String;)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test07.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test07.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test07.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test07.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"([X)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test08.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test08.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test08.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test08.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"([)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test09.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test09.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test09.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test09.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"(Ljava/lang/String[)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test10.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test10.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test10.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903976/Test10.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +identity class Test00 version 69:0 +{ + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"(Ljava/lang/String" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903987/Test00.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903987/Test00.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903987/Test00.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/case7903987/Test00.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Oracle, Red Hat and/or theirs affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +identity class Test00 version 69:0 +{ + const #1=true; + const #2=192837465; + const #3=1l; + const #5=2.1f; + const #6=2.2d; + const #8="Long utf-8"; + const #9=false; + + Field v1:I; + + Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + Method m:"(Ljava/lang/String;)Ljava/lang/String;" + stack 1 locals 2 + { + aconst_null; + areturn; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/clfacc00610m10p.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/clfacc00610m10p.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/clfacc00610m10p.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/clfacc00610m10p.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1996, 2018 Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +package javasoft/sqe/tests/vm/classfmt/clf/clfacc006/clfacc00610m1; + +public class clfacc00610m10p { + +public Method :"()V" + stack 4 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object.:"()V"; + + iconst_1; + anewarray class clfacc00610m10p_; + pop; + + return; +} +} + +private class clfacc00610m10p_ { + +public Method :"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object.:"()V"; + return; +} +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/spinum00101m10p.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/spinum00101m10p.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/spinum00101m10p.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jasm/spinum00101m10p.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,790 @@ +/* + * Ident: @(#)spinum00101m10p.jasm generated from:%Z%%M% %I% %E% + * + * Copyright (c) 1996, 2018 Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +package javasoft/sqe/tests/vm/classfmt/lmt/spinum001/spinum00101m1; + +interface spinum00101m1_0I { +} // end interface +interface spinum00101m1_1I { +} // end interface +interface spinum00101m1_2I { +} // end interface +interface spinum00101m1_3I { +} // end interface +interface spinum00101m1_4I { +} // end interface +interface spinum00101m1_5I { +} // end interface +interface spinum00101m1_6I { +} // end interface +interface spinum00101m1_7I { +} // end interface +interface spinum00101m1_8I { +} // end interface +interface spinum00101m1_9I { +} // end interface +interface spinum00101m1_10I { +} // end interface +interface spinum00101m1_11I { +} // end interface +interface spinum00101m1_12I { +} // end interface +interface spinum00101m1_13I { +} // end interface +interface spinum00101m1_14I { +} // end interface +interface spinum00101m1_15I { +} // end interface +interface spinum00101m1_16I { +} // end interface +interface spinum00101m1_17I { +} // end interface +interface spinum00101m1_18I { +} // end interface +interface spinum00101m1_19I { +} // end interface +interface spinum00101m1_20I { +} // end interface +interface spinum00101m1_21I { +} // end interface +interface spinum00101m1_22I { +} // end interface +interface spinum00101m1_23I { +} // end interface +interface spinum00101m1_24I { +} // end interface +interface spinum00101m1_25I { +} // end interface +interface spinum00101m1_26I { +} // end interface +interface spinum00101m1_27I { +} // end interface +interface spinum00101m1_28I { +} // end interface +interface spinum00101m1_29I { +} // end interface +interface spinum00101m1_30I { +} // end interface +interface spinum00101m1_31I { +} // end interface +interface spinum00101m1_32I { +} // end interface +interface spinum00101m1_33I { +} // end interface +interface spinum00101m1_34I { +} // end interface +interface spinum00101m1_35I { +} // end interface +interface spinum00101m1_36I { +} // end interface +interface spinum00101m1_37I { +} // end interface +interface spinum00101m1_38I { +} // end interface +interface spinum00101m1_39I { +} // end interface +interface spinum00101m1_40I { +} // end interface +interface spinum00101m1_41I { +} // end interface +interface spinum00101m1_42I { +} // end interface +interface spinum00101m1_43I { +} // end interface +interface spinum00101m1_44I { +} // end interface +interface spinum00101m1_45I { +} // end interface +interface spinum00101m1_46I { +} // end interface +interface spinum00101m1_47I { +} // end interface +interface spinum00101m1_48I { +} // end interface +interface spinum00101m1_49I { +} // end interface +interface spinum00101m1_50I { +} // end interface +interface spinum00101m1_51I { +} // end interface +interface spinum00101m1_52I { +} // end interface +interface spinum00101m1_53I { +} // end interface +interface spinum00101m1_54I { +} // end interface +interface spinum00101m1_55I { +} // end interface +interface spinum00101m1_56I { +} // end interface +interface spinum00101m1_57I { +} // end interface +interface spinum00101m1_58I { +} // end interface +interface spinum00101m1_59I { +} // end interface +interface spinum00101m1_60I { +} // end interface +interface spinum00101m1_61I { +} // end interface +interface spinum00101m1_62I { +} // end interface +interface spinum00101m1_63I { +} // end interface +interface spinum00101m1_64I { +} // end interface +interface spinum00101m1_65I { +} // end interface +interface spinum00101m1_66I { +} // end interface +interface spinum00101m1_67I { +} // end interface +interface spinum00101m1_68I { +} // end interface +interface spinum00101m1_69I { +} // end interface +interface spinum00101m1_70I { +} // end interface +interface spinum00101m1_71I { +} // end interface +interface spinum00101m1_72I { +} // end interface +interface spinum00101m1_73I { +} // end interface +interface spinum00101m1_74I { +} // end interface +interface spinum00101m1_75I { +} // end interface +interface spinum00101m1_76I { +} // end interface +interface spinum00101m1_77I { +} // end interface +interface spinum00101m1_78I { +} // end interface +interface spinum00101m1_79I { +} // end interface +interface spinum00101m1_80I { +} // end interface +interface spinum00101m1_81I { +} // end interface +interface spinum00101m1_82I { +} // end interface +interface spinum00101m1_83I { +} // end interface +interface spinum00101m1_84I { +} // end interface +interface spinum00101m1_85I { +} // end interface +interface spinum00101m1_86I { +} // end interface +interface spinum00101m1_87I { +} // end interface +interface spinum00101m1_88I { +} // end interface +interface spinum00101m1_89I { +} // end interface +interface spinum00101m1_90I { +} // end interface +interface spinum00101m1_91I { +} // end interface +interface spinum00101m1_92I { +} // end interface +interface spinum00101m1_93I { +} // end interface +interface spinum00101m1_94I { +} // end interface +interface spinum00101m1_95I { +} // end interface +interface spinum00101m1_96I { +} // end interface +interface spinum00101m1_97I { +} // end interface +interface spinum00101m1_98I { +} // end interface +interface spinum00101m1_99I { +} // end interface +interface spinum00101m1_100I { +} // end interface +interface spinum00101m1_101I { +} // end interface +interface spinum00101m1_102I { +} // end interface +interface spinum00101m1_103I { +} // end interface +interface spinum00101m1_104I { +} // end interface +interface spinum00101m1_105I { +} // end interface +interface spinum00101m1_106I { +} // end interface +interface spinum00101m1_107I { +} // end interface +interface spinum00101m1_108I { +} // end interface +interface spinum00101m1_109I { +} // end interface +interface spinum00101m1_110I { +} // end interface +interface spinum00101m1_111I { +} // end interface +interface spinum00101m1_112I { +} // end interface +interface spinum00101m1_113I { +} // end interface +interface spinum00101m1_114I { +} // end interface +interface spinum00101m1_115I { +} // end interface +interface spinum00101m1_116I { +} // end interface +interface spinum00101m1_117I { +} // end interface +interface spinum00101m1_118I { +} // end interface +interface spinum00101m1_119I { +} // end interface +interface spinum00101m1_120I { +} // end interface +interface spinum00101m1_121I { +} // end interface +interface spinum00101m1_122I { +} // end interface +interface spinum00101m1_123I { +} // end interface +interface spinum00101m1_124I { +} // end interface +interface spinum00101m1_125I { +} // end interface +interface spinum00101m1_126I { +} // end interface +interface spinum00101m1_127I { +} // end interface +interface spinum00101m1_128I { +} // end interface +interface spinum00101m1_129I { +} // end interface +interface spinum00101m1_130I { +} // end interface +interface spinum00101m1_131I { +} // end interface +interface spinum00101m1_132I { +} // end interface +interface spinum00101m1_133I { +} // end interface +interface spinum00101m1_134I { +} // end interface +interface spinum00101m1_135I { +} // end interface +interface spinum00101m1_136I { +} // end interface +interface spinum00101m1_137I { +} // end interface +interface spinum00101m1_138I { +} // end interface +interface spinum00101m1_139I { +} // end interface +interface spinum00101m1_140I { +} // end interface +interface spinum00101m1_141I { +} // end interface +interface spinum00101m1_142I { +} // end interface +interface spinum00101m1_143I { +} // end interface +interface spinum00101m1_144I { +} // end interface +interface spinum00101m1_145I { +} // end interface +interface spinum00101m1_146I { +} // end interface +interface spinum00101m1_147I { +} // end interface +interface spinum00101m1_148I { +} // end interface +interface spinum00101m1_149I { +} // end interface +interface spinum00101m1_150I { +} // end interface +interface spinum00101m1_151I { +} // end interface +interface spinum00101m1_152I { +} // end interface +interface spinum00101m1_153I { +} // end interface +interface spinum00101m1_154I { +} // end interface +interface spinum00101m1_155I { +} // end interface +interface spinum00101m1_156I { +} // end interface +interface spinum00101m1_157I { +} // end interface +interface spinum00101m1_158I { +} // end interface +interface spinum00101m1_159I { +} // end interface +interface spinum00101m1_160I { +} // end interface +interface spinum00101m1_161I { +} // end interface +interface spinum00101m1_162I { +} // end interface +interface spinum00101m1_163I { +} // end interface +interface spinum00101m1_164I { +} // end interface +interface spinum00101m1_165I { +} // end interface +interface spinum00101m1_166I { +} // end interface +interface spinum00101m1_167I { +} // end interface +interface spinum00101m1_168I { +} // end interface +interface spinum00101m1_169I { +} // end interface +interface spinum00101m1_170I { +} // end interface +interface spinum00101m1_171I { +} // end interface +interface spinum00101m1_172I { +} // end interface +interface spinum00101m1_173I { +} // end interface +interface spinum00101m1_174I { +} // end interface +interface spinum00101m1_175I { +} // end interface +interface spinum00101m1_176I { +} // end interface +interface spinum00101m1_177I { +} // end interface +interface spinum00101m1_178I { +} // end interface +interface spinum00101m1_179I { +} // end interface +interface spinum00101m1_180I { +} // end interface +interface spinum00101m1_181I { +} // end interface +interface spinum00101m1_182I { +} // end interface +interface spinum00101m1_183I { +} // end interface +interface spinum00101m1_184I { +} // end interface +interface spinum00101m1_185I { +} // end interface +interface spinum00101m1_186I { +} // end interface +interface spinum00101m1_187I { +} // end interface +interface spinum00101m1_188I { +} // end interface +interface spinum00101m1_189I { +} // end interface +interface spinum00101m1_190I { +} // end interface +interface spinum00101m1_191I { +} // end interface +interface spinum00101m1_192I { +} // end interface +interface spinum00101m1_193I { +} // end interface +interface spinum00101m1_194I { +} // end interface +interface spinum00101m1_195I { +} // end interface +interface spinum00101m1_196I { +} // end interface +interface spinum00101m1_197I { +} // end interface +interface spinum00101m1_198I { +} // end interface +interface spinum00101m1_199I { +} // end interface +interface spinum00101m1_200I { +} // end interface +interface spinum00101m1_201I { +} // end interface +interface spinum00101m1_202I { +} // end interface +interface spinum00101m1_203I { +} // end interface +interface spinum00101m1_204I { +} // end interface +interface spinum00101m1_205I { +} // end interface +interface spinum00101m1_206I { +} // end interface +interface spinum00101m1_207I { +} // end interface +interface spinum00101m1_208I { +} // end interface +interface spinum00101m1_209I { +} // end interface +interface spinum00101m1_210I { +} // end interface +interface spinum00101m1_211I { +} // end interface +interface spinum00101m1_212I { +} // end interface +interface spinum00101m1_213I { +} // end interface +interface spinum00101m1_214I { +} // end interface +interface spinum00101m1_215I { +} // end interface +interface spinum00101m1_216I { +} // end interface +interface spinum00101m1_217I { +} // end interface +interface spinum00101m1_218I { +} // end interface +interface spinum00101m1_219I { +} // end interface +interface spinum00101m1_220I { +} // end interface +interface spinum00101m1_221I { +} // end interface +interface spinum00101m1_222I { +} // end interface +interface spinum00101m1_223I { +} // end interface +interface spinum00101m1_224I { +} // end interface +interface spinum00101m1_225I { +} // end interface +interface spinum00101m1_226I { +} // end interface +interface spinum00101m1_227I { +} // end interface +interface spinum00101m1_228I { +} // end interface +interface spinum00101m1_229I { +} // end interface +interface spinum00101m1_230I { +} // end interface +interface spinum00101m1_231I { +} // end interface +interface spinum00101m1_232I { +} // end interface +interface spinum00101m1_233I { +} // end interface +interface spinum00101m1_234I { +} // end interface +interface spinum00101m1_235I { +} // end interface +interface spinum00101m1_236I { +} // end interface +interface spinum00101m1_237I { +} // end interface +interface spinum00101m1_238I { +} // end interface +interface spinum00101m1_239I { +} // end interface +interface spinum00101m1_240I { +} // end interface +interface spinum00101m1_241I { +} // end interface +interface spinum00101m1_242I { +} // end interface +interface spinum00101m1_243I { +} // end interface +interface spinum00101m1_244I { +} // end interface +interface spinum00101m1_245I { +} // end interface +interface spinum00101m1_246I { +} // end interface +interface spinum00101m1_247I { +} // end interface +interface spinum00101m1_248I { +} // end interface +interface spinum00101m1_249I { +} // end interface +interface spinum00101m1_250I { +} // end interface +interface spinum00101m1_251I { +} // end interface +interface spinum00101m1_252I { +} // end interface +interface spinum00101m1_253I { +} // end interface +interface spinum00101m1_254I { +} // end interface +interface spinum00101m1_255I { +} // end interface +interface spinum00101m1_256I { +} // end interface + +public class spinum00101m10p implements + spinum00101m1_0I, + spinum00101m1_1I, + spinum00101m1_2I, + spinum00101m1_3I, + spinum00101m1_4I, + spinum00101m1_5I, + spinum00101m1_6I, + spinum00101m1_7I, + spinum00101m1_8I, + spinum00101m1_9I, + spinum00101m1_10I, + spinum00101m1_11I, + spinum00101m1_12I, + spinum00101m1_13I, + spinum00101m1_14I, + spinum00101m1_15I, + spinum00101m1_16I, + spinum00101m1_17I, + spinum00101m1_18I, + spinum00101m1_19I, + spinum00101m1_20I, + spinum00101m1_21I, + spinum00101m1_22I, + spinum00101m1_23I, + spinum00101m1_24I, + spinum00101m1_25I, + spinum00101m1_26I, + spinum00101m1_27I, + spinum00101m1_28I, + spinum00101m1_29I, + spinum00101m1_30I, + spinum00101m1_31I, + spinum00101m1_32I, + spinum00101m1_33I, + spinum00101m1_34I, + spinum00101m1_35I, + spinum00101m1_36I, + spinum00101m1_37I, + spinum00101m1_38I, + spinum00101m1_39I, + spinum00101m1_40I, + spinum00101m1_41I, + spinum00101m1_42I, + spinum00101m1_43I, + spinum00101m1_44I, + spinum00101m1_45I, + spinum00101m1_46I, + spinum00101m1_47I, + spinum00101m1_48I, + spinum00101m1_49I, + spinum00101m1_50I, + spinum00101m1_51I, + spinum00101m1_52I, + spinum00101m1_53I, + spinum00101m1_54I, + spinum00101m1_55I, + spinum00101m1_56I, + spinum00101m1_57I, + spinum00101m1_58I, + spinum00101m1_59I, + spinum00101m1_60I, + spinum00101m1_61I, + spinum00101m1_62I, + spinum00101m1_63I, + spinum00101m1_64I, + spinum00101m1_65I, + spinum00101m1_66I, + spinum00101m1_67I, + spinum00101m1_68I, + spinum00101m1_69I, + spinum00101m1_70I, + spinum00101m1_71I, + spinum00101m1_72I, + spinum00101m1_73I, + spinum00101m1_74I, + spinum00101m1_75I, + spinum00101m1_76I, + spinum00101m1_77I, + spinum00101m1_78I, + spinum00101m1_79I, + spinum00101m1_80I, + spinum00101m1_81I, + spinum00101m1_82I, + spinum00101m1_83I, + spinum00101m1_84I, + spinum00101m1_85I, + spinum00101m1_86I, + spinum00101m1_87I, + spinum00101m1_88I, + spinum00101m1_89I, + spinum00101m1_90I, + spinum00101m1_91I, + spinum00101m1_92I, + spinum00101m1_93I, + spinum00101m1_94I, + spinum00101m1_95I, + spinum00101m1_96I, + spinum00101m1_97I, + spinum00101m1_98I, + spinum00101m1_99I, + spinum00101m1_100I, + spinum00101m1_101I, + spinum00101m1_102I, + spinum00101m1_103I, + spinum00101m1_104I, + spinum00101m1_105I, + spinum00101m1_106I, + spinum00101m1_107I, + spinum00101m1_108I, + spinum00101m1_109I, + spinum00101m1_110I, + spinum00101m1_111I, + spinum00101m1_112I, + spinum00101m1_113I, + spinum00101m1_114I, + spinum00101m1_115I, + spinum00101m1_116I, + spinum00101m1_117I, + spinum00101m1_118I, + spinum00101m1_119I, + spinum00101m1_120I, + spinum00101m1_121I, + spinum00101m1_122I, + spinum00101m1_123I, + spinum00101m1_124I, + spinum00101m1_125I, + spinum00101m1_126I, + spinum00101m1_127I, + spinum00101m1_128I, + spinum00101m1_129I, + spinum00101m1_130I, + spinum00101m1_131I, + spinum00101m1_132I, + spinum00101m1_133I, + spinum00101m1_134I, + spinum00101m1_135I, + spinum00101m1_136I, + spinum00101m1_137I, + spinum00101m1_138I, + spinum00101m1_139I, + spinum00101m1_140I, + spinum00101m1_141I, + spinum00101m1_142I, + spinum00101m1_143I, + spinum00101m1_144I, + spinum00101m1_145I, + spinum00101m1_146I, + spinum00101m1_147I, + spinum00101m1_148I, + spinum00101m1_149I, + spinum00101m1_150I, + spinum00101m1_151I, + spinum00101m1_152I, + spinum00101m1_153I, + spinum00101m1_154I, + spinum00101m1_155I, + spinum00101m1_156I, + spinum00101m1_157I, + spinum00101m1_158I, + spinum00101m1_159I, + spinum00101m1_160I, + spinum00101m1_161I, + spinum00101m1_162I, + spinum00101m1_163I, + spinum00101m1_164I, + spinum00101m1_165I, + spinum00101m1_166I, + spinum00101m1_167I, + spinum00101m1_168I, + spinum00101m1_169I, + spinum00101m1_170I, + spinum00101m1_171I, + spinum00101m1_172I, + spinum00101m1_173I, + spinum00101m1_174I, + spinum00101m1_175I, + spinum00101m1_176I, + spinum00101m1_177I, + spinum00101m1_178I, + spinum00101m1_179I, + spinum00101m1_180I, + spinum00101m1_181I, + spinum00101m1_182I, + spinum00101m1_183I, + spinum00101m1_184I, + spinum00101m1_185I, + spinum00101m1_186I, + spinum00101m1_187I, + spinum00101m1_188I, + spinum00101m1_189I, + spinum00101m1_190I, + spinum00101m1_191I, + spinum00101m1_192I, + spinum00101m1_193I, + spinum00101m1_194I, + spinum00101m1_195I, + spinum00101m1_196I, + spinum00101m1_197I, + spinum00101m1_198I, + spinum00101m1_199I, + spinum00101m1_200I, + spinum00101m1_201I, + spinum00101m1_202I, + spinum00101m1_203I, + spinum00101m1_204I, + spinum00101m1_205I, + spinum00101m1_206I, + spinum00101m1_207I, + spinum00101m1_208I, + spinum00101m1_209I, + spinum00101m1_210I, + spinum00101m1_211I, + spinum00101m1_212I, + spinum00101m1_213I, + spinum00101m1_214I, + spinum00101m1_215I, + spinum00101m1_216I, + spinum00101m1_217I, + spinum00101m1_218I, + spinum00101m1_219I, + spinum00101m1_220I, + spinum00101m1_221I, + spinum00101m1_222I, + spinum00101m1_223I, + spinum00101m1_224I, + spinum00101m1_225I, + spinum00101m1_226I, + spinum00101m1_227I, + spinum00101m1_228I, + spinum00101m1_229I, + spinum00101m1_230I, + spinum00101m1_231I, + spinum00101m1_232I, + spinum00101m1_233I, + spinum00101m1_234I, + spinum00101m1_235I, + spinum00101m1_236I, + spinum00101m1_237I, + spinum00101m1_238I, + spinum00101m1_239I, + spinum00101m1_240I, + spinum00101m1_241I, + spinum00101m1_242I, + spinum00101m1_243I, + spinum00101m1_244I, + spinum00101m1_245I, + spinum00101m1_246I, + spinum00101m1_247I, + spinum00101m1_248I, + spinum00101m1_249I, + spinum00101m1_250I, + spinum00101m1_251I, + spinum00101m1_252I, + spinum00101m1_253I, + spinum00101m1_254I, + spinum00101m1_255I, + spinum00101m1_256I +{ + +public Method :"()V" stack 1 { + aload_0; + invokespecial java/lang/Object.:"()V"; + return; +} +} // end Class spinum00101m10p diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/12.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/12.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/12.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/12.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,128 @@ +class IntAndClass$IntAndClassImp { + 0xCAFEBABE; + 0; // minor version + 55; // version + [] { // Constant Pool + ; // first element is empty + Method #3 #12; // #1 + class #13; // #2 + class #16; // #3 + class #17; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + Utf8 "Code"; // #7 + Utf8 "LineNumberTable"; // #8 + Utf8 "SourceFile"; // #9 + Utf8 "IntAndClass.java"; // #10 + Utf8 "NestHost"; // #11 + NameAndType #5 #6; // #12 + Utf8 "IntAndClass$IntAndClassImp"; // #13 + Utf8 "IntAndClassImp"; // #14 + Utf8 "InnerClasses"; // #15 + Utf8 "java/lang/Object"; // #16 + Utf8 "IntAndClass"; // #17 + } + + 0x0021; // access + #2; // this_cpx + #3; // super_cpx + + [] { // Interfaces +#4; + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#7) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB70001B1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#8) { // LineNumberTable + [] { // line_number_table + 0 3; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#9) { // SourceFile + #10; + } // end of SourceFile + ; + Attr(#11) { // NestHost +#4; + } // end of NestHost + ; + Attr(#15) { // InnerClasses + [] { // classes + #2 #4 #14 9; + } + } // end of InnerClasses + } // end of Attributes +} +class IntAndClass { + 0xCAFEBABE; + 0; // minor version + 55; // version + [] { // Constant Pool + ; // first element is empty + class #9; // #1 + class #10; // #2 + class #11; // #3 + Utf8 "IntAndClassImp"; // #4 + Utf8 "InnerClasses"; // #5 + Utf8 "SourceFile"; // #6 + Utf8 "IntAndClass.java"; // #7 + Utf8 "NestMembers"; // #8 + Utf8 "IntAndClass"; // #9 + Utf8 "java/lang/Object"; // #10 + Utf8 "IntAndClass$IntAndClassImp"; // #11 + } + + 0x0601; // access + #1; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + } // end of Methods + + [] { // Attributes + Attr(#6) { // SourceFile + #7; + } // end of SourceFile + ; + Attr(#8) { // NestMembers + [] { // classes +#3; + } + } // end of NestMembers + ; + Attr(#5) { // InnerClasses + [] { // classes + #3 #1 #4 9; + } + } // end of InnerClasses + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/bad.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/bad.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/bad.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jcoder/bad.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +class negative/bad { + 0xCAFEBA; // -- 0xCAFEBABE + 3; // minor version + 45; // version + [] { // Constant Pool + ; // first element is empty + Class #12; // #1 + Class #6; // #2 + Method #1 #4; // #3 + NameAndType #14 #15; // #4 + Utf8 "ConstantValue"; // #5 + Utf8 "negative/bad"; // #6 + Utf8 "Exceptions"; // #7 + Utf8 "LineNumberTable"; // #8 + Utf8 "SourceFile"; // #9 + Utf8 "LocalVariables"; // #10 + Utf8 "Code"; // #11 + Utf8 "java/lang/Object"; // #12 + Utf8 "attr003.jcod"; // #13 + Utf8 ""; // #14 + Utf8 "()V"; // #15 + } + + 0x0001; // access + #2; // this_cpx + #1; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #14; // name_index + #15; // descriptor_index + [] { // Attributes + Attr(#11) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + ; + Attr(#11) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x03 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.g.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.g.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.g.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.g.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + /* Jasm source of the test resource may look like this: + module moduleB@1.2.3 version 62:0 + { + requires mandated java.base@jck-22; + exports packB; + } + */ +module moduleB { + 0xCAFEBABE; + 0; // minor version + 62; // version + [15] { // Constant Pool + ; // first element is empty + Class #2; // #1 at 0x0A + Utf8 "module-info"; // #2 at 0x0D + Utf8 "SourceFile"; // #3 at 0x1B + Utf8 "module-info.jcod"; // #4 at 0x28 + Utf8 "Module"; // #5 at 0x3B + Module #7; // #6 at 0x44 + Utf8 "moduleB"; // #7 at 0x47 + Module #9; // #8 at 0x51 + Utf8 "java.base"; // #9 at 0x54 + Utf8 "jdk4jck_22"; // #10 at 0x60 + Package #12; // #11 at 0x6D + Utf8 "packB"; // #12 at 0x70 + Utf8 "1.2.3"; // #13 at 0x78 + Utf8 "ModulePackages"; // #14 at 0x80 + } // end of Constant Pool + + 0x8000; // access [ ACC_MODULE, 0xFFFF0000 ] + #1; // this_cpx + #0; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [0] { // Methods + } // end of Methods + + [2] { // Attributes + Attr(#3, 2) { // SourceFile at 0x9F + #4; + } // end of SourceFile + ; + Attr(#5, 28) { // Module at 0xA7 + #6; // name_index + 0x0000; // flags + + #13; // version + [1] { // requires + #8 0x8000 #10; // ACC_MANDATED + } // end of requires + + [1] { // exports + #11 0x0000 // [ ] + [0] { + }; + } // of exports + + [0] { // opens + } // of opens + + [0] { // uses + } // end of uses + + [0] { // provides + } // end of provides + + } // end of Module + } // end of Attributes +} // end of module moduleB diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/jdec/case7902055/module-info.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + /* Jasm source of the test resource may look like this: + module moduleB@1.2.3 version 62:0 + { + requires mandated java.base@jck-22; + exports packB; + } + */ +module { + 0xCAFEBABE; + 0; // minor version + 62; // version + [] { // Constant Pool + ; // first element is empty + Class #2; // #1 + Utf8 "module-info"; // #2 + Utf8 "SourceFile"; // #3 + Utf8 "module-info.jcod"; // #4 + Utf8 "Module"; // #5 + Module #7; // #6 + Utf8 "moduleB"; // #7 + Module #9; // #8 + Utf8 "java.base"; // #9 + Utf8 "jdk4jck_22"; // #10 + Package #12; // #11 + Utf8 "packB"; // #12 + Utf8 "1.2.3"; // #13 + Utf8 "ModulePackages"; // #14 + } + + 0x8000; // access + #1; // this_cpx + #0; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + } // end of Methods + + [] { // Attributes + Attr(#3) { // SourceFile + #4; + } // end of SourceFile + ; + Attr(#5) { // Module + #6; // name_index + 0x0000; // flags + + #13; // version + [] { // requires + #8 0x8000 #10; + } // end of requires + + [] { // exports + #11 0x0000 + [] { + }; + } // of exports + + [] { // opens + } // of opens + + [] { // uses + } // end of uses + + [] { // provides + } // end of provides + + } // end of Module + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField00.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField00.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField00.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField00.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +abstract interface class ClassField00 version 69:0 +{ + static public protected Field field0:"I"; + + static public final transient Field field1:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassField00, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +value abstract class ClassField01 version 69:65535 +{ + + static public final volatile Field field0:"I"; + + static public final strict transient Field field1:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassField01, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +// Fields of interfaces must have their ACC_PUBLIC, ACC_STATIC, and ACC_FINAL flags set; +// they may have their ACC_STRICT_INIT or ACC_SYNTHETIC flag set, +// and must not have any of the other flags in Table 4.5-A set (JLS §9.3): +// ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its package. +// ACC_PRIVATE 0x0002 Declared private; accessible only within the defining class and other classes belonging to the same nest (5.4.4). +// ACC_PROTECTED 0x0004 Declared protected; may be accessed within subclasses. +// ACC_STATIC 0x0008 Declared static. +// ACC_FINAL 0x0010 Declared final; never directly assigned to after object construction (JLS §17.5). +// ACC_VOLATILE 0x0040 Declared volatile; cannot be cached. +// ACC_TRANSIENT 0x0080 Declared transient; not written or read by a persistent object manager. +// ACC_STRICT_INIT 0x0800 A strictly-initialized field; must be initialized before it can be read. +// ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code. +// ACC_ENUM 0x4000 Declared as an element of an enum class. + + +abstract interface class ClassField04 version 69:65535 +{ + // OK + static public final strict Field field0:"I"; + static public final synthetic Field field1:"I"; + // negative + static public final synthetic enum Field field2:"I"; + static public final transient Field field3:"I"; + static final strict Field field4:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassField04, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField03.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField03.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField03.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField03.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +abstract interface class ClassField03 version 69:0 +{ + + static public final Field field0:"I"; + + static public final strict Field field1:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassField03, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField04.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField04.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField04.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassField04.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +// Each field of a value class must have at least one of its ACC_STATIC or ACC_STRICT_INIT flags set. + +value final class ClassField04 version 69:65535 +{ + // OK + static public final strict Field field0:"I"; + public strict synthetic Field field1:"I"; + public static enum Field field2:"I"; + + // negative + public final Field field3:"I"; + Field field4:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassField04, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile00.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile00.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile00.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile00.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public value class ClassFile00 version 69:0 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile00, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile01.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile01.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile01.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile01.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public identity class ClassFile01 version 69:0 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile01, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile02.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile02.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile02.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile02.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public identity class ClassFile02 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile02, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile03.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile03.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile03.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile03.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public value class ClassFile03 { + + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile03, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile04.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile04.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile04.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile04.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public identity value class ClassFile04 version 69:65535 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile04, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile05.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile05.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile05.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile05.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +private public identity class ClassFile05 version 69:65535 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile05, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile06.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile06.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile06.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile06.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public identity enum interface class ClassFile06 version 69:65535 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile06, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile07.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile07.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile07.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile07.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +// If the ACC_ANNOTATION flag is set, the ACC_INTERFACE flag must also be set. + +public annotation class ClassFile06 version 69:65535 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile07, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile08.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile08.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile08.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile08.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +// If the ACC_INTERFACE flag is set, the ACC_ABSTRACT flag must also be set, +// and the ACC_FINAL, ACC_SUPER ACC_IDENTITY, ACC_ENUM, and ACC_MODULE flags set must not be set. + +interface enum class ClassFile08 version 69:65535 +{ + public Field field:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile08, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile09.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile09.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile09.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile09.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +// If the ACC_INTERFACE flag is not set, any of the other flags in Table 4.1-B may be set except ACC_ANNOTATION and ACC_MODULE. +// However, such a class file must have at least one of its ACC_FINAL, ACC_IDENTITY, or ACC_ABSTRACT flags set, +// and must not have both its ACC_FINAL and ACC_ABSTRACT flags set (JLS §8.1.1.2). + +value class ClassFile09 version 69:65535 +{ + public Field field:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile09, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile10.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile10.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile10.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile10.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +// If the ACC_INTERFACE flag is not set, any of the other flags in Table 4.1-B may be set except ACC_ANNOTATION and ACC_MODULE. +// However, such a class file must have at least one of its ACC_FINAL, ACC_IDENTITY, or ACC_ABSTRACT flags set, +// and must not have both its ACC_FINAL and ACC_ABSTRACT flags set (JLS §8.1.1.2). + +value abstract final class ClassFile10 version 69:65535 +{ + static public Field field:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile10, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile11.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile11.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile11.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile11.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +final value class ClassFile11 version 69:65535 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile11, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile12.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile12.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile12.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile12.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +identity class ClassFile12 version 69:65535 +{ + strict private Field field:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile12, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile13.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile13.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile13.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile13.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +value interface ClassFile13 version 69:65535 +{ + strict public static final Field field:"I"; + + Method "init":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile13, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile14.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile14.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile14.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile14.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public super class ClassFile14 version 69:0 +{ + strict private Field field00:"I"; + private Field field01:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile00, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile15.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile15.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile15.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/structure/ClassFile/ClassFile15.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javasoft/sqe/tests; + +public super class ClassFile15 version 69:65535 +{ + strict private Field field00:"I"; + private Field field01:"I"; + + Method "":"()V" + stack 4 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + stack_map class ClassFile00, float; + putfield Field field:"I"; + return; + } +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,195 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01 { + 0xCAFEBABE; + 0; // minor version + 58; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + class #8; // #7 + Utf8 "java/lang/ArithmeticException"; // #8 + Field #10 #11; // #9 + class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/System"; // #12 + Utf8 "out"; // #13 + Utf8 "Ljava/io/PrintStream;"; // #14 + String #16; // #15 + Utf8 "failed"; // #16 + Method #18 #19; // #17 + class #20; // #18 + NameAndType #21 #22; // #19 + Utf8 "java/io/PrintStream"; // #20 + Utf8 "print"; // #21 + Utf8 "(Ljava/lang/String;)V"; // #22 + String #24; // #23 + Utf8 "passed"; // #24 + class #26; // #25 + Utf8 "org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01"; // #26 + Utf8 "Code"; // #27 + Utf8 "LineNumberTable"; // #28 + Utf8 "LocalVariableTable"; // #29 + Utf8 "this"; // #30 + Utf8 "Lorg/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative01;"; // #31 + Utf8 "calculate"; // #32 + Utf8 "()I"; // #33 + Utf8 "i"; // #34 + Utf8 "I"; // #35 + Utf8 "e"; // #36 + Utf8 "Ljava/lang/ArithmeticException;"; // #37 + Utf8 "a1"; // #38 + Utf8 "a2"; // #39 + Utf8 "a3"; // #40 + Utf8 "StackMapTable"; // #41 + Utf8 "SourceFile"; // #42 + Utf8 "InvalidSourceDebugExtension.java"; // #43 + Utf8 "SourceDebugExtension"; // #44 + } + + 0x0021; // access + #25; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#27) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB70001B1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#28) { // LineNumberTable + [] { // line_number_table + 0 25; + } + } // end of LineNumberTable + ; + Attr(#29) { // LocalVariableTable + [] { // LocalVariableTable + 0 5 30 31 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #32; // name_index + #33; // descriptor_index + [] { // Attributes + Attr(#27) { // Code + 3; // max_stack + 5; // max_locals + Bytes[]{ + 0x043C043D043E1B1C; + 0x1D646C3604150408; + 0xA2000C8401018404; + 0x01A7FFF4053DA700; + 0x073A04053E1B04A0; + 0x000D1C04A000081D; + 0x059F000DB2000912; + 0x0FB6001105ACB200; + 0x091217B6001103AC; + } + [] { // Traps + 6 30 33 7; + } // end of Traps + [] { // Attributes + Attr(#28) { // LineNumberTable + [] { // line_number_table + 0 28; + 2 29; + 4 30; + 6 32; + 19 33; + 22 32; + 28 35; + 30 38; + 33 36; + 35 37; + 37 39; + 52 40; + 60 41; + 62 43; + 70 44; + } + } // end of LineNumberTable + ; + Attr(#29) { // LocalVariableTable + [] { // LocalVariableTable + 13 15 34 35 4; + 35 2 36 37 4; + 0 72 30 31 0; + 2 70 38 35 1; + 4 68 39 35 2; + 6 66 40 35 3; + } + } // end of LocalVariableTable + ; + Attr(#41) { // StackMapTable + [] { // + 255b, 13, []{O,25; I; I; I; I}, []{}; // full_frame + 250b, 14; // chop_frame 1 + 68b, []z{O,7}; // same_locals_1_stack_item_frame + 3b; // same_frame + 14b; // same_frame + 9b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#42) { // SourceFile + #43; + } // end of SourceFile + Attr(#44, 2147483647) { // SourceDebugExtension + 0x00; 0x11; 0x22; + 0x33; 0x44; 0x55; + } + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,195 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02 { + 0xCAFEBABE; + 0; // minor version + 58; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + class #8; // #7 + Utf8 "java/lang/ArithmeticException"; // #8 + Field #10 #11; // #9 + class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "java/lang/System"; // #12 + Utf8 "out"; // #13 + Utf8 "Ljava/io/PrintStream;"; // #14 + String #16; // #15 + Utf8 "failed"; // #16 + Method #18 #19; // #17 + class #20; // #18 + NameAndType #21 #22; // #19 + Utf8 "java/io/PrintStream"; // #20 + Utf8 "print"; // #21 + Utf8 "(Ljava/lang/String;)V"; // #22 + String #24; // #23 + Utf8 "passed"; // #24 + class #26; // #25 + Utf8 "org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02"; // #26 + Utf8 "Code"; // #27 + Utf8 "LineNumberTable"; // #28 + Utf8 "LocalVariableTable"; // #29 + Utf8 "this"; // #30 + Utf8 "Lorg/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionNegative02;"; // #31 + Utf8 "calculate"; // #32 + Utf8 "()I"; // #33 + Utf8 "i"; // #34 + Utf8 "I"; // #35 + Utf8 "e"; // #36 + Utf8 "Ljava/lang/ArithmeticException;"; // #37 + Utf8 "a1"; // #38 + Utf8 "a2"; // #39 + Utf8 "a3"; // #40 + Utf8 "StackMapTable"; // #41 + Utf8 "SourceFile"; // #42 + Utf8 "InvalidSourceDebugExtension.java"; // #43 + Utf8 "SourceDebugExtension"; // #44 + } + + 0x0021; // access + #25; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#27) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB70001B1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#28) { // LineNumberTable + [] { // line_number_table + 0 25; + } + } // end of LineNumberTable + ; + Attr(#29) { // LocalVariableTable + [] { // LocalVariableTable + 0 5 30 31 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #32; // name_index + #33; // descriptor_index + [] { // Attributes + Attr(#27) { // Code + 3; // max_stack + 5; // max_locals + Bytes[]{ + 0x043C043D043E1B1C; + 0x1D646C3604150408; + 0xA2000C8401018404; + 0x01A7FFF4053DA700; + 0x073A04053E1B04A0; + 0x000D1C04A000081D; + 0x059F000DB2000912; + 0x0FB6001105ACB200; + 0x091217B6001103AC; + } + [] { // Traps + 6 30 33 7; + } // end of Traps + [] { // Attributes + Attr(#28) { // LineNumberTable + [] { // line_number_table + 0 28; + 2 29; + 4 30; + 6 32; + 19 33; + 22 32; + 28 35; + 30 38; + 33 36; + 35 37; + 37 39; + 52 40; + 60 41; + 62 43; + 70 44; + } + } // end of LineNumberTable + ; + Attr(#29) { // LocalVariableTable + [] { // LocalVariableTable + 13 15 34 35 4; + 35 2 36 37 4; + 0 72 30 31 0; + 2 70 38 35 1; + 4 68 39 35 2; + 6 66 40 35 3; + } + } // end of LocalVariableTable + ; + Attr(#41) { // StackMapTable + [] { // + 255b, 13, []{O,25; I; I; I; I}, []{}; // full_frame + 250b, 14; // chop_frame 1 + 68b, []z{O,7}; // same_locals_1_stack_item_frame + 3b; // same_frame + 14b; // same_frame + 9b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#42) { // SourceFile + #43; + } // end of SourceFile + Attr(#44, 2) { // SourceDebugExtension + 0x00; 0x11; 0x22; + 0x33; 0x44; 0x55; + } + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,203 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01 { + 0xCAFEBABE; + 0; // minor version + 58; // version + [45] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "java/lang/ArithmeticException"; // #8 at 0x3C + Field #10 #11; // #9 at 0x5C + class #12; // #10 at 0x61 + NameAndType #13 #14; // #11 at 0x64 + Utf8 "java/lang/System"; // #12 at 0x69 + Utf8 "out"; // #13 at 0x7C + Utf8 "Ljava/io/PrintStream;"; // #14 at 0x82 + String #16; // #15 at 0x9A + Utf8 "failed"; // #16 at 0x9D + Method #18 #19; // #17 at 0xA6 + class #20; // #18 at 0xAB + NameAndType #21 #22; // #19 at 0xAE + Utf8 "java/io/PrintStream"; // #20 at 0xB3 + Utf8 "print"; // #21 at 0xC9 + Utf8 "(Ljava/lang/String;)V"; // #22 at 0xD1 + String #24; // #23 at 0xE9 + Utf8 "SourceDebugExtensionPositive01 passed"; // #24 at 0xEC + class #26; // #25 at 0xF5 + Utf8 "org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01"; // #26 at 0xF8 + Utf8 "Code"; // #27 at 0x0149 + Utf8 "LineNumberTable"; // #28 at 0x0150 + Utf8 "LocalVariableTable"; // #29 at 0x0162 + Utf8 "this"; // #30 at 0x0177 + Utf8 "Lorg/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01;"; // #31 at 0x017E + Utf8 "calculate"; // #32 at 0x01D1 + Utf8 "()I"; // #33 at 0x01DD + Utf8 "i"; // #34 at 0x01E3 + Utf8 "I"; // #35 at 0x01E7 + Utf8 "e"; // #36 at 0x01EB + Utf8 "Ljava/lang/ArithmeticException;"; // #37 at 0x01EF + Utf8 "a1"; // #38 at 0x0211 + Utf8 "a2"; // #39 at 0x0216 + Utf8 "a3"; // #40 at 0x021B + Utf8 "StackMapTable"; // #41 at 0x0220 + Utf8 "SourceDebugExtension"; // #42 at 0x0230 + Utf8 "SourceFile"; // #43 at 0x0247 + Utf8 "SourceDebugExtension.java"; // #44 at 0x0254 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #25; // this_cpx + #2; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [2] { // Methods + { // method at 0x027C + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#27, 47) { // Code at 0x0284 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end of Traps + [2] { // Attributes + Attr(#28, 6) { // LineNumberTable at 0x029B + [1] { // line_number_table + 0 25; // at 0x02A7 + } + } // end of LineNumberTable + ; + Attr(#29, 12) { // LocalVariableTable at 0x02A7 + [1] { // LocalVariableTable + 0 5 30 31 0; // at 0x02B9 + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x02B9 + 0x0001; // access + #32; // name_index : calculate + #33; // descriptor_index : ()I + [1] { // Attributes + Attr(#27, 260) { // Code at 0x02C1 + 3; // max_stack + 5; // max_locals + Bytes[72]{ + 0x043C043D043E1B1C; + 0x1D646C3604150408; + 0xA2000C8401018404; + 0x01A7FFF4053DA700; + 0x073A04053E1B04A0; + 0x000D1C04A000081D; + 0x059F000DB2000912; + 0x0FB6001105ACB200; + 0x091217B6001103AC; + } + [1] { // Traps + 6 30 33 7; // at 0x0321 + } // end of Traps + [3] { // Attributes + Attr(#28, 62) { // LineNumberTable at 0x0323 + [15] { // line_number_table + 0 28; // at 0x032F + 2 29; // at 0x0333 + 4 30; // at 0x0337 + 6 32; // at 0x033B + 19 33; // at 0x033F + 22 32; // at 0x0343 + 28 35; // at 0x0347 + 30 38; // at 0x034B + 33 36; // at 0x034F + 35 37; // at 0x0353 + 37 39; // at 0x0357 + 52 40; // at 0x035B + 60 41; // at 0x035F + 62 43; // at 0x0363 + 70 44; // at 0x0367 + } + } // end of LineNumberTable + ; + Attr(#29, 62) { // LocalVariableTable at 0x0367 + [6] { // LocalVariableTable + 13 15 34 35 4; // at 0x0379 + 35 2 36 37 4; // at 0x0383 + 0 72 30 31 0; // at 0x038D + 2 70 38 35 1; // at 0x0397 + 4 68 39 35 2; // at 0x03A1 + 6 66 40 35 3; // at 0x03AB + } + } // end of LocalVariableTable + ; + Attr(#41, 26) { // StackMapTable at 0x03AB + [6] { // + 255b, 13, [5]{7b,25; 1b; 1b; 1b; 1b}, [0]{}; // full_frame + 250b, 14; // chop_frame 1 + 68b, [1]z{7b,7}; // same_locals_1_stack_item_frame + 3b; // same_frame + 14b; // same_frame + 9b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [2] { // Attributes + Attr(#43, 2) { // SourceFile at 0x03CD + #44; + } // end of SourceFile + ; + Attr(#42) { // SourceDebugExtension at 0x03D5 + "\tThe Memory Model determines what values can be read at every point in the program.\n"; + "The actions of each thread in isolation must behave as governed by the semantics of "; + "that thread, with the exception that the values seen by each read are determined by "; + "the memory model.\nWhen we refer to this, we say that the program obeys intra-thread "; + "semantics.\n\tIntra-thread semantics are the semantics for single-threaded programs, "; + "and allow the complete prediction of the behavior of a thread based on the values "; + "seen by read actions within the thread.\n\tTo determine if the actions of thread \'t\' in "; + "an execution are legal, we simply evaluate the implementation of thread \"t\" as it would "; + "be performed in a single-threaded context, as defined in the rest of this specification."; + } // end of SourceDebugExtension + } // end of Attributes +} // end of class org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,451 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02 { + 0xCAFEBABE; + 0; // minor version + 58; // version + [45] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "java/lang/ArithmeticException"; // #8 at 0x3C + Field #10 #11; // #9 at 0x5C + class #12; // #10 at 0x61 + NameAndType #13 #14; // #11 at 0x64 + Utf8 "java/lang/System"; // #12 at 0x69 + Utf8 "out"; // #13 at 0x7C + Utf8 "Ljava/io/PrintStream;"; // #14 at 0x82 + String #16; // #15 at 0x9A + Utf8 "failed"; // #16 at 0x9D + Method #18 #19; // #17 at 0xA6 + class #20; // #18 at 0xAB + NameAndType #21 #22; // #19 at 0xAE + Utf8 "java/io/PrintStream"; // #20 at 0xB3 + Utf8 "print"; // #21 at 0xC9 + Utf8 "(Ljava/lang/String;)V"; // #22 at 0xD1 + String #24; // #23 at 0xE9 + Utf8 "SourceDebugExtensionPositive02 passed"; // #24 at 0xEC + class #26; // #25 at 0xF5 + Utf8 "org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02"; // #26 at 0xF8 + Utf8 "Code"; // #27 at 0x0149 + Utf8 "LineNumberTable"; // #28 at 0x0150 + Utf8 "LocalVariableTable"; // #29 at 0x0162 + Utf8 "this"; // #30 at 0x0177 + Utf8 "Lorg/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02;"; // #31 at 0x017E + Utf8 "calculate"; // #32 at 0x01D1 + Utf8 "()I"; // #33 at 0x01DD + Utf8 "i"; // #34 at 0x01E3 + Utf8 "I"; // #35 at 0x01E7 + Utf8 "e"; // #36 at 0x01EB + Utf8 "Ljava/lang/ArithmeticException;"; // #37 at 0x01EF + Utf8 "a1"; // #38 at 0x0211 + Utf8 "a2"; // #39 at 0x0216 + Utf8 "a3"; // #40 at 0x021B + Utf8 "StackMapTable"; // #41 at 0x0220 + Utf8 "SourceDebugExtension"; // #42 at 0x0230 + Utf8 "SourceFile"; // #43 at 0x0247 + Utf8 "SourceDebugExtension.java"; // #44 at 0x0254 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #25; // this_cpx + #2; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [0] { // Fields + } // end of Fields + + [2] { // Methods + { // method at 0x027C + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#27, 47) { // Code at 0x0284 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end of Traps + [2] { // Attributes + Attr(#28, 6) { // LineNumberTable at 0x029B + [1] { // line_number_table + 0 25; // at 0x02A7 + } + } // end of LineNumberTable + ; + Attr(#29, 12) { // LocalVariableTable at 0x02A7 + [1] { // LocalVariableTable + 0 5 30 31 0; // at 0x02B9 + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x02B9 + 0x0001; // access + #32; // name_index : calculate + #33; // descriptor_index : ()I + [1] { // Attributes + Attr(#27, 260) { // Code at 0x02C1 + 3; // max_stack + 5; // max_locals + Bytes[72]{ + 0x043C043D043E1B1C; + 0x1D646C3604150408; + 0xA2000C8401018404; + 0x01A7FFF4053DA700; + 0x073A04053E1B04A0; + 0x000D1C04A000081D; + 0x059F000DB2000912; + 0x0FB6001105ACB200; + 0x091217B6001103AC; + } + [1] { // Traps + 6 30 33 7; // at 0x0321 + } // end of Traps + [3] { // Attributes + Attr(#28, 62) { // LineNumberTable at 0x0323 + [15] { // line_number_table + 0 28; // at 0x032F + 2 29; // at 0x0333 + 4 30; // at 0x0337 + 6 32; // at 0x033B + 19 33; // at 0x033F + 22 32; // at 0x0343 + 28 35; // at 0x0347 + 30 38; // at 0x034B + 33 36; // at 0x034F + 35 37; // at 0x0353 + 37 39; // at 0x0357 + 52 40; // at 0x035B + 60 41; // at 0x035F + 62 43; // at 0x0363 + 70 44; // at 0x0367 + } + } // end of LineNumberTable + ; + Attr(#29, 62) { // LocalVariableTable at 0x0367 + [6] { // LocalVariableTable + 13 15 34 35 4; // at 0x0379 + 35 2 36 37 4; // at 0x0383 + 0 72 30 31 0; // at 0x038D + 2 70 38 35 1; // at 0x0397 + 4 68 39 35 2; // at 0x03A1 + 6 66 40 35 3; // at 0x03AB + } + } // end of LocalVariableTable + ; + Attr(#41, 26) { // StackMapTable at 0x03AB + [6] { // + 255b, 13, [5]{7b,25; 1b; 1b; 1b; 1b}, [0]{}; // full_frame + 250b, 14; // chop_frame 1 + 68b, [1]z{7b,7}; // same_locals_1_stack_item_frame + 3b; // same_frame + 14b; // same_frame + 9b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [2] { // Attributes + Attr(#43, 2) { // SourceFile at 0x03CD + #44; + } // end of SourceFile + ; + Attr(#42, 65540) { // SourceDebugExtension at 0x03D5 + 0x11 0x22 0x33 0x44; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5A 0x5B 0x5C 0x5D 0x5E 0x5F 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6A 0x6B 0x6C 0x6D 0x6E 0x6F 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF; + } // end of SourceDebugExtension + } // end of Attributes +} // end of class org/openjdk/asmtools/transform/case7902820/data/SourceDebugExtensionPositive02 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,97 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +package org/openjdk/asmtools/transform/case7903259/data; + +public final super class #10 /* BuildString */ version 60:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Asciz "java/lang/Object"; + const #5 = Asciz ""; + const #6 = Asciz "()V"; + const #7 = String #8; // "Hello" + const #8 = Asciz "Hello"; + const #9 = Field #10.#11; // BuildString.intialString:"Ljava/lang/String;" + const #10 = class #12; // BuildString + const #11 = NameAndType #13:#14; // intialString:"Ljava/lang/String;" + const #12 = Asciz "org/openjdk/asmtools/transform/case7903259/data/BuildString"; + const #13 = Asciz "intialString"; + const #14 = Asciz "Ljava/lang/String;"; + const #15 = Field #16.#17; // java/lang/System.out:"Ljava/io/PrintStream;" + const #16 = class #18; // java/lang/System + const #17 = NameAndType #19:#20; // out:"Ljava/io/PrintStream;" + const #18 = Asciz "java/lang/System"; + const #19 = Asciz "out"; + const #20 = Asciz "Ljava/io/PrintStream;"; + const #21 = String #22; // " World !" + const #22 = Asciz " World !"; + const #23 = Method #24.#25; // java/lang/String.concat:"(Ljava/lang/String;)Ljava/lang/String;" + const #24 = class #26; // java/lang/String + const #25 = NameAndType #27:#28; // concat:"(Ljava/lang/String;)Ljava/lang/String;" + const #26 = Asciz "java/lang/String"; + const #27 = Asciz "concat"; + const #28 = Asciz "(Ljava/lang/String;)Ljava/lang/String;"; + const #29 = Method #30.#31; // java/io/PrintStream.println:"(Ljava/lang/String;)V" + const #30 = class #32; // java/io/PrintStream + const #31 = NameAndType #33:#34; // println:"(Ljava/lang/String;)V" + const #32 = Asciz "java/io/PrintStream"; + const #33 = Asciz "println"; + const #34 = Asciz "(Ljava/lang/String;)V"; + const #35 = Asciz "ConstantValue"; + const #36 = Asciz "Code"; + const #37 = Asciz "LineNumberTable"; + const #38 = Asciz "LocalVariableTable"; + const #39 = Asciz "this"; + const #40 = Asciz "Lorg/openjdk/asmtools/transform/case7903259/data/BuildString;"; + const #41 = Asciz "printDecoratedString"; + const #42 = Asciz "SourceFile"; + const #43 = Asciz "BuildString.java"; + + private final Field #13:#14 = #7; // intialString:"Ljava/lang/String;" = String "Hello" + + public Method #5:#6 // "":"()V" + stack 2 locals 1 + { + var 0 #39:#40; // this:"Lorg/openjdk/asmtools/transform/case7903259/data/BuildString;" + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: aload_0; + 5: ldc #7; // String "Hello" + 7: putfield #9; // Field intialString:"Ljava/lang/String;" + 10: return; + endvar 0; + } + public Method #41:#6 // printDecoratedString:"()V" + stack 3 locals 1 + { + var 0 #39:#40; // this:"Lorg/openjdk/asmtools/transform/case7903259/data/BuildString;" + 0: getstatic #15; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 3: ldc #7; // String "Hello" + 5: ldc #21; // String " World !" + 7: invokevirtual #23; // Method java/lang/String.concat:"(Ljava/lang/String;)Ljava/lang/String;" + 10: invokevirtual #29; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 13: return; + endvar 0; + } +} // end Class BuildString compiled from "BuildString.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jcoder jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jcoder --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jcoder 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jcoder 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,165 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case7903259/data/BuildString { + 0xCAFEBABE; + 0; // minor version + 60; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Object"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + String #8; // #7 + Utf8 "Hello"; // #8 + Field #10 #11; // #9 + class #12; // #10 + NameAndType #13 #14; // #11 + Utf8 "org/openjdk/asmtools/transform/case7903259/data/BuildString"; // #12 + Utf8 "intialString"; // #13 + Utf8 "Ljava/lang/String;"; // #14 + Field #16 #17; // #15 + class #18; // #16 + NameAndType #19 #20; // #17 + Utf8 "java/lang/System"; // #18 + Utf8 "out"; // #19 + Utf8 "Ljava/io/PrintStream;"; // #20 + String #22; // #21 + Utf8 " World !"; // #22 + Method #24 #25; // #23 + class #26; // #24 + NameAndType #27 #28; // #25 + Utf8 "java/lang/String"; // #26 + Utf8 "concat"; // #27 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #28 + Method #30 #31; // #29 + class #32; // #30 + NameAndType #33 #34; // #31 + Utf8 "java/io/PrintStream"; // #32 + Utf8 "println"; // #33 + Utf8 "(Ljava/lang/String;)V"; // #34 + Utf8 "ConstantValue"; // #35 + Utf8 "Code"; // #36 + Utf8 "LineNumberTable"; // #37 + Utf8 "LocalVariableTable"; // #38 + Utf8 "this"; // #39 + Utf8 "Lorg/openjdk/asmtools/transform/case7903259/data/BuildString;"; // #40 + Utf8 "printDecoratedString"; // #41 + Utf8 "SourceFile"; // #42 + Utf8 "BuildString.java"; // #43 + } + + 0x0031; // access + #10; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0012; // access + #13; // name_index + #14; // descriptor_index + [] { // Attributes + Attr(#35) { // ConstantValue + #7; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#36) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB700012A1207B5; + 0x0009B1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#37) { // LineNumberTable + [] { // line_number_table + 0 3; + 4 4; + } + } // end of LineNumberTable + ; + Attr(#38) { // LocalVariableTable + [] { // LocalVariableTable + 0 11 39 40 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #41; // name_index + #6; // descriptor_index + [] { // Attributes + Attr(#36) { // Code + 3; // max_stack + 1; // max_locals + Bytes[]{ + 0xB2000F12071215B6; + 0x0017B6001DB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#37) { // LineNumberTable + [] { // line_number_table + 0 6; + 13 7; + } + } // end of LineNumberTable + ; + Attr(#38) { // LocalVariableTable + [] { // LocalVariableTable + 0 14 39 40 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#42) { // SourceFile + #43; + } // end of SourceFile + } // end of Attributes +} Binary files /srv/release.debian.org/tmp/VijDAKK687/jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jdec.bin and /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jdec.bin differ Binary files /srv/release.debian.org/tmp/VijDAKK687/jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jdis.bin and /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903259/jdis.bin differ diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org/openjdk/asmtools/transform/case7903454/data; + +public super class Utf8Code version 61:0 +{ + static Field ČeštinaAlphabet:"Ljava/lang/String;"; + static Field ქართულიენაAlphabet:"Ljava/lang/String;"; + static Field ΕλληνικάAlphabet:"Ljava/lang/String;"; + Field line:"Ljava/lang/String;"; + private Field نتیجہ:"Ljava/lang/String;"; + + private Method вычислитьБольшиеБуквы:"()Ljava/lang/String;" + stack 2 locals 1 + { + aload_0; + getfield Field line:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.codePoints:"()Ljava/util/stream/IntStream;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + test:"()Ljava/util/function/IntPredicate;" { + MethodType "(I)Z", + MethodHandle REF_invokeStatic:Method Utf8Code.lambda$вычислитьБольшиеБуквы$0:"(I)Z", + MethodType "(I)Z" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.filter:"(Ljava/util/function/IntPredicate;)Ljava/util/stream/IntStream;", 2; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + apply:"()Ljava/util/function/IntFunction;" { + MethodType "(I)Ljava/lang/Object;", + MethodHandle REF_invokeStatic:Method Utf8Code.lambda$вычислитьБольшиеБуквы$1:"(I)Ljava/lang/String;", + MethodType "(I)Ljava/lang/String;" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.mapToObj:"(Ljava/util/function/IntFunction;)Ljava/util/stream/Stream;", 2; + invokestatic Method java/util/stream/Collectors.joining:"()Ljava/util/stream/Collector;"; + invokeinterface InterfaceMethod java/util/stream/Stream.collect:"(Ljava/util/stream/Collector;)Ljava/lang/Object;", 2; + checkcast class java/lang/String; + areturn; + } + private Method вычислитьМаленькиеБуквы:"()Ljava/lang/String;" + stack 2 locals 1 + { + aload_0; + getfield Field line:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.codePoints:"()Ljava/util/stream/IntStream;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + test:"()Ljava/util/function/IntPredicate;" { + MethodType "(I)Z", + MethodHandle REF_invokeStatic:Method Utf8Code.lambda$вычислитьМаленькиеБуквы$2:"(I)Z", + MethodType "(I)Z" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.filter:"(Ljava/util/function/IntPredicate;)Ljava/util/stream/IntStream;", 2; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + apply:"()Ljava/util/function/IntFunction;" { + MethodType "(I)Ljava/lang/Object;", + MethodHandle REF_invokeStatic:Method Utf8Code.lambda$вычислитьМаленькиеБуквы$3:"(I)Ljava/lang/String;", + MethodType "(I)Ljava/lang/String;" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.mapToObj:"(Ljava/util/function/IntFunction;)Ljava/util/stream/Stream;", 2; + invokestatic Method java/util/stream/Collectors.joining:"()Ljava/util/stream/Collector;"; + invokeinterface InterfaceMethod java/util/stream/Stream.collect:"(Ljava/util/stream/Collector;)Ljava/lang/Object;", 2; + checkcast class java/lang/String; + areturn; + } + public Method calculate:"()I" + stack 4 locals 2 + { + aload_0; + getfield Field نتیجہ:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.isEmpty:"()Z"; + ifeq L38; + aload_0; + aload_0; + invokevirtual Method вычислитьБольшиеБуквы:"()Ljava/lang/String;"; + iconst_0; + bipush 20; + invokevirtual Method java/lang/String.substring:"(II)Ljava/lang/String;"; + aload_0; + invokevirtual Method вычислитьМаленькиеБуквы:"()Ljava/lang/String;"; + bipush 90; + invokevirtual Method java/lang/String.substring:"(I)Ljava/lang/String;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" { + String "\u0001\u0001" + }; + putfield Field نتیجہ:"Ljava/lang/String;"; + L38: stack_frame_type same; + aload_0; + getfield Field نتیجہ:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.length:"()I"; + istore_1; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload_1; + aload_0; + getfield Field نتیجہ:"Ljava/lang/String;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(ILjava/lang/String;)Ljava/lang/String;" { + String "\u0001 \u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + iload_1; + ireturn; + } + public Method "":"()V" + stack 6 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + aload_0; + ldc String ""; + putfield Field نتیجہ:"Ljava/lang/String;"; + aload_0; + getstatic Field ČeštinaAlphabet:"Ljava/lang/String;"; + ldc String " "; + ldc String ""; + invokevirtual Method java/lang/String.replaceAll:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; + getstatic Field ქართულიენაAlphabet:"Ljava/lang/String;"; + ldc String " "; + ldc String ""; + invokevirtual Method java/lang/String.replaceAll:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; + getstatic Field ΕλληνικάAlphabet:"Ljava/lang/String;"; + ldc String " "; + ldc String ""; + invokevirtual Method java/lang/String.replaceAll:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" { + String "\u0001\u0001\u0001" + }; + putfield Field line:"Ljava/lang/String;"; + return; + } + private static synthetic Method lambda$вычислитьМаленькиеБуквы$3:"(I)Ljava/lang/String;" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.toString:"(I)Ljava/lang/String;"; + areturn; + } + private static synthetic Method lambda$вычислитьМаленькиеБуквы$2:"(I)Z" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.isLowerCase:"(I)Z"; + ireturn; + } + private static synthetic Method lambda$вычислитьБольшиеБуквы$1:"(I)Ljava/lang/String;" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.toString:"(I)Ljava/lang/String;"; + areturn; + } + private static synthetic Method lambda$вычислитьБольшиеБуквы$0:"(I)Z" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.isUpperCase:"(I)Z"; + ireturn; + } + static Method "":"()V" + stack 1 locals 0 + { + ldc String "A Á B C Č D Ď E É Ě F G H Ch I Í J K L M N Ň O Ó P Q R Ř S Š T Ť U Ú Ů V W X Y Ý Z Ž a á b c č d ď e é ě f g h ch i í j k l m n ň o ó p q r ř s š t ť u ú ů v w x y ý z ž"; + putstatic Field ČeštinaAlphabet:"Ljava/lang/String;"; + ldc String "Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჷ ჸ ჹ ჺ ჻ ჼ ჽ ჾ ჿ"; + putstatic Field ქართულიენაAlphabet:"Ljava/lang/String;"; + ldc String "Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ/ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω"; + putstatic Field ΕλληνικάAlphabet:"Ljava/lang/String;"; + return; + } + + SourceFile "Utf8Code.java"; + + SourceDebugExtension { + "\tThe Memory Model determines what values can be read at every point in th"; + "e program.\nThe actions of each thread in isolation must behave as governe"; + "d by the semantics of that thread, with the exception that the values seen"; + " by each read are determined by the memory model.\nWhen we refer to this, "; + "we say that the program obeys intra-thread semantics.\n\tIntra-thread sema"; + "ntics are the semantics for single-threaded programs, and allow the comple"; + "te prediction of the behavior of a thread based on the values seen by read"; + " actions within the thread.\n\tTo determine if the actions of thread \'t\'"; + " in an execution are legal, we simply evaluate the implementation of threa"; + "d \"t\" as it would be performed in a single-threaded context, as defined "; + "in the rest of this specification."; + } + + public static final InnerClass Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + + BootstrapMethod #149 #156 #157 #156; + BootstrapMethod #149 #160 #162 #165; + BootstrapMethod #149 #156 #166 #156; + BootstrapMethod #149 #160 #169 #165; + BootstrapMethod #172 #178; + BootstrapMethod #172 #180; + BootstrapMethod #172 #182; +} // end Class Utf8Code compiled from "Utf8Code.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8Code.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +class org/openjdk/asmtools/transform/case7903454/data/Utf8Code { + 0xCAFEBABE; + 0; // minor version + 61; // version + [] { // Constant Pool + ; // first element is empty + Field #2 #3; // #1 + class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "org/openjdk/asmtools/transform/case7903454/data/Utf8Code"; // #4 + Utf8 "line"; // #5 + Utf8 "Ljava/lang/String;"; // #6 + Method #8 #9; // #7 + class #10; // #8 + NameAndType #11 #12; // #9 + Utf8 "java/lang/String"; // #10 + Utf8 "codePoints"; // #11 + Utf8 "()Ljava/util/stream/IntStream;"; // #12 + InvokeDynamic 0s #14; // #13 + NameAndType #15 #16; // #14 + Utf8 "test"; // #15 + Utf8 "()Ljava/util/function/IntPredicate;"; // #16 + InterfaceMethod #18 #19; // #17 + class #20; // #18 + NameAndType #21 #22; // #19 + Utf8 "java/util/stream/IntStream"; // #20 + Utf8 "filter"; // #21 + Utf8 "(Ljava/util/function/IntPredicate;)Ljava/util/stream/IntStream;"; // #22 + InvokeDynamic 1s #24; // #23 + NameAndType #25 #26; // #24 + Utf8 "apply"; // #25 + Utf8 "()Ljava/util/function/IntFunction;"; // #26 + InterfaceMethod #18 #28; // #27 + NameAndType #29 #30; // #28 + Utf8 "mapToObj"; // #29 + Utf8 "(Ljava/util/function/IntFunction;)Ljava/util/stream/Stream;"; // #30 + Method #32 #33; // #31 + class #34; // #32 + NameAndType #35 #36; // #33 + Utf8 "java/util/stream/Collectors"; // #34 + Utf8 "joining"; // #35 + Utf8 "()Ljava/util/stream/Collector;"; // #36 + InterfaceMethod #38 #39; // #37 + class #40; // #38 + NameAndType #41 #42; // #39 + Utf8 "java/util/stream/Stream"; // #40 + Utf8 "collect"; // #41 + Utf8 "(Ljava/util/stream/Collector;)Ljava/lang/Object;"; // #42 + InvokeDynamic 2s #14; // #43 + InvokeDynamic 3s #24; // #44 + Field #2 #46; // #45 + NameAndType #47 #6; // #46 + Utf8 "نتیجہ"; // #47 + Method #8 #49; // #48 + NameAndType #50 #51; // #49 + Utf8 "isEmpty"; // #50 + Utf8 "()Z"; // #51 + Method #2 #53; // #52 + NameAndType #54 #55; // #53 + Utf8 "вычислитьБольшиеБуквы"; // #54 + Utf8 "()Ljava/lang/String;"; // #55 + Method #8 #57; // #56 + NameAndType #58 #59; // #57 + Utf8 "substring"; // #58 + Utf8 "(II)Ljava/lang/String;"; // #59 + Method #2 #61; // #60 + NameAndType #62 #55; // #61 + Utf8 "вычислитьМаленькиеБуквы"; // #62 + Method #8 #64; // #63 + NameAndType #58 #65; // #64 + Utf8 "(I)Ljava/lang/String;"; // #65 + InvokeDynamic 4s #67; // #66 + NameAndType #68 #69; // #67 + Utf8 "makeConcatWithConstants"; // #68 + Utf8 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; // #69 + Method #8 #71; // #70 + NameAndType #72 #73; // #71 + Utf8 "length"; // #72 + Utf8 "()I"; // #73 + Field #75 #76; // #74 + class #77; // #75 + NameAndType #78 #79; // #76 + Utf8 "java/lang/System"; // #77 + Utf8 "out"; // #78 + Utf8 "Ljava/io/PrintStream;"; // #79 + InvokeDynamic 5s #81; // #80 + NameAndType #68 #82; // #81 + Utf8 "(ILjava/lang/String;)Ljava/lang/String;"; // #82 + Method #84 #85; // #83 + class #86; // #84 + NameAndType #87 #88; // #85 + Utf8 "java/io/PrintStream"; // #86 + Utf8 "println"; // #87 + Utf8 "(Ljava/lang/String;)V"; // #88 + Method #90 #91; // #89 + class #92; // #90 + NameAndType #93 #94; // #91 + Utf8 "java/lang/Object"; // #92 + Utf8 ""; // #93 + Utf8 "()V"; // #94 + String #96; // #95 + Utf8 ""; // #96 + Field #2 #98; // #97 + NameAndType #99 #6; // #98 + Utf8 "ČeštinaAlphabet"; // #99 + String #101; // #100 + Utf8 " "; // #101 + Method #8 #103; // #102 + NameAndType #104 #69; // #103 + Utf8 "replaceAll"; // #104 + Field #2 #106; // #105 + NameAndType #107 #6; // #106 + Utf8 "ქართულიენაAlphabet"; // #107 + Field #2 #109; // #108 + NameAndType #110 #6; // #109 + Utf8 "ΕλληνικάAlphabet"; // #110 + InvokeDynamic 6s #112; // #111 + NameAndType #68 #113; // #112 + Utf8 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; // #113 + Method #115 #116; // #114 + class #117; // #115 + NameAndType #118 #65; // #116 + Utf8 "java/lang/Character"; // #117 + Utf8 "toString"; // #118 + Method #115 #120; // #119 + NameAndType #121 #122; // #120 + Utf8 "isLowerCase"; // #121 + Utf8 "(I)Z"; // #122 + Method #115 #124; // #123 + NameAndType #125 #122; // #124 + Utf8 "isUpperCase"; // #125 + String #127; // #126 + Utf8 "A Á B C Č D Ď E É Ě F G H Ch I Í J K L M N Ň O Ó P Q R Ř S Š T Ť U Ú Ů V W X Y Ý Z Ž a á b c č d ď e é ě f g h ch i í j k l m n ň o ó p q r ř s š t ť u ú ů v w x y ý z ž"; // #127 + String #129; // #128 + Utf8 "Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჷ ჸ ჹ ჺ ჻ ჼ ჽ ჾ ჿ"; // #129 + String #131; // #130 + Utf8 "Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ/ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω"; // #131 + Utf8 "Code"; // #132 + Utf8 "LineNumberTable"; // #133 + Utf8 "LocalVariableTable"; // #134 + Utf8 "this"; // #135 + Utf8 "Lorg/openjdk/asmtools/transform/case7903454/data/Utf8Code;"; // #136 + Utf8 "calculate"; // #137 + Utf8 "I"; // #138 + Utf8 "StackMapTable"; // #139 + Utf8 "lambda$вычислитьМаленькиеБуквы$3"; // #140 + Utf8 "cp"; // #141 + Utf8 "lambda$вычислитьМаленькиеБуквы$2"; // #142 + Utf8 "lambda$вычислитьБольшиеБуквы$1"; // #143 + Utf8 "lambda$вычислитьБольшиеБуквы$0"; // #144 + Utf8 ""; // #145 + Utf8 "SourceFile"; // #146 + Utf8 "Utf8Code.java"; // #147 + Utf8 "BootstrapMethods"; // #148 + MethodHandle 6b #150; // #149 + Method #151 #152; // #150 + class #153; // #151 + NameAndType #154 #155; // #152 + Utf8 "java/lang/invoke/LambdaMetafactory"; // #153 + Utf8 "metafactory"; // #154 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; // #155 + MethodType #122; // #156 + MethodHandle 6b #158; // #157 + Method #2 #159; // #158 + NameAndType #144 #122; // #159 + MethodType #161; // #160 + Utf8 "(I)Ljava/lang/Object;"; // #161 + MethodHandle 6b #163; // #162 + Method #2 #164; // #163 + NameAndType #143 #65; // #164 + MethodType #65; // #165 + MethodHandle 6b #167; // #166 + Method #2 #168; // #167 + NameAndType #142 #122; // #168 + MethodHandle 6b #170; // #169 + Method #2 #171; // #170 + NameAndType #140 #65; // #171 + MethodHandle 6b #173; // #172 + Method #174 #175; // #173 + class #176; // #174 + NameAndType #68 #177; // #175 + Utf8 "java/lang/invoke/StringConcatFactory"; // #176 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #177 + String #179; // #178 + Utf8 "\u0001\u0001"; // #179 + String #181; // #180 + Utf8 "\u0001 \u0001"; // #181 + String #183; // #182 + Utf8 "\u0001\u0001\u0001"; // #183 + Utf8 "InnerClasses"; // #184 + class #186; // #185 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #186 + class #188; // #187 + Utf8 "java/lang/invoke/MethodHandles"; // #188 + Utf8 "Lookup"; // #189 + Utf8 "SourceDebugExtension"; // #190 + } + + 0x0021; // access + #2; // this_cpx + #90; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0008; // access + #99; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #107; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0008; // access + #110; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0000; // access + #5; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + ; + { // field + 0x0002; // access + #47; // name_index + #6; // descriptor_index + [] { // Attributes + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0002; // access + #54; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB40001B60007BA; + 0x000D0000B9001102; + 0x00BA00170000B900; + 0x1B0200B8001FB900; + 0x250200C00008B0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 21; + 27 22; + 38 21; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 39 135 136 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0002; // access + #62; // name_index + #55; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 2; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB40001B60007BA; + 0x002B0000B9001102; + 0x00BA002C0000B900; + 0x1B0200B8001FB900; + 0x250200C00008B0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 26; + 27 27; + 38 26; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 39 135 136 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #137; // name_index + #73; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 4; // max_stack + 2; // max_locals + Bytes[]{ + 0x2AB4002DB6003099; + 0x001F2A2AB6003403; + 0x1014B600382AB600; + 0x3C105AB6003FBA00; + 0x420000B5002D2AB4; + 0x002DB600463CB200; + 0x4A1B2AB4002DBA00; + 0x500000B600531BAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 31; + 10 32; + 38 33; + 46 34; + 62 35; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 64 135 136 0; + 46 18 72 138 1; + } + } // end of LocalVariableTable + ; + Attr(#139) { // StackMapTable + [] { // + 38b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #93; // name_index + #94; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 6; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB700592A125FB5; + 0x002D2AB200611264; + 0x125FB60066B20069; + 0x1264125FB60066B2; + 0x006C1264125FB600; + 0x66BA006F0000B500; + 0x01B1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 38; + 4 18; + 10 39; + 28 40; + 38 41; + 49 42; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 50 135 136 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x100A; // access + #140; // name_index + #65; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x1AB80072B0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 26; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 5 141 138 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x100A; // access + #142; // name_index + #122; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x1AB80077AC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 26; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 5 141 138 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x100A; // access + #143; // name_index + #65; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x1AB80072B0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 21; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 5 141 138 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x100A; // access + #144; // name_index + #122; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x1AB8007BAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 21; + } + } // end of LineNumberTable + ; + Attr(#134) { // LocalVariableTable + [] { // LocalVariableTable + 0 5 141 138 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0008; // access + #145; // name_index + #94; // descriptor_index + [] { // Attributes + Attr(#132) { // Code + 1; // max_stack + 0; // max_locals + Bytes[]{ + 0x127EB300611280B3; + 0x00691282B3006CB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#133) { // LineNumberTable + [] { // line_number_table + 0 6; + 5 10; + 10 14; + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#146) { // SourceFile + #147; + } // end of SourceFile + ; + Attr(#148) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #149; // bootstrap_method_ref + [] { // bootstrap_arguments + #156; + #157; + #156; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #149; // bootstrap_method_ref + [] { // bootstrap_arguments + #160; + #162; + #165; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #149; // bootstrap_method_ref + [] { // bootstrap_arguments + #156; + #166; + #156; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #149; // bootstrap_method_ref + [] { // bootstrap_arguments + #160; + #169; + #165; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #172; // bootstrap_method_ref + [] { // bootstrap_arguments + #178; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #172; // bootstrap_method_ref + [] { // bootstrap_arguments + #180; + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #172; // bootstrap_method_ref + [] { // bootstrap_arguments + #182; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#184) { // InnerClasses + [] { // classes + #185 #187 #189 25; + } + } // end of InnerClasses + ; + Attr(#190) { // SourceDebugExtension + "\u0000\tThe Memory Model determines what values can be read at every point in the program.\n"; + "The actions of each thread in isolation must behave as governed by the semantics of "; + "that thread, with the exception that the values seen by each read are determined by "; + "the memory model.\nWhen we refer to this, we say that the program obeys intra-thread "; + "semantics.\n\tIntra-thread semantics are the semantics for single-threaded programs, "; + "and allow the complete prediction of the behavior of a thread based on the values "; + "seen by read actions within the thread.\n\tTo determine if the actions of thread \'t\' in "; + "an execution are legal, we simply evaluate the implementation of thread \"t\" as it would "; + "be performed in a single-threaded context, as defined in the rest of this specification."; + } // end of SourceDebugExtension + } // end of Attributes +} diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + // SourceDebugExtension has broken Utf 8 string. +package org/openjdk/asmtools/transform/case7903454/data; + +public super class Utf8CodeBroken01 version 61:0 +{ + static Field ČeštinaAlphabet:"Ljava/lang/String;"; + static Field ქართულიენაAlphabet:"Ljava/lang/String;"; + static Field ΕλληνικάAlphabet:"Ljava/lang/String;"; + Field line:"Ljava/lang/String;"; + private Field نتیجہ:"Ljava/lang/String;"; + + private Method вычислитьБольшиеБуквы:"()Ljava/lang/String;" + stack 2 locals 1 + { + aload_0; + getfield Field line:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.codePoints:"()Ljava/util/stream/IntStream;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + test:"()Ljava/util/function/IntPredicate;" { + MethodType "(I)Z", + MethodHandle REF_invokeStatic:Method Utf8CodeBroken01.lambda$вычислитьБольшиеБуквы$0:"(I)Z", + MethodType "(I)Z" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.filter:"(Ljava/util/function/IntPredicate;)Ljava/util/stream/IntStream;", 2; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + apply:"()Ljava/util/function/IntFunction;" { + MethodType "(I)Ljava/lang/Object;", + MethodHandle REF_invokeStatic:Method Utf8CodeBroken01.lambda$вычислитьБольшиеБуквы$1:"(I)Ljava/lang/String;", + MethodType "(I)Ljava/lang/String;" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.mapToObj:"(Ljava/util/function/IntFunction;)Ljava/util/stream/Stream;", 2; + invokestatic Method java/util/stream/Collectors.joining:"()Ljava/util/stream/Collector;"; + invokeinterface InterfaceMethod java/util/stream/Stream.collect:"(Ljava/util/stream/Collector;)Ljava/lang/Object;", 2; + checkcast class java/lang/String; + areturn; + } + private Method вычислитьМаленькиеБуквы:"()Ljava/lang/String;" + stack 2 locals 1 + { + aload_0; + getfield Field line:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.codePoints:"()Ljava/util/stream/IntStream;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + test:"()Ljava/util/function/IntPredicate;" { + MethodType "(I)Z", + MethodHandle REF_invokeStatic:Method Utf8CodeBroken01.lambda$вычислитьМаленькиеБуквы$2:"(I)Z", + MethodType "(I)Z" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.filter:"(Ljava/util/function/IntPredicate;)Ljava/util/stream/IntStream;", 2; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;": + apply:"()Ljava/util/function/IntFunction;" { + MethodType "(I)Ljava/lang/Object;", + MethodHandle REF_invokeStatic:Method Utf8CodeBroken01.lambda$вычислитьМаленькиеБуквы$3:"(I)Ljava/lang/String;", + MethodType "(I)Ljava/lang/String;" + }; + invokeinterface InterfaceMethod java/util/stream/IntStream.mapToObj:"(Ljava/util/function/IntFunction;)Ljava/util/stream/Stream;", 2; + invokestatic Method java/util/stream/Collectors.joining:"()Ljava/util/stream/Collector;"; + invokeinterface InterfaceMethod java/util/stream/Stream.collect:"(Ljava/util/stream/Collector;)Ljava/lang/Object;", 2; + checkcast class java/lang/String; + areturn; + } + public Method calculate:"()I" + stack 4 locals 2 + { + aload_0; + getfield Field نتیجہ:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.isEmpty:"()Z"; + ifeq L38; + aload_0; + aload_0; + invokevirtual Method вычислитьБольшиеБуквы:"()Ljava/lang/String;"; + iconst_0; + bipush 20; + invokevirtual Method java/lang/String.substring:"(II)Ljava/lang/String;"; + aload_0; + invokevirtual Method вычислитьМаленькиеБуквы:"()Ljava/lang/String;"; + bipush 90; + invokevirtual Method java/lang/String.substring:"(I)Ljava/lang/String;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" { + String "\u0001\u0001" + }; + putfield Field نتیجہ:"Ljava/lang/String;"; + L38: stack_frame_type same; + aload_0; + getfield Field نتیجہ:"Ljava/lang/String;"; + invokevirtual Method java/lang/String.length:"()I"; + istore_1; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + iload_1; + aload_0; + getfield Field نتیجہ:"Ljava/lang/String;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(ILjava/lang/String;)Ljava/lang/String;" { + String "\u0001 \u0001" + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + iload_1; + ireturn; + } + public Method "":"()V" + stack 6 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + aload_0; + ldc String ""; + putfield Field نتیجہ:"Ljava/lang/String;"; + aload_0; + getstatic Field ČeštinaAlphabet:"Ljava/lang/String;"; + ldc String " "; + ldc String ""; + invokevirtual Method java/lang/String.replaceAll:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; + getstatic Field ქართულიენაAlphabet:"Ljava/lang/String;"; + ldc String " "; + ldc String ""; + invokevirtual Method java/lang/String.replaceAll:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; + getstatic Field ΕλληνικάAlphabet:"Ljava/lang/String;"; + ldc String " "; + ldc String ""; + invokevirtual Method java/lang/String.replaceAll:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + makeConcatWithConstants:"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" { + String "\u0001\u0001\u0001" + }; + putfield Field line:"Ljava/lang/String;"; + return; + } + private static synthetic Method lambda$вычислитьМаленькиеБуквы$3:"(I)Ljava/lang/String;" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.toString:"(I)Ljava/lang/String;"; + areturn; + } + private static synthetic Method lambda$вычислитьМаленькиеБуквы$2:"(I)Z" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.isLowerCase:"(I)Z"; + ireturn; + } + private static synthetic Method lambda$вычислитьБольшиеБуквы$1:"(I)Ljava/lang/String;" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.toString:"(I)Ljava/lang/String;"; + areturn; + } + private static synthetic Method lambda$вычислитьБольшиеБуквы$0:"(I)Z" + stack 1 locals 1 + { + iload_0; + invokestatic Method java/lang/Character.isUpperCase:"(I)Z"; + ireturn; + } + static Method "":"()V" + stack 1 locals 0 + { + ldc String "A Á B C Č D Ď E É Ě F G H Ch I Í J K L M N Ň O Ó P Q R Ř S Š T Ť U Ú Ů V W X Y Ý Z Ž a á b c č d ď e é ě f g h ch i í j k l m n ň o ó p q r ř s š t ť u ú ů v w x y ý z ž"; + putstatic Field ČeštinaAlphabet:"Ljava/lang/String;"; + ldc String "Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჷ ჸ ჹ ჺ ჻ ჼ ჽ ჾ ჿ"; + putstatic Field ქართულიენაAlphabet:"Ljava/lang/String;"; + ldc String "Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ/ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω"; + putstatic Field ΕλληνικάAlphabet:"Ljava/lang/String;"; + return; + } + + SourceFile "Utf8CodeBroken01.java"; + + public static final InnerClass Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + + BootstrapMethod #89 #86; + BootstrapMethod #89 #56; + BootstrapMethod #54 #55 #73 #55; + BootstrapMethod #54 #78 #152 #94; + BootstrapMethod #54 #78 #50 #94; + BootstrapMethod #54 #55 #142 #55; + BootstrapMethod #89 #69; + + SourceDebugExtension { + // == The bytes do not represent a valid modified UTF-8 encoding of a Unicode string. == + 0x00 0x0A 0x21 0xD0 0xA6 0xD0 0xB8 0xD1 0x82 0xD0 0xB0 0xD1 0x82; + 0xD0 0xB0 0x21; + } +} // end Class Utf8CodeBroken01 compiled from "Utf8CodeBroken01.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + // SourceDebugExtension has broken Utf 8 string. + class org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01 { + 0xCAFEBABE; + 0; // minor version + 61; // version + [185] { // Constant Pool + ; // first element is empty + String #80; // #1 at 0x0A + String #137; // #2 at 0x0D + String #159; // #3 at 0x10 + String #163; // #4 at 0x13 + String #115; // #5 at 0x16 + Field #109 #81; // #6 at 0x19 + InvokeDynamic 0s #164; // #7 at 0x1E + InterfaceMethod #119 #101; // #8 at 0x23 + Field #109 #68; // #9 at 0x28 + Field #109 #116; // #10 at 0x2D + Method #87 #158; // #11 at 0x32 + Method #109 #75; // #12 at 0x37 + Method #31 #44; // #13 at 0x3C + Method #87 #61; // #14 at 0x41 + Method #109 #134; // #15 at 0x46 + Method #87 #123; // #16 at 0x4B + Field #109 #139; // #17 at 0x50 + Method #165 #57; // #18 at 0x55 + InvokeDynamic 1s #125; // #19 at 0x5A + InvokeDynamic 2s #179; // #20 at 0x5F + InvokeDynamic 3s #88; // #21 at 0x64 + Method #31 #130; // #22 at 0x69 + InterfaceMethod #47 #93; // #23 at 0x6E + InvokeDynamic 4s #88; // #24 at 0x73 + Field #176 #171; // #25 at 0x78 + Method #74 #95; // #26 at 0x7D + InvokeDynamic 5s #179; // #27 at 0x82 + InterfaceMethod #119 #118; // #28 at 0x87 + Method #31 #107; // #29 at 0x8C + Method #31 #177; // #30 at 0x91 + class #117; // #31 at 0x96 + Method #31 #71; // #32 at 0x99 + InvokeDynamic 6s #150; // #33 at 0x9E + Method #31 #132; // #34 at 0xA3 + Method #128 #133; // #35 at 0xA8 + Field #109 #96; // #36 at 0xAD + Utf8 "java/lang/Object"; // #37 at 0xB2 + Utf8 "makeConcatWithConstants"; // #38 at 0xC5 + NameAndType #49 #135; // #39 at 0xDF + NameAndType #59 #72; // #40 at 0xE4 + Utf8 "()V"; // #41 at 0xE9 + Utf8 "InnerClasses"; // #42 at 0xEF + Utf8 "(Ljava/util/function/IntPredicate;)Ljava/util/stream/IntStream;"; // #43 at 0xFE + NameAndType #183 #67; // #44 at 0x0140 + Utf8 ""; // #45 at 0x0145 + class #161; // #46 at 0x0150 + class #172; // #47 at 0x0153 + Utf8 "toString"; // #48 at 0x0156 + Utf8 "lambda$вычислитьМаленькиеБуквы$3"; // #49 at 0x0161 + MethodHandle 6b #90; // #50 at 0x019B + Utf8 "()Ljava/lang/String;"; // #51 at 0x019F + Utf8 ""; // #52 at 0x01B6 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; // #53 at 0x01BF + MethodHandle 6b #120; // #54 at 0x028E + MethodType #72; // #55 at 0x0292 + String #160; // #56 at 0x0295 + NameAndType #52 #41; // #57 at 0x0298 + Utf8 "org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01"; // #58 at 0x029D + Utf8 "lambda$вычислитьМаленькиеБуквы$2"; // #59 at 0x02D8 + Utf8 "ქართულიენაAlphabet"; // #60 at 0x0312 + NameAndType #48 #135; // #61 at 0x033B + Utf8 "(I)Ljava/lang/Object;"; // #62 at 0x0340 + Utf8 "ΕλληνικάAlphabet"; // #63 at 0x0358 + Utf8 "(Ljava/lang/String;)V"; // #64 at 0x0373 + class #156; // #65 at 0x038B + Utf8 "نتیجہ"; // #66 at 0x038E + Utf8 "()I"; // #67 at 0x039B + NameAndType #180 #97; // #68 at 0x03A1 + String #144; // #69 at 0x03A6 + Utf8 "collect"; // #70 at 0x03A9 + NameAndType #146 #162; // #71 at 0x03B3 + Utf8 "(I)Z"; // #72 at 0x03B8 + MethodHandle 6b #102; // #73 at 0x03BF + class #110; // #74 at 0x03C3 + NameAndType #106 #51; // #75 at 0x03C6 + Utf8 "metafactory"; // #76 at 0x03CB + Utf8 "SourceFile"; // #77 at 0x03D9 + MethodType #62; // #78 at 0x03E6 + Utf8 "apply"; // #79 at 0x03E9 + Utf8 "Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ/ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω"; // #80 at 0x03F1 + NameAndType #60 #97; // #81 at 0x0486 + Utf8 "mapToObj"; // #82 at 0x048B + class #108; // #83 at 0x0496 + Utf8 "(Ljava/util/stream/Collector;)Ljava/lang/Object;"; // #84 at 0x0499 + NameAndType #38 #126; // #85 at 0x04CC + String #124; // #86 at 0x04D1 + class #145; // #87 at 0x04D4 + NameAndType #79 #153; // #88 at 0x04D7 + MethodHandle 6b #147; // #89 at 0x04DC + Method #109 #98; // #90 at 0x04E0 + Utf8 "(II)Ljava/lang/String;"; // #91 at 0x04E5 + NameAndType #76 #53; // #92 at 0x04FE + NameAndType #70 #84; // #93 at 0x0503 + MethodType #135; // #94 at 0x0508 + NameAndType #184 #151; // #95 at 0x050B + NameAndType #66 #97; // #96 at 0x0510 + Utf8 "Ljava/lang/String;"; // #97 at 0x0515 + NameAndType #143 #135; // #98 at 0x052A + NameAndType #154 #72; // #99 at 0x052F + Utf8 "out"; // #100 at 0x0534 + NameAndType #82 #121; // #101 at 0x053A + Method #109 #99; // #102 at 0x053F + Utf8 "java/lang/System"; // #103 at 0x0544 + Utf8 "test"; // #104 at 0x0557 + Method #109 #39; // #105 at 0x055E + Utf8 "вычислитьБольшиеБуквы"; // #106 at 0x0563 + NameAndType #181 #135; // #107 at 0x0590 + Utf8 "java/lang/invoke/StringConcatFactory"; // #108 at 0x0595 + class #58; // #109 at 0x05BC + Utf8 "java/util/stream/Collectors"; // #110 at 0x05BF + Utf8 "isUpperCase"; // #111 at 0x05DD + Utf8 "()Ljava/util/function/IntPredicate;"; // #112 at 0x05EB + Utf8 "вычислитьМаленькиеБуквы"; // #113 at 0x0611 + Utf8 "calculate"; // #114 at 0x0642 + Utf8 "A Á B C Č D Ď E É Ě F G H Ch I Í J K L M N Ň O Ó P Q R Ř S Š T Ť U Ú Ů V W X Y Ý Z Ž a á b c č d ď e é ě f g h ch i í j k l m n ň o ó p q r ř s š t ť u ú ů v w x y ý z ž"; // #115 at 0x064E + NameAndType #63 #97; // #116 at 0x0718 + Utf8 "java/lang/String"; // #117 at 0x071D + NameAndType #173 #43; // #118 at 0x0730 + class #178; // #119 at 0x0735 + Method #65 #92; // #120 at 0x0738 + Utf8 "(Ljava/util/function/IntFunction;)Ljava/util/stream/Stream;"; // #121 at 0x073D + Method #109 #40; // #122 at 0x077B + NameAndType #149 #72; // #123 at 0x0780 + Utf8 "\u0001 \u0001"; // #124 at 0x0785 + NameAndType #38 #162; // #125 at 0x078B + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #126 at 0x0790 + class #140; // #127 at 0x082B + class #131; // #128 at 0x082E + Utf8 "ČeštinaAlphabet"; // #129 at 0x0831 + NameAndType #136 #138; // #130 at 0x0845 + Utf8 "java/io/PrintStream"; // #131 at 0x084A + NameAndType #181 #91; // #132 at 0x0860 + NameAndType #167 #64; // #133 at 0x0865 + NameAndType #113 #51; // #134 at 0x086A + Utf8 "(I)Ljava/lang/String;"; // #135 at 0x086F + Utf8 "isEmpty"; // #136 at 0x0887 + Utf8 "Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჷ ჸ ჹ ჺ ჻ ჼ ჽ ჾ ჿ"; // #137 at 0x0891 + Utf8 "()Z"; // #138 at 0x09EB + NameAndType #129 #97; // #139 at 0x09F1 + Utf8 "java/lang/invoke/MethodHandles"; // #140 at 0x09F6 + Utf8 "StackMapTable"; // #141 at 0x0A17 + MethodHandle 6b #122; // #142 at 0x0A27 + Utf8 "lambda$вычислитьБольшиеБуквы$1"; // #143 at 0x0A2B + Utf8 "\u0001\u0001\u0001"; // #144 at 0x0A61 + Utf8 "java/lang/Character"; // #145 at 0x0A67 + Utf8 "replaceAll"; // #146 at 0x0A7D + Method #83 #85; // #147 at 0x0A8A + Utf8 "()Ljava/util/stream/IntStream;"; // #148 at 0x0A8F + Utf8 "isLowerCase"; // #149 at 0x0AB0 + NameAndType #38 #169; // #150 at 0x0ABE + Utf8 "()Ljava/util/stream/Collector;"; // #151 at 0x0AC3 + MethodHandle 6b #105; // #152 at 0x0AE4 + Utf8 "()Ljava/util/function/IntFunction;"; // #153 at 0x0AE8 + Utf8 "lambda$вычислитьБольшиеБуквы$0"; // #154 at 0x0B0D + Utf8 "codePoints"; // #155 at 0x0B43 + Utf8 "java/lang/invoke/LambdaMetafactory"; // #156 at 0x0B50 + Utf8 "Utf8CodeBroken01.java"; // #157 at 0x0B75 + NameAndType #111 #72; // #158 at 0x0B85 + Utf8 " "; // #159 at 0x0B8A + Utf8 "\u0001\u0001"; // #160 at 0x0B8E + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #161 at 0x0B93 + Utf8 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; // #162 at 0x0BBB + Utf8 ""; // #163 at 0x0BF6 + NameAndType #38 #166; // #164 at 0x0BF9 + class #37; // #165 at 0x0BFE + Utf8 "(ILjava/lang/String;)Ljava/lang/String;"; // #166 at 0x0C01 + Utf8 "println"; // #167 at 0x0C2B + Utf8 "SourceDebugExtension"; // #168 at 0x0C35 + Utf8 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"; // #169 at 0x0C4C + Utf8 "Code"; // #170 at 0x0C99 + NameAndType #100 #175; // #171 at 0x0CA0 + Utf8 "java/util/stream/Stream"; // #172 at 0x0CA5 + Utf8 "filter"; // #173 at 0x0CBF + Utf8 "Lookup"; // #174 at 0x0CC8 + Utf8 "Ljava/io/PrintStream;"; // #175 at 0x0CD1 + class #103; // #176 at 0x0CE9 + NameAndType #155 #148; // #177 at 0x0CEC + Utf8 "java/util/stream/IntStream"; // #178 at 0x0CF1 + NameAndType #104 #112; // #179 at 0x0D0E + Utf8 "line"; // #180 at 0x0D13 + Utf8 "substring"; // #181 at 0x0D1A + Utf8 "BootstrapMethods"; // #182 at 0x0D26 + Utf8 "length"; // #183 at 0x0D39 + Utf8 "joining"; // #184 at 0x0D42 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #109; // this_cpx + #165; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [5] { // Fields + { // field at 0x0D56 + 0x0008; // access + #129; // name_index : ČeštinaAlphabet + #97; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x0D5E + 0x0008; // access + #60; // name_index : ქართულიენაAlphabet + #97; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x0D66 + 0x0008; // access + #63; // name_index : ΕλληνικάAlphabet + #97; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x0D6E + 0x0000; // access + #180; // name_index : line + #97; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x0D76 + 0x0002; // access + #66; // name_index : نتیجہ + #97; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + } // end of Fields + + [9] { // Methods + { // method at 0x0D80 + 0x0002; // access + #106; // name_index : вычислитьБольшиеБуквы + #51; // descriptor_index : ()Ljava/lang/String; + [1] { // Attributes + Attr(#170, 51) { // Code at 0x0D88 + 2; // max_stack + 1; // max_locals + Bytes[39]{ + 0x2AB40009B6001EBA; + 0x00140000B9001C02; + 0x00BA00180000B900; + 0x080200B8001AB900; + 0x170200C0001FB0; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0DC1 + 0x0002; // access + #113; // name_index : вычислитьМаленькиеБуквы + #51; // descriptor_index : ()Ljava/lang/String; + [1] { // Attributes + Attr(#170, 51) { // Code at 0x0DC9 + 2; // max_stack + 1; // max_locals + Bytes[39]{ + 0x2AB40009B6001EBA; + 0x001B0000B9001C02; + 0x00BA00150000B900; + 0x080200B8001AB900; + 0x170200C0001FB0; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0E02 + 0x0001; // access + #114; // name_index : calculate + #67; // descriptor_index : ()I + [1] { // Attributes + Attr(#170, 85) { // Code at 0x0E0A + 4; // max_stack + 2; // max_locals + Bytes[64]{ + 0x2AB40024B6001699; + 0x001F2A2AB6000C03; + 0x1014B600222AB600; + 0x0F105AB6001DBA00; + 0x130000B500242AB4; + 0x0024B6000D3CB200; + 0x191B2AB40024BA00; + 0x070000B600231BAC; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#141, 3) { // StackMapTable at 0x0E5C + [1] { // + 38b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0E65 + 0x0001; // access + #52; // name_index : + #41; // descriptor_index : ()V + [1] { // Attributes + Attr(#170, 62) { // Code at 0x0E6D + 6; // max_stack + 1; // max_locals + Bytes[50]{ + 0x2AB700122A1204B5; + 0x00242AB200111203; + 0x1204B60020B20006; + 0x12031204B60020B2; + 0x000A12031204B600; + 0x20BA00210000B500; + 0x09B1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0EB1 + 0x100A; // access + #49; // name_index : lambda$вычислитьМаленькиеБуквы$3 + #135; // descriptor_index : (I)Ljava/lang/String; + [1] { // Attributes + Attr(#170, 17) { // Code at 0x0EB9 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x1AB8000EB0; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0ED0 + 0x100A; // access + #59; // name_index : lambda$вычислитьМаленькиеБуквы$2 + #72; // descriptor_index : (I)Z + [1] { // Attributes + Attr(#170, 17) { // Code at 0x0ED8 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x1AB80010AC; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0EEF + 0x100A; // access + #143; // name_index : lambda$вычислитьБольшиеБуквы$1 + #135; // descriptor_index : (I)Ljava/lang/String; + [1] { // Attributes + Attr(#170, 17) { // Code at 0x0EF7 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x1AB8000EB0; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0F0E + 0x100A; // access + #154; // name_index : lambda$вычислитьБольшиеБуквы$0 + #72; // descriptor_index : (I)Z + [1] { // Attributes + Attr(#170, 17) { // Code at 0x0F16 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x1AB8000BAC; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0F2D + 0x0008; // access + #45; // name_index : + #41; // descriptor_index : ()V + [1] { // Attributes + Attr(#170, 28) { // Code at 0x0F35 + 1; // max_stack + 0; // max_locals + Bytes[16]{ + 0x1205B300111202B3; + 0x00061201B3000AB1; + } + [0] { // Traps + } // end of Traps + [0] { // Attributes + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [4] { // Attributes + Attr(#77, 2) { // SourceFile at 0x0F59 + #157; + } // end of SourceFile + ; + Attr(#168, 16) { // SourceDebugExtension at 0x0F61 + // == The bytes do not represent a valid modified UTF-8 encoding of a Unicode string. == + 0x00 0x0A 0x21 0xD0 0xA6 0xD0 0xB8 0xD1 0x82 0xD0 0xB0 0xD1 0x82 0xD0; + 0xB0 0x21; + } // end of SourceDebugExtension + ; + Attr(#42, 10) { // InnerClasses at 0x0F77 + [1] { // classes + #46 #127 #174 25; // at 0x0F87 + } + } // end of InnerClasses + ; + Attr(#182, 60) { // BootstrapMethods at 0x0F87 + [7] { // bootstrap_methods + { // bootstrap_method + #89; // bootstrap_method_ref + [1] { // bootstrap_arguments + #86; // at 0x0F95 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #89; // bootstrap_method_ref + [1] { // bootstrap_arguments + #56; // at 0x0F9B + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #54; // bootstrap_method_ref + [3] { // bootstrap_arguments + #55; // at 0x0FA1 + #73; // at 0x0FA3 + #55; // at 0x0FA5 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #54; // bootstrap_method_ref + [3] { // bootstrap_arguments + #78; // at 0x0FAB + #152; // at 0x0FAD + #94; // at 0x0FAF + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #54; // bootstrap_method_ref + [3] { // bootstrap_arguments + #78; // at 0x0FB5 + #50; // at 0x0FB7 + #94; // at 0x0FB9 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #54; // bootstrap_method_ref + [3] { // bootstrap_arguments + #55; // at 0x0FBF + #142; // at 0x0FC1 + #55; // at 0x0FC3 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #89; // bootstrap_method_ref + [1] { // bootstrap_arguments + #69; // at 0x0FC9 + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + } // end of Attributes +} // end of class org/openjdk/asmtools/transform/case7903454/data/Utf8CodeBroken01 diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,564 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +package org/openjdk/asmtools/transform/case8302260; + +public super class #7 /* TestRunner */ implements #157 /* org/openjdk/asmtools/lib/transform/ITestRunner */ version 60:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Asciz "java/lang/Object"; + const #5 = Asciz ""; + const #6 = Asciz "()V"; + const #7 = class #8; // TestRunner + const #8 = Asciz "org/openjdk/asmtools/transform/case8302260/TestRunner"; + const #9 = Method #10.#11; // java/lang/Class.getPackageName:"()Ljava/lang/String;" + const #10 = class #12; // java/lang/Class + const #11 = NameAndType #13:#14; // getPackageName:"()Ljava/lang/String;" + const #12 = Asciz "java/lang/Class"; + const #13 = Asciz "getPackageName"; + const #14 = Asciz "()Ljava/lang/String;"; + const #15 = InvokeDynamic 0:#16; // #0:makeConcatWithConstants:"(Ljava/lang/String;)Ljava/lang/String;" + const #16 = NameAndType #17:#18; // makeConcatWithConstants:"(Ljava/lang/String;)Ljava/lang/String;" + const #17 = Asciz "makeConcatWithConstants"; + const #18 = Asciz "(Ljava/lang/String;)Ljava/lang/String;"; + const #19 = Field #7.#20; // TestRunner.superPackage:"Ljava/lang/String;" + const #20 = NameAndType #21:#22; // superPackage:"Ljava/lang/String;" + const #21 = Asciz "superPackage"; + const #22 = Asciz "Ljava/lang/String;"; + const #23 = class #24; // org/openjdk/asmtools/transform/case8302260/data/CTestClass + const #24 = Asciz "org/openjdk/asmtools/transform/case8302260/data/CTestClass"; + const #25 = String #26; // "stringField" + const #26 = Asciz "stringField"; + const #27 = class #28; // java/lang/String + const #28 = Asciz "java/lang/String"; + const #29 = Method #7.#30; // TestRunner.testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + const #30 = NameAndType #31:#32; // testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + const #31 = Asciz "testFieldRef"; + const #32 = Asciz "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;"; + const #33 = String #34; // "CTestClass" + const #34 = Asciz "CTestClass"; + const #35 = InterfaceMethod #36.#37; // java/lang/constant/ClassDesc.of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + const #36 = class #38; // java/lang/constant/ClassDesc + const #37 = NameAndType #39:#40; // of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + const #38 = Asciz "java/lang/constant/ClassDesc"; + const #39 = Asciz "of"; + const #40 = Asciz "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;"; + const #41 = Field #42.#43; // java/lang/constant/ConstantDescs.CD_String:"Ljava/lang/constant/ClassDesc;" + const #42 = class #44; // java/lang/constant/ConstantDescs + const #43 = NameAndType #45:#46; // CD_String:"Ljava/lang/constant/ClassDesc;" + const #44 = Asciz "java/lang/constant/ConstantDescs"; + const #45 = Asciz "CD_String"; + const #46 = Asciz "Ljava/lang/constant/ClassDesc;"; + const #47 = Method #7.#48; // TestRunner.testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + const #48 = NameAndType #49:#50; // testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + const #49 = Asciz "testFieldValue"; + const #50 = Asciz "(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V"; + const #51 = String #52; // "longField" + const #52 = Asciz "longField"; + const #53 = Field #54.#55; // java/lang/Long.TYPE:"Ljava/lang/Class;" + const #54 = class #56; // java/lang/Long + const #55 = NameAndType #57:#58; // TYPE:"Ljava/lang/Class;" + const #56 = Asciz "java/lang/Long"; + const #57 = Asciz "TYPE"; + const #58 = Asciz "Ljava/lang/Class;"; + const #59 = Field #42.#60; // java/lang/constant/ConstantDescs.CD_long:"Ljava/lang/constant/ClassDesc;" + const #60 = NameAndType #61:#46; // CD_long:"Ljava/lang/constant/ClassDesc;" + const #61 = Asciz "CD_long"; + const #62 = String #63; // "stringField2" + const #63 = Asciz "stringField2"; + const #64 = String #65; // "longField2" + const #65 = Asciz "longField2"; + const #66 = String #67; // "stringField3" + const #67 = Asciz "stringField3"; + const #68 = String #69; // "longField3" + const #69 = Asciz "longField3"; + const #70 = Field #71.#72; // java/lang/System.out:"Ljava/io/PrintStream;" + const #71 = class #73; // java/lang/System + const #72 = NameAndType #74:#75; // out:"Ljava/io/PrintStream;" + const #73 = Asciz "java/lang/System"; + const #74 = Asciz "out"; + const #75 = Asciz "Ljava/io/PrintStream;"; + const #76 = Method #77.#78; // java/lang/invoke/VarHandle.get:"()Ljava/lang/Object;" + const #77 = class #79; // java/lang/invoke/VarHandle + const #78 = NameAndType #80:#81; // get:"()Ljava/lang/Object;" + const #79 = Asciz "java/lang/invoke/VarHandle"; + const #80 = Asciz "get"; + const #81 = Asciz "()Ljava/lang/Object;"; + const #82 = InvokeDynamic 1:#83; // #1:makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" + const #83 = NameAndType #17:#84; // makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" + const #84 = Asciz "(Ljava/lang/Object;)Ljava/lang/String;"; + const #85 = Method #86.#87; // java/io/PrintStream.print:"(Ljava/lang/String;)V" + const #86 = class #88; // java/io/PrintStream + const #87 = NameAndType #89:#90; // print:"(Ljava/lang/String;)V" + const #88 = Asciz "java/io/PrintStream"; + const #89 = Asciz "print"; + const #90 = Asciz "(Ljava/lang/String;)V"; + const #91 = class #92; // java/lang/Throwable + const #92 = Asciz "java/lang/Throwable"; + const #93 = String #94; // " 1: failed" + const #94 = Asciz " 1: failed"; + const #95 = Method #86.#96; // java/io/PrintStream.println:"(Ljava/lang/String;)V" + const #96 = NameAndType #97:#90; // println:"(Ljava/lang/String;)V" + const #97 = Asciz "println"; + const #98 = Field #71.#99; // java/lang/System.err:"Ljava/io/PrintStream;" + const #99 = NameAndType #100:#75; // err:"Ljava/io/PrintStream;" + const #100 = Asciz "err"; + const #101 = Method #91.#102; // java/lang/Throwable.printStackTrace:"(Ljava/io/PrintStream;)V" + const #102 = NameAndType #103:#104; // printStackTrace:"(Ljava/io/PrintStream;)V" + const #103 = Asciz "printStackTrace"; + const #104 = Asciz "(Ljava/io/PrintStream;)V"; + const #105 = Method #106.#107; // java/lang/invoke/MethodHandles.lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + const #106 = class #108; // java/lang/invoke/MethodHandles + const #107 = NameAndType #109:#110; // lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + const #108 = Asciz "java/lang/invoke/MethodHandles"; + const #109 = Asciz "lookup"; + const #110 = Asciz "()Ljava/lang/invoke/MethodHandles$Lookup;"; + const #111 = InterfaceMethod #36.#112; // java/lang/constant/ClassDesc.resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object;" + const #112 = NameAndType #113:#114; // resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object;" + const #113 = Asciz "resolveConstantDesc"; + const #114 = Asciz "(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object;"; + const #115 = Method #116.#117; // java/lang/invoke/MethodHandles$Lookup.findStaticVarHandle:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + const #116 = class #118; // java/lang/invoke/MethodHandles$Lookup + const #117 = NameAndType #119:#32; // findStaticVarHandle:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + const #118 = Asciz "java/lang/invoke/MethodHandles$Lookup"; + const #119 = Asciz "findStaticVarHandle"; + const #120 = InvokeDynamic 2:#83; // #2:makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" + const #121 = String #122; // " 2: failed" + const #122 = Asciz " 2: failed"; + const #123 = Method #77.#124; // java/lang/invoke/VarHandle.describeConstable:"()Ljava/util/Optional;" + const #124 = NameAndType #125:#126; // describeConstable:"()Ljava/util/Optional;" + const #125 = Asciz "describeConstable"; + const #126 = Asciz "()Ljava/util/Optional;"; + const #127 = Method #128.#129; // java/util/Optional.orElseThrow:"()Ljava/lang/Object;" + const #128 = class #130; // java/util/Optional + const #129 = NameAndType #131:#81; // orElseThrow:"()Ljava/lang/Object;" + const #130 = Asciz "java/util/Optional"; + const #131 = Asciz "orElseThrow"; + const #132 = class #133; // java/lang/invoke/VarHandle$VarHandleDesc + const #133 = Asciz "java/lang/invoke/VarHandle$VarHandleDesc"; + const #134 = Method #132.#135; // java/lang/invoke/VarHandle$VarHandleDesc.resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/VarHandle;" + const #135 = NameAndType #113:#136; // resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/VarHandle;" + const #136 = Asciz "(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/VarHandle;"; + const #137 = InvokeDynamic 3:#83; // #3:makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" + const #138 = String #139; // " 3: failed" + const #139 = Asciz " 3: failed"; + const #140 = Method #132.#141; // java/lang/invoke/VarHandle$VarHandleDesc.ofStaticField:"(Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)Ljava/lang/invoke/VarHandle$VarHandleDesc;" + const #141 = NameAndType #142:#143; // ofStaticField:"(Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)Ljava/lang/invoke/VarHandle$VarHandleDesc;" + const #142 = Asciz "ofStaticField"; + const #143 = Asciz "(Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)Ljava/lang/invoke/VarHandle$VarHandleDesc;"; + const #144 = InvokeDynamic 4:#83; // #4:makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" + const #145 = String #146; // " 4: failed" + const #146 = Asciz " 4: failed"; + const #147 = InvokeDynamic 5:#16; // #5:makeConcatWithConstants:"(Ljava/lang/String;)Ljava/lang/String;" + const #148 = class #149; // java/lang/NoSuchFieldException + const #149 = Asciz "java/lang/NoSuchFieldException"; + const #150 = class #151; // java/lang/IllegalAccessException + const #151 = Asciz "java/lang/IllegalAccessException"; + const #152 = String #153; // "0: failed" + const #153 = Asciz "0: failed"; + const #154 = Method #155.#102; // java/lang/ReflectiveOperationException.printStackTrace:"(Ljava/io/PrintStream;)V" + const #155 = class #156; // java/lang/ReflectiveOperationException + const #156 = Asciz "java/lang/ReflectiveOperationException"; + const #157 = class #158; // org/openjdk/asmtools/lib/transform/ITestRunner + const #158 = Asciz "org/openjdk/asmtools/lib/transform/ITestRunner"; + const #159 = Asciz "Code"; + const #160 = Asciz "LineNumberTable"; + const #161 = Asciz "LocalVariableTable"; + const #162 = Asciz "this"; + const #163 = Asciz "Lorg/openjdk/asmtools/transform/case8302260/TestRunner;"; + const #164 = Asciz "run"; + const #165 = Asciz "vh"; + const #166 = Asciz "Ljava/lang/invoke/VarHandle;"; + const #167 = Asciz "e"; + const #168 = Asciz "Ljava/lang/Throwable;"; + const #169 = Asciz "vh2"; + const #170 = Asciz "vhd"; + const #171 = Asciz "Ljava/lang/invoke/VarHandle$VarHandleDesc;"; + const #172 = Asciz "obj"; + const #173 = Asciz "t"; + const #174 = Asciz "desc"; + const #175 = Asciz "name"; + const #176 = Asciz "fdesc"; + const #177 = Asciz "StackMapTable"; + const #178 = Asciz "Ljava/lang/ReflectiveOperationException;"; + const #179 = Asciz "rec"; + const #180 = Asciz "fname"; + const #181 = Asciz "type"; + const #182 = Asciz "LocalVariableTypeTable"; + const #183 = Asciz "Ljava/lang/Class<*>;"; + const #184 = Asciz "Signature"; + const #185 = Asciz "(Ljava/lang/Class<*>;Ljava/lang/String;Ljava/lang/Class<*>;)Ljava/lang/invoke/VarHandle;"; + const #186 = Asciz "SourceFile"; + const #187 = Asciz "TestRunner.java"; + const #188 = Asciz "BootstrapMethods"; + const #189 = MethodHandle 6:#190; // REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #190 = Method #191.#192; // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #191 = class #193; // java/lang/invoke/StringConcatFactory + const #192 = NameAndType #17:#194; // makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" + const #193 = Asciz "java/lang/invoke/StringConcatFactory"; + const #194 = Asciz "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + const #195 = String #196; // ".data" + const #196 = Asciz ".data"; + const #197 = String #198; // " 1: " + const #198 = Asciz " 1: "; + const #199 = String #200; // " 2: " + const #200 = Asciz " 2: "; + const #201 = String #202; // " 3: " + const #202 = Asciz " 3: "; + const #203 = String #204; // " 4: " + const #204 = Asciz " 4: "; + const #205 = String #206; // "0: " + const #206 = Asciz "0: "; + const #207 = Asciz "InnerClasses"; + const #208 = Asciz "Lookup"; + const #209 = Asciz "VarHandleDesc"; + + final Field #21:#22; // superPackage:"Ljava/lang/String;" + + public Method #5:#6 // "":"()V" + stack 2 locals 1 + { + var 0 #162:#163; // this:"Lorg/openjdk/asmtools/transform/case8302260/TestRunner;" + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: aload_0; + 5: ldc #7; // class TestRunner + 7: invokevirtual #9; // Method java/lang/Class.getPackageName:"()Ljava/lang/String;" + 10: invokedynamic #15; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/String;)Ljava/lang/String;" { + // String ".data" + // } + 15: putfield #19; // Field superPackage:"Ljava/lang/String;" + 18: return; + endvar 0; + } + public Method #164:#6 // run:"()V" + stack 5 locals 2 + { + var 0 #162:#163; // this:"Lorg/openjdk/asmtools/transform/case8302260/TestRunner;" + 0: aload_0; + 1: ldc #23; // class org/openjdk/asmtools/transform/case8302260/data/CTestClass + 3: ldc #25; // String "stringField" + 5: ldc #27; // class java/lang/String + 7: invokevirtual #29; // Method testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 10: astore_1; + var 1 #165:#166; // vh:"Ljava/lang/invoke/VarHandle;" + 11: aload_0; + 12: aload_1; + 13: aload_0; + 14: getfield #19; // Field superPackage:"Ljava/lang/String;" + 17: ldc #33; // String "CTestClass" + 19: invokestatic #35; // InterfaceMethod java/lang/constant/ClassDesc.of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + 22: ldc #25; // String "stringField" + 24: getstatic #41; // Field java/lang/constant/ConstantDescs.CD_String:"Ljava/lang/constant/ClassDesc;" + 27: invokevirtual #47; // Method testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + 30: aload_0; + 31: ldc #23; // class org/openjdk/asmtools/transform/case8302260/data/CTestClass + 33: ldc #51; // String "longField" + 35: getstatic #53; // Field java/lang/Long.TYPE:"Ljava/lang/Class;" + 38: invokevirtual #29; // Method testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 41: astore_1; + 42: aload_0; + 43: aload_1; + 44: aload_0; + 45: getfield #19; // Field superPackage:"Ljava/lang/String;" + 48: ldc #33; // String "CTestClass" + 50: invokestatic #35; // InterfaceMethod java/lang/constant/ClassDesc.of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + 53: ldc #51; // String "longField" + 55: getstatic #59; // Field java/lang/constant/ConstantDescs.CD_long:"Ljava/lang/constant/ClassDesc;" + 58: invokevirtual #47; // Method testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + 61: aload_0; + 62: ldc #23; // class org/openjdk/asmtools/transform/case8302260/data/CTestClass + 64: ldc #62; // String "stringField2" + 66: ldc #27; // class java/lang/String + 68: invokevirtual #29; // Method testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 71: astore_1; + 72: aload_0; + 73: aload_1; + 74: aload_0; + 75: getfield #19; // Field superPackage:"Ljava/lang/String;" + 78: ldc #33; // String "CTestClass" + 80: invokestatic #35; // InterfaceMethod java/lang/constant/ClassDesc.of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + 83: ldc #62; // String "stringField2" + 85: getstatic #41; // Field java/lang/constant/ConstantDescs.CD_String:"Ljava/lang/constant/ClassDesc;" + 88: invokevirtual #47; // Method testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + 91: aload_0; + 92: ldc #23; // class org/openjdk/asmtools/transform/case8302260/data/CTestClass + 94: ldc #64; // String "longField2" + 96: getstatic #53; // Field java/lang/Long.TYPE:"Ljava/lang/Class;" + 99: invokevirtual #29; // Method testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 102: astore_1; + 103: aload_0; + 104: aload_1; + 105: aload_0; + 106: getfield #19; // Field superPackage:"Ljava/lang/String;" + 109: ldc #33; // String "CTestClass" + 111: invokestatic #35; // InterfaceMethod java/lang/constant/ClassDesc.of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + 114: ldc #64; // String "longField2" + 116: getstatic #59; // Field java/lang/constant/ConstantDescs.CD_long:"Ljava/lang/constant/ClassDesc;" + 119: invokevirtual #47; // Method testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + 122: aload_0; + 123: ldc #23; // class org/openjdk/asmtools/transform/case8302260/data/CTestClass + 125: ldc #66; // String "stringField3" + 127: ldc #27; // class java/lang/String + 129: invokevirtual #29; // Method testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 132: astore_1; + 133: aload_0; + 134: aload_1; + 135: aload_0; + 136: getfield #19; // Field superPackage:"Ljava/lang/String;" + 139: ldc #33; // String "CTestClass" + 141: invokestatic #35; // InterfaceMethod java/lang/constant/ClassDesc.of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + 144: ldc #66; // String "stringField3" + 146: getstatic #41; // Field java/lang/constant/ConstantDescs.CD_String:"Ljava/lang/constant/ClassDesc;" + 149: invokevirtual #47; // Method testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + 152: aload_0; + 153: ldc #23; // class org/openjdk/asmtools/transform/case8302260/data/CTestClass + 155: ldc #68; // String "longField3" + 157: getstatic #53; // Field java/lang/Long.TYPE:"Ljava/lang/Class;" + 160: invokevirtual #29; // Method testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 163: astore_1; + 164: aload_0; + 165: aload_1; + 166: aload_0; + 167: getfield #19; // Field superPackage:"Ljava/lang/String;" + 170: ldc #33; // String "CTestClass" + 172: invokestatic #35; // InterfaceMethod java/lang/constant/ClassDesc.of:"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;" + 175: ldc #68; // String "longField3" + 177: getstatic #59; // Field java/lang/constant/ConstantDescs.CD_long:"Ljava/lang/constant/ClassDesc;" + 180: invokevirtual #47; // Method testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + 183: return; + endvar 0,1; + } + Method #49:#50 // testFieldValue:"(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V" + stack 5 locals 7 + { + var 0 #162:#163; // this:"Lorg/openjdk/asmtools/transform/case8302260/TestRunner;" + var 1 #165:#166; // vh:"Ljava/lang/invoke/VarHandle;" + var 2 #174:#46; // desc:"Ljava/lang/constant/ClassDesc;" + var 3 #175:#22; // name:"Ljava/lang/String;" + var 4 #176:#46; // fdesc:"Ljava/lang/constant/ClassDesc;" + 0: aload_1; + 1: ifnull 40; + try T0; + 4: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 7: aload_1; + 8: invokevirtual #76; // Method java/lang/invoke/VarHandle.get:"()Ljava/lang/Object;" + 11: invokedynamic #82; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" { + // String " 1: " + // } + 16: invokevirtual #85; // Method java/io/PrintStream.print:"(Ljava/lang/String;)V" + endtry T0; + 19: goto 40; + catch T0 #91; // java/lang/Throwable + 22: stack_frame_type stack1; + stack_map #91; // class java/lang/Throwable; + astore 5; + var 5 #167:#168; // e:"Ljava/lang/Throwable;" + 24: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 27: ldc #93; // String " 1: failed" + 29: invokevirtual #95; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 32: aload 5; + 34: getstatic #98; // Field java/lang/System.err:"Ljava/io/PrintStream;" + 37: invokevirtual #101; // Method java/lang/Throwable.printStackTrace:"(Ljava/io/PrintStream;)V" + endvar 5; + try T1; + 40: stack_frame_type same; + invokestatic #105; // Method java/lang/invoke/MethodHandles.lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + 43: aload_2; + 44: invokestatic #105; // Method java/lang/invoke/MethodHandles.lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + 47: invokeinterface #111, 2; // InterfaceMethod java/lang/constant/ClassDesc.resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object;" + 52: checkcast #10; // class java/lang/Class + 55: aload_3; + 56: aload 4; + 58: invokestatic #105; // Method java/lang/invoke/MethodHandles.lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + 61: invokeinterface #111, 2; // InterfaceMethod java/lang/constant/ClassDesc.resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object;" + 66: checkcast #10; // class java/lang/Class + 69: invokevirtual #115; // Method java/lang/invoke/MethodHandles$Lookup.findStaticVarHandle:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 72: astore 5; + var 5 #169:#166; // vh2:"Ljava/lang/invoke/VarHandle;" + 74: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 77: aload 5; + 79: invokevirtual #76; // Method java/lang/invoke/VarHandle.get:"()Ljava/lang/Object;" + 82: invokedynamic #120; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" { + // String " 2: " + // } + 87: invokevirtual #85; // Method java/io/PrintStream.print:"(Ljava/lang/String;)V" + endvar 5; + endtry T1; + 90: goto 111; + catch T1 #91; // java/lang/Throwable + 93: stack_frame_type stack1; + stack_map #91; // class java/lang/Throwable; + astore 5; + var 5 #167:#168; // e:"Ljava/lang/Throwable;" + 95: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 98: ldc #121; // String " 2: failed" + 100: invokevirtual #95; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 103: aload 5; + 105: getstatic #98; // Field java/lang/System.err:"Ljava/io/PrintStream;" + 108: invokevirtual #101; // Method java/lang/Throwable.printStackTrace:"(Ljava/io/PrintStream;)V" + endvar 5; + 111: stack_frame_type same; + aload_1; + 112: ifnull 174; + try T2; + 115: aload_1; + 116: invokevirtual #123; // Method java/lang/invoke/VarHandle.describeConstable:"()Ljava/util/Optional;" + 119: invokevirtual #127; // Method java/util/Optional.orElseThrow:"()Ljava/lang/Object;" + 122: checkcast #132; // class java/lang/invoke/VarHandle$VarHandleDesc + 125: astore 5; + var 5 #170:#171; // vhd:"Ljava/lang/invoke/VarHandle$VarHandleDesc;" + 127: aload 5; + 129: invokestatic #105; // Method java/lang/invoke/MethodHandles.lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + 132: invokevirtual #134; // Method java/lang/invoke/VarHandle$VarHandleDesc.resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/VarHandle;" + 135: astore 6; + var 6 #172:#166; // obj:"Ljava/lang/invoke/VarHandle;" + 137: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 140: aload 6; + 142: invokevirtual #76; // Method java/lang/invoke/VarHandle.get:"()Ljava/lang/Object;" + 145: invokedynamic #137; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" { + // String " 3: " + // } + 150: invokevirtual #85; // Method java/io/PrintStream.print:"(Ljava/lang/String;)V" + endvar 5,6; + endtry T2; + 153: goto 174; + catch T2 #91; // java/lang/Throwable + 156: stack_frame_type stack1; + stack_map #91; // class java/lang/Throwable; + astore 5; + var 5 #167:#168; // e:"Ljava/lang/Throwable;" + 158: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 161: ldc #138; // String " 3: failed" + 163: invokevirtual #95; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 166: aload 5; + 168: getstatic #98; // Field java/lang/System.err:"Ljava/io/PrintStream;" + 171: invokevirtual #101; // Method java/lang/Throwable.printStackTrace:"(Ljava/io/PrintStream;)V" + endvar 5; + try T3; + 174: stack_frame_type same; + aload_2; + 175: aload_3; + 176: aload 4; + 178: invokestatic #140; // Method java/lang/invoke/VarHandle$VarHandleDesc.ofStaticField:"(Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)Ljava/lang/invoke/VarHandle$VarHandleDesc;" + 181: astore 5; + var 5 #170:#171; // vhd:"Ljava/lang/invoke/VarHandle$VarHandleDesc;" + 183: aload 5; + 185: invokestatic #105; // Method java/lang/invoke/MethodHandles.lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + 188: invokevirtual #134; // Method java/lang/invoke/VarHandle$VarHandleDesc.resolveConstantDesc:"(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/VarHandle;" + 191: astore 6; + var 6 #172:#166; // obj:"Ljava/lang/invoke/VarHandle;" + 193: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 196: aload 6; + 198: invokevirtual #76; // Method java/lang/invoke/VarHandle.get:"()Ljava/lang/Object;" + 201: invokedynamic #144; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/Object;)Ljava/lang/String;" { + // String " 4: " + // } + 206: invokevirtual #95; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + endvar 5,6; + endtry T3; + 209: goto 230; + catch T3 #91; // java/lang/Throwable + 212: stack_frame_type stack1; + stack_map #91; // class java/lang/Throwable; + astore 5; + var 5 #173:#168; // t:"Ljava/lang/Throwable;" + 214: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 217: ldc #145; // String " 4: failed" + 219: invokevirtual #95; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 222: aload 5; + 224: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 227: invokevirtual #101; // Method java/lang/Throwable.printStackTrace:"(Ljava/io/PrintStream;)V" + endvar 5; + 230: stack_frame_type same; + return; + endvar 0,1,2,3,4; + } + Method #31:#32:#185 // testFieldRef:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;":"(Ljava/lang/Class<*>;Ljava/lang/String;Ljava/lang/Class<*>;)Ljava/lang/invoke/VarHandle;" + stack 4 locals 6 + { + var 0 #162:#163; // this:"Lorg/openjdk/asmtools/transform/case8302260/TestRunner;" + var 1 #179:#58; // rec:"Ljava/lang/Class;" + var 2 #180:#22; // fname:"Ljava/lang/String;" + var 3 #181:#58; // type:"Ljava/lang/Class;" + 0: aconst_null; + 1: astore 4; + try T0, T1; + var 4 #165:#166; // vh:"Ljava/lang/invoke/VarHandle;" + 3: invokestatic #105; // Method java/lang/invoke/MethodHandles.lookup:"()Ljava/lang/invoke/MethodHandles$Lookup;" + 6: aload_1; + 7: aload_2; + 8: aload_3; + 9: invokevirtual #115; // Method java/lang/invoke/MethodHandles$Lookup.findStaticVarHandle:"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;" + 12: astore 4; + 14: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 17: aload_2; + 18: invokedynamic #147; // InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: + // "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;": + // makeConcatWithConstants:"(Ljava/lang/String;)Ljava/lang/String;" { + // String "0: " + // } + 23: invokevirtual #85; // Method java/io/PrintStream.print:"(Ljava/lang/String;)V" + endtry T0,T1; + 26: goto 47; + catch T0 #148; // java/lang/NoSuchFieldException + catch T1 #150; // java/lang/IllegalAccessException + 29: stack_frame_type full; + locals_map #7, #10, #27, #10, #77; // class TestRunner, class java/lang/Class, class java/lang/String, class java/lang/Class, class java/lang/invoke/VarHandle; + stack_map #155; // class java/lang/ReflectiveOperationException; + astore 5; + var 5 #167:#178; // e:"Ljava/lang/ReflectiveOperationException;" + 31: getstatic #70; // Field java/lang/System.out:"Ljava/io/PrintStream;" + 34: ldc #152; // String "0: failed" + 36: invokevirtual #95; // Method java/io/PrintStream.println:"(Ljava/lang/String;)V" + 39: aload 5; + 41: getstatic #98; // Field java/lang/System.err:"Ljava/io/PrintStream;" + 44: invokevirtual #154; // Method java/lang/ReflectiveOperationException.printStackTrace:"(Ljava/io/PrintStream;)V" + endvar 5; + 47: stack_frame_type same; + aload 4; + 49: areturn; + endvar 0,1,2,3,4; + } + + public static final InnerClass #208 = #116 of #106; // Lookup = class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + public static final InnerClass #209 = #132 of #77; // VarHandleDesc = class java/lang/invoke/VarHandle$VarHandleDesc of class java/lang/invoke/VarHandle + + BootstrapMethod #189 #195; + BootstrapMethod #189 #197; + BootstrapMethod #189 #199; + BootstrapMethod #189 #201; + BootstrapMethod #189 #203; + BootstrapMethod #189 #205; +} // end Class TestRunner compiled from "TestRunner.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/TestRunner.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,601 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case8302260/TestRunner { + 0xCAFEBABE; + 0; // minor version + 60; // version + [210] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "org/openjdk/asmtools/transform/case8302260/TestRunner"; // #8 at 0x3C + Method #10 #11; // #9 at 0x74 + class #12; // #10 at 0x79 + NameAndType #13 #14; // #11 at 0x7C + Utf8 "java/lang/Class"; // #12 at 0x81 + Utf8 "getPackageName"; // #13 at 0x93 + Utf8 "()Ljava/lang/String;"; // #14 at 0xA4 + InvokeDynamic 0s #16; // #15 at 0xBB + NameAndType #17 #18; // #16 at 0xC0 + Utf8 "makeConcatWithConstants"; // #17 at 0xC5 + Utf8 "(Ljava/lang/String;)Ljava/lang/String;"; // #18 at 0xDF + Field #7 #20; // #19 at 0x0108 + NameAndType #21 #22; // #20 at 0x010D + Utf8 "superPackage"; // #21 at 0x0112 + Utf8 "Ljava/lang/String;"; // #22 at 0x0121 + class #24; // #23 at 0x0136 + Utf8 "org/openjdk/asmtools/transform/case8302260/data/CTestClass"; // #24 at 0x0139 + String #26; // #25 at 0x0176 + Utf8 "stringField"; // #26 at 0x0179 + class #28; // #27 at 0x0187 + Utf8 "java/lang/String"; // #28 at 0x018A + Method #7 #30; // #29 at 0x019D + NameAndType #31 #32; // #30 at 0x01A2 + Utf8 "testFieldRef"; // #31 at 0x01A7 + Utf8 "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;"; // #32 at 0x01B6 + String #34; // #33 at 0x020B + Utf8 "CTestClass"; // #34 at 0x020E + InterfaceMethod #36 #37; // #35 at 0x021B + class #38; // #36 at 0x0220 + NameAndType #39 #40; // #37 at 0x0223 + Utf8 "java/lang/constant/ClassDesc"; // #38 at 0x0228 + Utf8 "of"; // #39 at 0x0247 + Utf8 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/constant/ClassDesc;"; // #40 at 0x024C + Field #42 #43; // #41 at 0x0293 + class #44; // #42 at 0x0298 + NameAndType #45 #46; // #43 at 0x029B + Utf8 "java/lang/constant/ConstantDescs"; // #44 at 0x02A0 + Utf8 "CD_String"; // #45 at 0x02C3 + Utf8 "Ljava/lang/constant/ClassDesc;"; // #46 at 0x02CF + Method #7 #48; // #47 at 0x02F0 + NameAndType #49 #50; // #48 at 0x02F5 + Utf8 "testFieldValue"; // #49 at 0x02FA + Utf8 "(Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V"; // #50 at 0x030B + String #52; // #51 at 0x037B + Utf8 "longField"; // #52 at 0x037E + Field #54 #55; // #53 at 0x038A + class #56; // #54 at 0x038F + NameAndType #57 #58; // #55 at 0x0392 + Utf8 "java/lang/Long"; // #56 at 0x0397 + Utf8 "TYPE"; // #57 at 0x03A8 + Utf8 "Ljava/lang/Class;"; // #58 at 0x03AF + Field #42 #60; // #59 at 0x03C3 + NameAndType #61 #46; // #60 at 0x03C8 + Utf8 "CD_long"; // #61 at 0x03CD + String #63; // #62 at 0x03D7 + Utf8 "stringField2"; // #63 at 0x03DA + String #65; // #64 at 0x03E9 + Utf8 "longField2"; // #65 at 0x03EC + String #67; // #66 at 0x03F9 + Utf8 "stringField3"; // #67 at 0x03FC + String #69; // #68 at 0x040B + Utf8 "longField3"; // #69 at 0x040E + Field #71 #72; // #70 at 0x041B + class #73; // #71 at 0x0420 + NameAndType #74 #75; // #72 at 0x0423 + Utf8 "java/lang/System"; // #73 at 0x0428 + Utf8 "out"; // #74 at 0x043B + Utf8 "Ljava/io/PrintStream;"; // #75 at 0x0441 + Method #77 #78; // #76 at 0x0459 + class #79; // #77 at 0x045E + NameAndType #80 #81; // #78 at 0x0461 + Utf8 "java/lang/invoke/VarHandle"; // #79 at 0x0466 + Utf8 "get"; // #80 at 0x0483 + Utf8 "()Ljava/lang/Object;"; // #81 at 0x0489 + InvokeDynamic 1s #83; // #82 at 0x04A0 + NameAndType #17 #84; // #83 at 0x04A5 + Utf8 "(Ljava/lang/Object;)Ljava/lang/String;"; // #84 at 0x04AA + Method #86 #87; // #85 at 0x04D3 + class #88; // #86 at 0x04D8 + NameAndType #89 #90; // #87 at 0x04DB + Utf8 "java/io/PrintStream"; // #88 at 0x04E0 + Utf8 "print"; // #89 at 0x04F6 + Utf8 "(Ljava/lang/String;)V"; // #90 at 0x04FE + class #92; // #91 at 0x0516 + Utf8 "java/lang/Throwable"; // #92 at 0x0519 + String #94; // #93 at 0x052F + Utf8 " 1: failed"; // #94 at 0x0532 + Method #86 #96; // #95 at 0x053F + NameAndType #97 #90; // #96 at 0x0544 + Utf8 "println"; // #97 at 0x0549 + Field #71 #99; // #98 at 0x0553 + NameAndType #100 #75; // #99 at 0x0558 + Utf8 "err"; // #100 at 0x055D + Method #91 #102; // #101 at 0x0563 + NameAndType #103 #104; // #102 at 0x0568 + Utf8 "printStackTrace"; // #103 at 0x056D + Utf8 "(Ljava/io/PrintStream;)V"; // #104 at 0x057F + Method #106 #107; // #105 at 0x059A + class #108; // #106 at 0x059F + NameAndType #109 #110; // #107 at 0x05A2 + Utf8 "java/lang/invoke/MethodHandles"; // #108 at 0x05A7 + Utf8 "lookup"; // #109 at 0x05C8 + Utf8 "()Ljava/lang/invoke/MethodHandles$Lookup;"; // #110 at 0x05D1 + InterfaceMethod #36 #112; // #111 at 0x05FD + NameAndType #113 #114; // #112 at 0x0602 + Utf8 "resolveConstantDesc"; // #113 at 0x0607 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object;"; // #114 at 0x061D + Method #116 #117; // #115 at 0x065B + class #118; // #116 at 0x0660 + NameAndType #119 #32; // #117 at 0x0663 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #118 at 0x0668 + Utf8 "findStaticVarHandle"; // #119 at 0x0690 + InvokeDynamic 2s #83; // #120 at 0x06A6 + String #122; // #121 at 0x06AB + Utf8 " 2: failed"; // #122 at 0x06AE + Method #77 #124; // #123 at 0x06BB + NameAndType #125 #126; // #124 at 0x06C0 + Utf8 "describeConstable"; // #125 at 0x06C5 + Utf8 "()Ljava/util/Optional;"; // #126 at 0x06D9 + Method #128 #129; // #127 at 0x06F2 + class #130; // #128 at 0x06F7 + NameAndType #131 #81; // #129 at 0x06FA + Utf8 "java/util/Optional"; // #130 at 0x06FF + Utf8 "orElseThrow"; // #131 at 0x0714 + class #133; // #132 at 0x0722 + Utf8 "java/lang/invoke/VarHandle$VarHandleDesc"; // #133 at 0x0725 + Method #132 #135; // #134 at 0x0750 + NameAndType #113 #136; // #135 at 0x0755 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/VarHandle;"; // #136 at 0x075A + InvokeDynamic 3s #83; // #137 at 0x07A2 + String #139; // #138 at 0x07A7 + Utf8 " 3: failed"; // #139 at 0x07AA + Method #132 #141; // #140 at 0x07B7 + NameAndType #142 #143; // #141 at 0x07BC + Utf8 "ofStaticField"; // #142 at 0x07C1 + Utf8 "(Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)Ljava/lang/invoke/VarHandle$VarHandleDesc;"; // #143 at 0x07D1 + InvokeDynamic 4s #83; // #144 at 0x084E + String #146; // #145 at 0x0853 + Utf8 " 4: failed"; // #146 at 0x0856 + InvokeDynamic 5s #16; // #147 at 0x0863 + class #149; // #148 at 0x0868 + Utf8 "java/lang/NoSuchFieldException"; // #149 at 0x086B + class #151; // #150 at 0x088C + Utf8 "java/lang/IllegalAccessException"; // #151 at 0x088F + String #153; // #152 at 0x08B2 + Utf8 "0: failed"; // #153 at 0x08B5 + Method #155 #102; // #154 at 0x08C1 + class #156; // #155 at 0x08C6 + Utf8 "java/lang/ReflectiveOperationException"; // #156 at 0x08C9 + class #158; // #157 at 0x08F2 + Utf8 "org/openjdk/asmtools/lib/transform/ITestRunner"; // #158 at 0x08F5 + Utf8 "Code"; // #159 at 0x0926 + Utf8 "LineNumberTable"; // #160 at 0x092D + Utf8 "LocalVariableTable"; // #161 at 0x093F + Utf8 "this"; // #162 at 0x0954 + Utf8 "Lorg/openjdk/asmtools/transform/case8302260/TestRunner;"; // #163 at 0x095B + Utf8 "run"; // #164 at 0x0995 + Utf8 "vh"; // #165 at 0x099B + Utf8 "Ljava/lang/invoke/VarHandle;"; // #166 at 0x09A0 + Utf8 "e"; // #167 at 0x09BF + Utf8 "Ljava/lang/Throwable;"; // #168 at 0x09C3 + Utf8 "vh2"; // #169 at 0x09DB + Utf8 "vhd"; // #170 at 0x09E1 + Utf8 "Ljava/lang/invoke/VarHandle$VarHandleDesc;"; // #171 at 0x09E7 + Utf8 "obj"; // #172 at 0x0A14 + Utf8 "t"; // #173 at 0x0A1A + Utf8 "desc"; // #174 at 0x0A1E + Utf8 "name"; // #175 at 0x0A25 + Utf8 "fdesc"; // #176 at 0x0A2C + Utf8 "StackMapTable"; // #177 at 0x0A34 + Utf8 "Ljava/lang/ReflectiveOperationException;"; // #178 at 0x0A44 + Utf8 "rec"; // #179 at 0x0A6F + Utf8 "fname"; // #180 at 0x0A75 + Utf8 "type"; // #181 at 0x0A7D + Utf8 "LocalVariableTypeTable"; // #182 at 0x0A84 + Utf8 "Ljava/lang/Class<*>;"; // #183 at 0x0A9D + Utf8 "Signature"; // #184 at 0x0AB4 + Utf8 "(Ljava/lang/Class<*>;Ljava/lang/String;Ljava/lang/Class<*>;)Ljava/lang/invoke/VarHandle;"; // #185 at 0x0AC0 + Utf8 "SourceFile"; // #186 at 0x0B1B + Utf8 "TestRunner.java"; // #187 at 0x0B28 + Utf8 "BootstrapMethods"; // #188 at 0x0B3A + MethodHandle 6b #190; // #189 at 0x0B4D + Method #191 #192; // #190 at 0x0B51 + class #193; // #191 at 0x0B56 + NameAndType #17 #194; // #192 at 0x0B59 + Utf8 "java/lang/invoke/StringConcatFactory"; // #193 at 0x0B5E + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; // #194 at 0x0B85 + String #196; // #195 at 0x0C20 + Utf8 ".data"; // #196 at 0x0C23 + String #198; // #197 at 0x0C2C + Utf8 " 1: "; // #198 at 0x0C2F + String #200; // #199 at 0x0C37 + Utf8 " 2: "; // #200 at 0x0C3A + String #202; // #201 at 0x0C42 + Utf8 " 3: "; // #202 at 0x0C45 + String #204; // #203 at 0x0C4D + Utf8 " 4: "; // #204 at 0x0C50 + String #206; // #205 at 0x0C58 + Utf8 "0: "; // #206 at 0x0C5B + Utf8 "InnerClasses"; // #207 at 0x0C62 + Utf8 "Lookup"; // #208 at 0x0C71 + Utf8 "VarHandleDesc"; // #209 at 0x0C7A + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #7; // this_cpx + #2; // super_cpx + + [1] { // Interfaces + #157; // org/openjdk/asmtools/lib/transform/ITestRunner at 0x0C94 + } // end of Interfaces + + [1] { // Fields + { // field at 0x0C96 + 0x0010; // access + #21; // name_index : superPackage + #22; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + } // end of Fields + + [4] { // Methods + { // method at 0x0CA0 + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#159, 65) { // Code at 0x0CA8 + 2; // max_stack + 1; // max_locals + Bytes[19]{ + 0x2AB700012A1207B6; + 0x0009BA000F0000B5; + 0x0013B1; + } + [0] { // Traps + } // end of Traps + [2] { // Attributes + Attr(#160, 10) { // LineNumberTable at 0x0CCD + [2] { // line_number_table + 0 35; // at 0x0CD9 + 4 37; // at 0x0CDD + } + } // end of LineNumberTable + ; + Attr(#161, 12) { // LocalVariableTable at 0x0CDD + [1] { // LocalVariableTable + 0 19 162 163 0; // at 0x0CEF + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0CEF + 0x0001; // access + #164; // name_index : run + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#159, 284) { // Code at 0x0CF7 + 5; // max_stack + 2; // max_locals + Bytes[184]{ + 0x2A12171219121BB6; + 0x001D4C2A2B2AB400; + 0x131221B800231219; + 0xB20029B6002F2A12; + 0x171233B20035B600; + 0x1D4C2A2B2AB40013; + 0x1221B800231233B2; + 0x003BB6002F2A1217; + 0x123E121BB6001D4C; + 0x2A2B2AB400131221; + 0xB80023123EB20029; + 0xB6002F2A12171240; + 0xB20035B6001D4C2A; + 0x2B2AB400131221B8; + 0x00231240B2003BB6; + 0x002F2A1217124212; + 0x1BB6001D4C2A2B2A; + 0xB400131221B80023; + 0x1242B20029B6002F; + 0x2A12171244B20035; + 0xB6001D4C2A2B2AB4; + 0x00131221B8002312; + 0x44B2003BB6002FB1; + } + [0] { // Traps + } // end of Traps + [2] { // Attributes + Attr(#160, 54) { // LineNumberTable at 0x0DC1 + [13] { // line_number_table + 0 44; // at 0x0DCD + 11 45; // at 0x0DD1 + 30 46; // at 0x0DD5 + 42 47; // at 0x0DD9 + 61 49; // at 0x0DDD + 72 50; // at 0x0DE1 + 91 51; // at 0x0DE5 + 103 52; // at 0x0DE9 + 122 54; // at 0x0DED + 133 55; // at 0x0DF1 + 152 56; // at 0x0DF5 + 164 57; // at 0x0DF9 + 183 58; // at 0x0DFD + } + } // end of LineNumberTable + ; + Attr(#161, 22) { // LocalVariableTable at 0x0DFD + [2] { // LocalVariableTable + 0 184 162 163 0; // at 0x0E0F + 11 173 165 166 1; // at 0x0E19 + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0E19 + 0x0000; // access + #49; // name_index : testFieldValue + #50; // descriptor_index : (Ljava/lang/invoke/VarHandle;Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;)V + [1] { // Attributes + Attr(#159, 579) { // Code at 0x0E21 + 5; // max_stack + 7; // max_locals + Bytes[231]{ + 0x2BC60027B200462B; + 0xB6004CBA00520000; + 0xB60055A700153A05; + 0xB20046125DB6005F; + 0x1905B20062B60065; + 0xB800692CB80069B9; + 0x006F0200C0000A2D; + 0x1904B80069B9006F; + 0x0200C0000AB60073; + 0x3A05B200461905B6; + 0x004CBA00780000B6; + 0x0055A700153A05B2; + 0x00461279B6005F19; + 0x05B20062B600652B; + 0xC6003E2BB6007BB6; + 0x007FC000843A0519; + 0x05B80069B600863A; + 0x06B200461906B600; + 0x4CBA00890000B600; + 0x55A700153A05B200; + 0x46128AB6005F1905; + 0xB20062B600652C2D; + 0x1904B8008C3A0519; + 0x05B80069B600863A; + 0x06B200461906B600; + 0x4CBA00900000B600; + 0x5FA700153A05B200; + 0x461291B6005F1905; + 0xB20046B60065B1; + } + [4] { // Traps + 4 19 22 91; // at 0x0F20 + 40 90 93 91; // at 0x0F28 + 115 153 156 91; // at 0x0F30 + 174 209 212 91; // at 0x0F38 + } // end of Traps + [3] { // Attributes + Attr(#160, 122) { // LineNumberTable at 0x0F3A + [30] { // line_number_table + 0 61; // at 0x0F46 + 4 63; // at 0x0F4A + 19 67; // at 0x0F4E + 22 64; // at 0x0F52 + 24 65; // at 0x0F56 + 32 66; // at 0x0F5A + 40 70; // at 0x0F5E + 58 71; // at 0x0F62 + 69 70; // at 0x0F66 + 74 72; // at 0x0F6A + 90 76; // at 0x0F6E + 93 73; // at 0x0F72 + 95 74; // at 0x0F76 + 103 75; // at 0x0F7A + 111 77; // at 0x0F7E + 115 79; // at 0x0F82 + 127 80; // at 0x0F86 + 137 81; // at 0x0F8A + 153 85; // at 0x0F8E + 156 82; // at 0x0F92 + 158 83; // at 0x0F96 + 166 84; // at 0x0F9A + 174 88; // at 0x0F9E + 183 89; // at 0x0FA2 + 193 90; // at 0x0FA6 + 209 94; // at 0x0FAA + 212 91; // at 0x0FAE + 214 92; // at 0x0FB2 + 222 93; // at 0x0FB6 + 230 95; // at 0x0FBA + } + } // end of LineNumberTable + ; + Attr(#161, 142) { // LocalVariableTable at 0x0FBA + [14] { // LocalVariableTable + 24 16 167 168 5; // at 0x0FCC + 74 16 169 166 5; // at 0x0FD6 + 95 16 167 168 5; // at 0x0FE0 + 127 26 170 171 5; // at 0x0FEA + 137 16 172 166 6; // at 0x0FF4 + 158 16 167 168 5; // at 0x0FFE + 183 26 170 171 5; // at 0x1008 + 193 16 172 166 6; // at 0x1012 + 214 16 173 168 5; // at 0x101C + 0 231 162 163 0; // at 0x1026 + 0 231 165 166 1; // at 0x1030 + 0 231 174 46 2; // at 0x103A + 0 231 175 22 3; // at 0x1044 + 0 231 176 46 4; // at 0x104E + } + } // end of LocalVariableTable + ; + Attr(#177, 22) { // StackMapTable at 0x104E + [8] { // + 86b, [1]z{7b,91}; // same_locals_1_stack_item_frame + 17b; // same_frame + 116b, [1]z{7b,91}; // same_locals_1_stack_item_frame + 17b; // same_frame + 108b, [1]z{7b,91}; // same_locals_1_stack_item_frame + 17b; // same_frame + 101b, [1]z{7b,91}; // same_locals_1_stack_item_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x106A + 0x0000; // access + #31; // name_index : testFieldRef + #32; // descriptor_index : (Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle; + [2] { // Attributes + Attr(#159, 248) { // Code at 0x1072 + 4; // max_stack + 6; // max_locals + Bytes[50]{ + 0x013A04B800692B2C; + 0x2DB600733A04B200; + 0x462CBA00930000B6; + 0x0055A700153A05B2; + 0x00461298B6005F19; + 0x05B20062B6009A19; + 0x04B0; + } + [2] { // Traps + 3 26 29 148; // at 0x10BC + 3 26 29 150; // at 0x10C4 + } // end of Traps + [4] { // Attributes + Attr(#160, 34) { // LineNumberTable at 0x10C6 + [8] { // line_number_table + 0 98; // at 0x10D2 + 3 100; // at 0x10D6 + 14 101; // at 0x10DA + 26 105; // at 0x10DE + 29 102; // at 0x10E2 + 31 103; // at 0x10E6 + 39 104; // at 0x10EA + 47 106; // at 0x10EE + } + } // end of LineNumberTable + ; + Attr(#161, 62) { // LocalVariableTable at 0x10EE + [6] { // LocalVariableTable + 31 16 167 178 5; // at 0x1100 + 0 50 162 163 0; // at 0x110A + 0 50 179 58 1; // at 0x1114 + 0 50 180 22 2; // at 0x111E + 0 50 181 58 3; // at 0x1128 + 3 47 165 166 4; // at 0x1132 + } + } // end of LocalVariableTable + ; + Attr(#182, 22) { // LocalVariableTypeTable at 0x1132 + [2] { // LocalVariableTypeTable + 0 50 179 183 1; // at 0x1144 + 0 50 181 183 3; // at 0x114E + } + } // end of LocalVariableTypeTable + ; + Attr(#177, 28) { // StackMapTable at 0x114E + [2] { // + 255b, 29, [5]{7b,7; 7b,10; 7b,27; 7b,10; 7b,77}, [1]{7b,155}; // full_frame + 17b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + ; + Attr(#184, 2) { // Signature at 0x1170 + #185; + } // end of Signature + } // end of Attributes + } + } // end of Methods + + [3] { // Attributes + Attr(#186, 2) { // SourceFile at 0x117A + #187; + } // end of SourceFile + ; + Attr(#188, 38) { // BootstrapMethods at 0x1182 + [6] { // bootstrap_methods + { // bootstrap_method + #189; // bootstrap_method_ref + [1] { // bootstrap_arguments + #195; // at 0x1190 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #189; // bootstrap_method_ref + [1] { // bootstrap_arguments + #197; // at 0x1196 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #189; // bootstrap_method_ref + [1] { // bootstrap_arguments + #199; // at 0x119C + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #189; // bootstrap_method_ref + [1] { // bootstrap_arguments + #201; // at 0x11A2 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #189; // bootstrap_method_ref + [1] { // bootstrap_arguments + #203; // at 0x11A8 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #189; // bootstrap_method_ref + [1] { // bootstrap_arguments + #205; // at 0x11AE + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#207, 18) { // InnerClasses at 0x11AE + [2] { // classes + #116 #106 #208 25; // at 0x11BE + #132 #77 #209 25; // at 0x11C6 + } + } // end of InnerClasses + } // end of Attributes +} // end of class org/openjdk/asmtools/transform/case8302260/TestRunner diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,77 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +package org/openjdk/asmtools/transform/case8302260/data; + +public super class #10 /* CTestClass */ extends #2 /* org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass */ implements #19 /* ITestInterfaceA */ version 60:0 +{ + const #1 = Method #2.#3; // org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass."":"()V" + const #2 = class #4; // org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Asciz "org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass"; + const #5 = Asciz ""; + const #6 = Asciz "()V"; + const #7 = String #8; // "CTestClass" + const #8 = Asciz "CTestClass"; + const #9 = Field #10.#11; // CTestClass.ctestString:"Ljava/lang/String;" + const #10 = class #12; // CTestClass + const #11 = NameAndType #13:#14; // ctestString:"Ljava/lang/String;" + const #12 = Asciz "org/openjdk/asmtools/transform/case8302260/data/CTestClass"; + const #13 = Asciz "ctestString"; + const #14 = Asciz "Ljava/lang/String;"; + const #15 = Field #10.#16; // CTestClass.ctestLong:"J" + const #16 = NameAndType #17:#18; // ctestLong:"J" + const #17 = Asciz "ctestLong"; + const #18 = Asciz "J"; + const #19 = class #20; // ITestInterfaceA + const #20 = Asciz "org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA"; + const #21 = Asciz "Code"; + const #22 = Asciz "LineNumberTable"; + const #23 = Asciz "LocalVariableTable"; + const #24 = Asciz "this"; + const #25 = Asciz "Lorg/openjdk/asmtools/transform/case8302260/data/CTestClass;"; + const #26 = Asciz ""; + const #27 = Asciz "SourceFile"; + const #28 = Asciz "CTestClass.java"; + + public static Field #13:#14; // ctestString:"Ljava/lang/String;" + public static Field #17:#18; // ctestLong:J + + public Method #5:#6 // "":"()V" + stack 1 locals 1 + { + var 0 #24:#25; // this:"Lorg/openjdk/asmtools/transform/case8302260/data/CTestClass;" + 0: aload_0; + 1: invokespecial #1; // Method org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass."":"()V" + 4: return; + endvar 0; + } + static Method #26:#6 // "":"()V" + stack 2 locals 0 + { + 0: ldc #7; // String "CTestClass" + 2: putstatic #9; // Field ctestString:"Ljava/lang/String;" + 5: lconst_1; + 6: putstatic #15; // Field ctestLong:"J" + 9: return; + } +} // end Class CTestClass compiled from "CTestClass.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/CTestClass.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,148 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case8302260/data/CTestClass { + 0xCAFEBABE; + 0; // minor version + 60; // version + [29] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass"; // #4 at 0x17 + Utf8 ""; // #5 at 0x5D + Utf8 "()V"; // #6 at 0x66 + String #8; // #7 at 0x6C + Utf8 "CTestClass"; // #8 at 0x6F + Field #10 #11; // #9 at 0x7C + class #12; // #10 at 0x81 + NameAndType #13 #14; // #11 at 0x84 + Utf8 "org/openjdk/asmtools/transform/case8302260/data/CTestClass"; // #12 at 0x89 + Utf8 "ctestString"; // #13 at 0xC6 + Utf8 "Ljava/lang/String;"; // #14 at 0xD4 + Field #10 #16; // #15 at 0xE9 + NameAndType #17 #18; // #16 at 0xEE + Utf8 "ctestLong"; // #17 at 0xF3 + Utf8 "J"; // #18 at 0xFF + class #20; // #19 at 0x0103 + Utf8 "org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA"; // #20 at 0x0106 + Utf8 "Code"; // #21 at 0x0148 + Utf8 "LineNumberTable"; // #22 at 0x014F + Utf8 "LocalVariableTable"; // #23 at 0x0161 + Utf8 "this"; // #24 at 0x0176 + Utf8 "Lorg/openjdk/asmtools/transform/case8302260/data/CTestClass;"; // #25 at 0x017D + Utf8 ""; // #26 at 0x01BC + Utf8 "SourceFile"; // #27 at 0x01C7 + Utf8 "CTestClass.java"; // #28 at 0x01D4 + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #10; // this_cpx + #2; // super_cpx + + [1] { // Interfaces + #19; // org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA at 0x01F0 + } // end of Interfaces + + [2] { // Fields + { // field at 0x01F2 + 0x0009; // access + #13; // name_index : ctestString + #14; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x01FA + 0x0009; // access + #17; // name_index : ctestLong + #18; // descriptor_index : J + [0] { // Attributes + } // end of Attributes + } + } // end of Fields + + [2] { // Methods + { // method at 0x0204 + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#21, 47) { // Code at 0x020C + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end of Traps + [2] { // Attributes + Attr(#22, 6) { // LineNumberTable at 0x0223 + [1] { // line_number_table + 0 28; // at 0x022F + } + } // end of LineNumberTable + ; + Attr(#23, 12) { // LocalVariableTable at 0x022F + [1] { // LocalVariableTable + 0 5 24 25 0; // at 0x0241 + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x0241 + 0x0008; // access + #26; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#21, 38) { // Code at 0x0249 + 2; // max_stack + 0; // max_locals + Bytes[10]{ + 0x1207B300090AB300; + 0x0FB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#22, 10) { // LineNumberTable at 0x0265 + [2] { // line_number_table + 0 29; // at 0x0271 + 5 30; // at 0x0275 + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [1] { // Attributes + Attr(#27, 2) { // SourceFile at 0x0277 + #28; + } // end of SourceFile + } // end of Attributes +} // end of class org/openjdk/asmtools/transform/case8302260/data/CTestClass diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,51 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +package org/openjdk/asmtools/transform/case8302260/data; + +public interface #1 /* ITestInterfaceA */ version 60:0 +{ + const #1 = class #2; // ITestInterfaceA + const #2 = Asciz "org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA"; + const #3 = class #4; // java/lang/Object + const #4 = Asciz "java/lang/Object"; + const #5 = Asciz "stringField"; + const #6 = Asciz "Ljava/lang/String;"; + const #7 = Asciz "ConstantValue"; + const #8 = String #9; // "ITestInterfaceA" + const #9 = Asciz "ITestInterfaceA"; + const #10 = Asciz "longField"; + const #11 = Asciz "J"; + const #12 = long 10l; + const #14 = Asciz "stringField3"; + const #15 = String #16; // "ITestInterfaceA3" + const #16 = Asciz "ITestInterfaceA3"; + const #17 = Asciz "longField3"; + const #18 = long 13l; + const #20 = Asciz "SourceFile"; + const #21 = Asciz "ITestInterfaceA.java"; + + public static final Field #5:#6 = #8; // stringField:"Ljava/lang/String;" = String "ITestInterfaceA" + public static final Field #10:#11 = #12; // longField:J = long 10l + public static final Field #14:#6 = #15; // stringField3:"Ljava/lang/String;" = String "ITestInterfaceA3" + public static final Field #17:#11 = #18; // longField3:J = long 13l +} // end Class ITestInterfaceA compiled from "ITestInterfaceA.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,111 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA { + 0xCAFEBABE; + 0; // minor version + 60; // version + [22] { // Constant Pool + ; // first element is empty + class #2; // #1 at 0x0A + Utf8 "org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA"; // #2 at 0x0D + class #4; // #3 at 0x4F + Utf8 "java/lang/Object"; // #4 at 0x52 + Utf8 "stringField"; // #5 at 0x65 + Utf8 "Ljava/lang/String;"; // #6 at 0x73 + Utf8 "ConstantValue"; // #7 at 0x88 + String #9; // #8 at 0x98 + Utf8 "ITestInterfaceA"; // #9 at 0x9B + Utf8 "longField"; // #10 at 0xAD + Utf8 "J"; // #11 at 0xB9 + long 0x000000000000000A;; // #12 at 0xBD + Utf8 "stringField3"; // #14 at 0xC6 + String #16; // #15 at 0xD5 + Utf8 "ITestInterfaceA3"; // #16 at 0xD8 + Utf8 "longField3"; // #17 at 0xEB + long 0x000000000000000D;; // #18 at 0xF8 + Utf8 "SourceFile"; // #20 at 0x0101 + Utf8 "ITestInterfaceA.java"; // #21 at 0x010E + } // end of Constant Pool + + 0x0601; // access [ ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT ] + #1; // this_cpx + #3; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [4] { // Fields + { // field at 0x012F + 0x0019; // access + #5; // name_index : stringField + #6; // descriptor_index : Ljava/lang/String; + [1] { // Attributes + Attr(#7, 2) { // ConstantValue at 0x0137 + #8; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field at 0x013F + 0x0019; // access + #10; // name_index : longField + #11; // descriptor_index : J + [1] { // Attributes + Attr(#7, 2) { // ConstantValue at 0x0147 + #12; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field at 0x014F + 0x0019; // access + #14; // name_index : stringField3 + #6; // descriptor_index : Ljava/lang/String; + [1] { // Attributes + Attr(#7, 2) { // ConstantValue at 0x0157 + #15; + } // end of ConstantValue + } // end of Attributes + } + ; + { // field at 0x015F + 0x0019; // access + #17; // name_index : longField3 + #11; // descriptor_index : J + [1] { // Attributes + Attr(#7, 2) { // ConstantValue at 0x0167 + #18; + } // end of ConstantValue + } // end of Attributes + } + } // end of Fields + + [0] { // Methods + } // end of Methods + + [1] { // Attributes + Attr(#20, 2) { // SourceFile at 0x0173 + #21; + } // end of SourceFile + } // end of Attributes +} // end of class org/openjdk/asmtools/transform/case8302260/data/ITestInterfaceA diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jasm jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jasm --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jasm 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jasm 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,91 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +package org/openjdk/asmtools/transform/case8302260/data/pkg; + +public super class #10 /* CTestSuperClass */ version 60:0 +{ + const #1 = Method #2.#3; // java/lang/Object."":"()V" + const #2 = class #4; // java/lang/Object + const #3 = NameAndType #5:#6; // "":"()V" + const #4 = Asciz "java/lang/Object"; + const #5 = Asciz ""; + const #6 = Asciz "()V"; + const #7 = String #8; // "CTestSuperClass" + const #8 = Asciz "CTestSuperClass"; + const #9 = Field #10.#11; // CTestSuperClass.stringField:"Ljava/lang/String;" + const #10 = class #12; // CTestSuperClass + const #11 = NameAndType #13:#14; // stringField:"Ljava/lang/String;" + const #12 = Asciz "org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass"; + const #13 = Asciz "stringField"; + const #14 = Asciz "Ljava/lang/String;"; + const #15 = long 100l; + const #17 = Field #10.#18; // CTestSuperClass.longField:"J" + const #18 = NameAndType #19:#20; // longField:"J" + const #19 = Asciz "longField"; + const #20 = Asciz "J"; + const #21 = String #22; // "CTestSuperClass2" + const #22 = Asciz "CTestSuperClass2"; + const #23 = Field #10.#24; // CTestSuperClass.stringField2:"Ljava/lang/String;" + const #24 = NameAndType #25:#14; // stringField2:"Ljava/lang/String;" + const #25 = Asciz "stringField2"; + const #26 = long 102l; + const #28 = Field #10.#29; // CTestSuperClass.longField2:"J" + const #29 = NameAndType #30:#20; // longField2:"J" + const #30 = Asciz "longField2"; + const #31 = Asciz "Code"; + const #32 = Asciz "LineNumberTable"; + const #33 = Asciz "LocalVariableTable"; + const #34 = Asciz "this"; + const #35 = Asciz "Lorg/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass;"; + const #36 = Asciz ""; + const #37 = Asciz "SourceFile"; + const #38 = Asciz "CTestSuperClass.java"; + + public static Field #13:#14; // stringField:"Ljava/lang/String;" + public static Field #19:#20; // longField:J + public static Field #25:#14; // stringField2:"Ljava/lang/String;" + public static Field #30:#20; // longField2:J + + public Method #5:#6 // "":"()V" + stack 1 locals 1 + { + var 0 #34:#35; // this:"Lorg/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass;" + 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V" + 4: return; + endvar 0; + } + static Method #36:#6 // "":"()V" + stack 2 locals 0 + { + 0: ldc #7; // String "CTestSuperClass" + 2: putstatic #9; // Field stringField:"Ljava/lang/String;" + 5: ldc2_w #15; // long 100l + 8: putstatic #17; // Field longField:"J" + 11: ldc #21; // String "CTestSuperClass2" + 13: putstatic #23; // Field stringField2:"Ljava/lang/String;" + 16: ldc2_w #26; // long 102l + 19: putstatic #28; // Field longField2:"J" + 22: return; + } +} // end Class CTestSuperClass compiled from "CTestSuperClass.java" diff -Nru jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jcod jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jcod --- jtreg8-8.1+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jcod 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/asmtools/test/resources/org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass.class.jcod 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,174 @@ +// +// Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +class org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass { + 0xCAFEBABE; + 0; // minor version + 60; // version + [39] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + String #8; // #7 at 0x39 + Utf8 "CTestSuperClass"; // #8 at 0x3C + Field #10 #11; // #9 at 0x4E + class #12; // #10 at 0x53 + NameAndType #13 #14; // #11 at 0x56 + Utf8 "org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass"; // #12 at 0x5B + Utf8 "stringField"; // #13 at 0xA1 + Utf8 "Ljava/lang/String;"; // #14 at 0xAF + long 0x0000000000000064;; // #15 at 0xC4 + Field #10 #18; // #17 at 0xCD + NameAndType #19 #20; // #18 at 0xD2 + Utf8 "longField"; // #19 at 0xD7 + Utf8 "J"; // #20 at 0xE3 + String #22; // #21 at 0xE7 + Utf8 "CTestSuperClass2"; // #22 at 0xEA + Field #10 #24; // #23 at 0xFD + NameAndType #25 #14; // #24 at 0x0102 + Utf8 "stringField2"; // #25 at 0x0107 + long 0x0000000000000066;; // #26 at 0x0116 + Field #10 #29; // #28 at 0x011F + NameAndType #30 #20; // #29 at 0x0124 + Utf8 "longField2"; // #30 at 0x0129 + Utf8 "Code"; // #31 at 0x0136 + Utf8 "LineNumberTable"; // #32 at 0x013D + Utf8 "LocalVariableTable"; // #33 at 0x014F + Utf8 "this"; // #34 at 0x0164 + Utf8 "Lorg/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass;"; // #35 at 0x016B + Utf8 ""; // #36 at 0x01B3 + Utf8 "SourceFile"; // #37 at 0x01BE + Utf8 "CTestSuperClass.java"; // #38 at 0x01CB + } // end of Constant Pool + + 0x0021; // access [ ACC_PUBLIC, ACC_SUPER ] + #10; // this_cpx + #2; // super_cpx + + [0] { // Interfaces + } // end of Interfaces + + [4] { // Fields + { // field at 0x01EC + 0x0009; // access + #13; // name_index : stringField + #14; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x01F4 + 0x0009; // access + #19; // name_index : longField + #20; // descriptor_index : J + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x01FC + 0x0009; // access + #25; // name_index : stringField2 + #14; // descriptor_index : Ljava/lang/String; + [0] { // Attributes + } // end of Attributes + } + ; + { // field at 0x0204 + 0x0009; // access + #30; // name_index : longField2 + #20; // descriptor_index : J + [0] { // Attributes + } // end of Attributes + } + } // end of Fields + + [2] { // Methods + { // method at 0x020E + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#31, 47) { // Code at 0x0216 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end of Traps + [2] { // Attributes + Attr(#32, 6) { // LineNumberTable at 0x022D + [1] { // line_number_table + 0 25; // at 0x0239 + } + } // end of LineNumberTable + ; + Attr(#33, 12) { // LocalVariableTable at 0x0239 + [1] { // LocalVariableTable + 0 5 34 35 0; // at 0x024B + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method at 0x024B + 0x0008; // access + #36; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#31, 59) { // Code at 0x0253 + 2; // max_stack + 0; // max_locals + Bytes[23]{ + 0x1207B3000914000F; + 0xB300111215B30017; + 0x14001AB3001CB1; + } + [0] { // Traps + } // end of Traps + [1] { // Attributes + Attr(#32, 18) { // LineNumberTable at 0x027C + [4] { // line_number_table + 0 26; // at 0x0288 + 5 27; // at 0x028C + 11 29; // at 0x0290 + 16 30; // at 0x0294 + } + } // end of LineNumberTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + } // end of Methods + + [1] { // Attributes + Attr(#37, 2) { // SourceFile at 0x0296 + #38; + } // end of SourceFile + } // end of Attributes +} // end of class org/openjdk/asmtools/transform/case8302260/data/pkg/CTestSuperClass diff -Nru jtreg8-8.1+1+ds1/debian/apiguardian/rules jtreg8-8.3+1+ds1/debian/apiguardian/rules --- jtreg8-8.1+1+ds1/debian/apiguardian/rules 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/apiguardian/rules 2026-09-30 21:11:41.000000000 +0000 @@ -3,14 +3,9 @@ %: dh $@ --buildsystem=gradle --with maven-repo-helper -override_dh_auto_clean: - dh_auto_clean - # Remove the build.gradle file we created during configure - rm -f build.gradle settings.gradle - -override_dh_auto_configure: - # Until the Debian Gradle toolchain has Kotlin support, - # copy the (patched) build.gradle.kts to build.gradle - cp build.gradle.kts build.gradle - cp settings.gradle.kts settings.gradle - dh_auto_configure +override_dh_auto_build: + trap 'mv -f build.gradle build.gradle.kts; \ + mv -f settings.gradle settings.gradle.kts' EXIT INT TERM HUP; \ + mv -f build.gradle.kts build.gradle; \ + mv -f settings.gradle.kts settings.gradle; \ + dh_auto_build diff -Nru jtreg8-8.1+1+ds1/debian/asmtools/rules jtreg8-8.3+1+ds1/debian/asmtools/rules --- jtreg8-8.1+1+ds1/debian/asmtools/rules 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/asmtools/rules 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,13 @@ +#!/usr/bin/make -f + +include /usr/share/dpkg/pkg-info.mk + +%: + dh $@ --buildsystem=ant --with javahelper + +override_dh_auto_clean: + dh_auto_clean -- -f build/build.xml -DBUILD_DIR=asmtools + +override_dh_auto_build: + JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 dh_auto_build -- -f build/build.xml jar -DBUILD_DIR=asmtools + diff -Nru jtreg8-8.1+1+ds1/debian/changelog jtreg8-8.3+1+ds1/debian/changelog --- jtreg8-8.1+1+ds1/debian/changelog 2026-01-25 19:42:45.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/changelog 2026-10-23 10:27:33.000000000 +0000 @@ -1,8 +1,49 @@ -jtreg8 (8.1+1+ds1-1~deb13u1) trixie-security; urgency=medium +jtreg8 (8.3+1+ds1-2~deb13u1) trixie-security; urgency=medium - * Upload to Debian 13 (trixie). + * Rebuildfor Trixie, needed by the latest Java 21 security releases - -- Vladimir Petko Mon, 26 Jan 2026 08:42:45 +1300 + -- Moritz Mühlenhoff Fri, 23 Oct 2026 12:27:33 +0200 + +jtreg8 (8.3+1+ds1-2) unstable; urgency=medium + + * d/{apiguardian/rules, opentest4j-reporting/rules}: Remove Gradle + Kotlin DSL build files (Closes: #1149426). + * Standards-Version 4.7.4: + - d/control: Drop Priority field. + + -- Vladimir Petko Thu, 01 Oct 2026 10:20:15 +1300 + +jtreg8 (8.3+1+ds1-1) unstable; urgency=medium + + * New upstream release jtreg 8.3, build 1. + * d/p/codetools-7904152.patch: Drop patch applied upstream. + + -- Vladimir Petko Mon, 22 Jun 2026 08:14:11 +1200 + +jtreg8 (8.2.1+1+ds1-2) unstable; urgency=medium + + * d/p/codetools-7904157-proposed.patch: override compile timeout + to resolve the test failure due to the compilation timing out + with the default timeout (Closes: #1128797). + + -- Vladimir Petko Mon, 23 Feb 2026 11:09:54 +1300 + +jtreg8 (8.2.1+1+ds1-1) unstable; urgency=medium + + * New upstream release jtreg 8.2.1, build 1. + - Update vendored junit to 5.14.2. + - Update vendored opentest4j-reporting to 0.2.5. + - Vendor asmtools 9.1+b01. + * d/control: Drop libasmtools-java dependency. + * d/p/fix_junit5_error_message.patch: drop junit error message + patch, JUnit 5 was upgraded. + * d/p/codetools-790410{5,6,7}-proposed.patch: Drop patches + applied upstream. + * d/gbp-import.sh: Sign tags on import. + * d/p/codetools-7904152.patch: skip security policy tests + with Java 25 (CODETOOLS-7904152). + + -- Vladimir Petko Tue, 17 Feb 2026 08:35:56 +1300 jtreg8 (8.1+1+ds1-1) unstable; urgency=medium diff -Nru jtreg8-8.1+1+ds1/debian/control jtreg8-8.3+1+ds1/debian/control --- jtreg8-8.1+1+ds1/debian/control 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/control 2026-09-30 21:11:41.000000000 +0000 @@ -1,6 +1,5 @@ Source: jtreg8 Section: java -Priority: optional Maintainer: Vladimir Petko Uploaders: Matthias Klose Build-Depends: @@ -10,7 +9,6 @@ help2man, javahelp2, javahelper, - libasmtools-java, libjcommander-java, libslf4j-java, libguice-java, @@ -41,7 +39,7 @@ libmaven-plugin-tools-java, libplexus-component-metadata-java, libxbean-java, -Standards-Version: 4.7.2 +Standards-Version: 4.7.4 Vcs-Git: https://salsa.debian.org/java-team/jtreg8.git Vcs-Browser: https://salsa.debian.org/java-team/jtreg8 Homepage: https://openjdk.java.net/jtreg diff -Nru jtreg8-8.1+1+ds1/debian/copyright jtreg8-8.3+1+ds1/debian/copyright --- jtreg8-8.1+1+ds1/debian/copyright 2025-10-22 19:51:59.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/copyright 2026-09-30 21:11:41.000000000 +0000 @@ -101,6 +101,12 @@ the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. +Files: asmtools/* +Copyright: 2014-2026, Oracle and/or its affiliates. +License: GPL-2.0 + On Debian systems the full text of the GPL-2.0 license can be found in + /usr/share/common-licenses/GPL-2.0. + Files: hawt-jni/* Copyright: 2009-2014, FuseSource Corp. 2004-2008, IBM Corporation and others @@ -211,6 +217,12 @@ On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". +Files: debian/asmtools/* +Copyright: 2023 Debian Java Maintainers +License: Apache-2.0 + On Debian systems the full text of the Apache-2.0 license can be found in + /usr/share/common-licenses/Apache-2.0. + Files: debian/jansi1/* Copyright: 2010, Miguel Landaeta 2016-2017, Markus Koschany diff -Nru jtreg8-8.1+1+ds1/debian/gbp-export.sh jtreg8-8.3+1+ds1/debian/gbp-export.sh --- jtreg8-8.1+1+ds1/debian/gbp-export.sh 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/gbp-export.sh 2026-09-30 21:11:41.000000000 +0000 @@ -1,3 +1,3 @@ #!/bin/sh -gbp export-orig --pristine-tar --component=opentest4j --component=apiguardian --component=hawt-jni --component=jansi1 --component=jline3 --component=junit4 --component=junit5 --component=libhamcrest-java --component=opentest4j-reporting --component=picocli --component=testng --component=univocity-parsers --compression=gzip +gbp export-orig --pristine-tar --component asmtools --component=opentest4j --component=apiguardian --component=hawt-jni --component=jansi1 --component=jline3 --component=junit4 --component=junit5 --component=libhamcrest-java --component=opentest4j-reporting --component=picocli --component=testng --component=univocity-parsers --compression=gzip diff -Nru jtreg8-8.1+1+ds1/debian/gbp-import.sh jtreg8-8.3+1+ds1/debian/gbp-import.sh --- jtreg8-8.1+1+ds1/debian/gbp-import.sh 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/gbp-import.sh 2026-09-30 21:11:41.000000000 +0000 @@ -1,3 +1,3 @@ #!/bin/sh -gbp import-orig --pristine-tar --component=opentest4j --component=apiguardian --component=hawt-jni --component=jansi1 --component=jline3 --component=junit4 --component=junit5 --component=libhamcrest-java --component=opentest4j-reporting --component=picocli --component=testng --component=univocity-parsers $* +gbp import-orig --sign-tags --pristine-tar --component asmtools --component=opentest4j --component=apiguardian --component=hawt-jni --component=jansi1 --component=jline3 --component=junit4 --component=junit5 --component=libhamcrest-java --component=opentest4j-reporting --component=picocli --component=testng --component=univocity-parsers $* diff -Nru jtreg8-8.1+1+ds1/debian/junit5/generated/JRE.java jtreg8-8.3+1+ds1/debian/junit5/generated/JRE.java --- jtreg8-8.1+1+ds1/debian/junit5/generated/JRE.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/junit5/generated/JRE.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,410 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.condition; + +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; +import static org.apiguardian.api.API.Status.STABLE; + +import java.lang.reflect.Method; + +import org.apiguardian.api.API; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.util.StringUtils; + +/** + * Enumeration of Java Runtime Environment (JRE) versions. + * + *

If the current JRE version can be detected but is not one of the predefined + * constants in this enum, {@link #OTHER} will be considered to be the + * {@linkplain #isCurrentVersion current JRE version}. If the current JRE version + * cannot be detected — for example, if the {@code java.version} JVM system + * property is undefined — {@link #UNDEFINED} will be considered to be the + * current JRE version. + * + * @since 5.1 + * @see #JAVA_8 + * @see #JAVA_9 + * @see #JAVA_10 + * @see #JAVA_11 + * @see #JAVA_12 + * @see #JAVA_13 + * @see #JAVA_14 + * @see #JAVA_15 + * @see #JAVA_16 + * @see #JAVA_17 + * @see #JAVA_18 + * @see #JAVA_19 + * @see #JAVA_20 + * @see #JAVA_21 + * @see #JAVA_22 + * @see #JAVA_23 + * @see #JAVA_24 + * @see #JAVA_25 + * @see #JAVA_26 + * @see #OTHER + * @see EnabledOnJre + * @see DisabledOnJre + * @see EnabledForJreRange + * @see DisabledForJreRange + */ +@API(status = STABLE, since = "5.1") +public enum JRE { + + /** + * An undefined JRE version. + * + *

This constant is used by JUnit as a default configuration value but is + * not intended to be used by users. + * + *

This constant returns {@code -1} for its {@linkplain #version() version}. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + UNDEFINED(-1), + + /** + * Java 8. + */ + JAVA_8(8), + + /** + * Java 9. + */ + JAVA_9(9), + + /** + * Java 10. + */ + JAVA_10(10), + + /** + * Java 11. + */ + JAVA_11(11), + + /** + * Java 12. + * + * @since 5.4 + */ + @API(status = STABLE, since = "5.4") + JAVA_12(12), + + /** + * Java 13. + * + * @since 5.4 + */ + @API(status = STABLE, since = "5.4") + JAVA_13(13), + + /** + * Java 14. + * + * @since 5.5 + */ + @API(status = STABLE, since = "5.5") + JAVA_14(14), + + /** + * Java 15. + * + * @since 5.6 + */ + @API(status = STABLE, since = "5.6") + JAVA_15(15), + + /** + * Java 16. + * + * @since 5.7 + */ + @API(status = STABLE, since = "5.7") + JAVA_16(16), + + /** + * Java 17. + * + * @since 5.7.1 + */ + @API(status = STABLE, since = "5.7.1") + JAVA_17(17), + + /** + * Java 18. + * + * @since 5.8.1 + */ + @API(status = STABLE, since = "5.8.1") + JAVA_18(18), + + /** + * Java 19. + * + * @since 5.9 + */ + @API(status = STABLE, since = "5.9") + JAVA_19(19), + + /** + * Java 20. + * + * @since 5.9 + */ + @API(status = STABLE, since = "5.9") + JAVA_20(20), + + /** + * Java 21. + * + * @since 5.9.2 + */ + @API(status = STABLE, since = "5.9.2") + JAVA_21(21), + + /** + * Java 22. + * + * @since 5.10 + */ + @API(status = STABLE, since = "5.10") + JAVA_22(22), + + /** + * Java 23. + * + * @since 5.11 + */ + @API(status = STABLE, since = "5.11") + JAVA_23(23), + + /** + * Java 24. + * + * @since 5.11 + */ + @API(status = STABLE, since = "5.11") + JAVA_24(24), + + /** + * Java 25. + * + * @since 5.11.4 + */ + @API(status = STABLE, since = "5.11.4") + JAVA_25(25), + + /** + * Java 26. + * + * @since 5.13.2 + */ + @API(status = STABLE, since = "5.13.2") + JAVA_26(26), + + /** + * A JRE version other than {@link #JAVA_8}, {@link #JAVA_9}, + * {@link #JAVA_10}, {@link #JAVA_11}, {@link #JAVA_12}, + * {@link #JAVA_13}, {@link #JAVA_14}, {@link #JAVA_15}, + * {@link #JAVA_16}, {@link #JAVA_17}, {@link #JAVA_18}, + * {@link #JAVA_19}, {@link #JAVA_20}, {@link #JAVA_21}, + * {@link #JAVA_22}, {@link #JAVA_23}, {@link #JAVA_24}, + * {@link #JAVA_25}, or {@link #JAVA_26}. + * + *

This constant returns {@link Integer#MAX_VALUE} for its + * {@linkplain #version() version}. To retrieve the actual version number, + * use {@link #currentVersionNumber()}. + */ + OTHER(Integer.MAX_VALUE); + + static final int UNDEFINED_VERSION = -1; + + static final int MINIMUM_VERSION = 8; + + private static final Logger logger = LoggerFactory.getLogger(JRE.class); + + private static final int CURRENT_VERSION = determineCurrentVersion(); + + private static final JRE CURRENT_JRE = determineCurrentJre(CURRENT_VERSION); + + private static int determineCurrentVersion() { + String javaVersion = System.getProperty("java.version"); + boolean javaVersionIsBlank = StringUtils.isBlank(javaVersion); + + if (javaVersionIsBlank) { + logger.debug( + () -> "JVM system property 'java.version' is undefined. It is therefore not possible to detect Java 8."); + } + + if (!javaVersionIsBlank && javaVersion.startsWith("1.8")) { + return 8; + } + + try { + // java.lang.Runtime.version() is a static method available on Java 9+ + // that returns an instance of java.lang.Runtime.Version which has the + // following method: public int major() + Method versionMethod = Runtime.class.getMethod("version"); + Object version = ReflectionSupport.invokeMethod(versionMethod, null); + Method majorMethod = version.getClass().getMethod("major"); + return (int) ReflectionSupport.invokeMethod(majorMethod, version); + } + catch (Exception ex) { + logger.debug(ex, () -> "Failed to determine the current JRE version via java.lang.Runtime.Version."); + } + + return UNDEFINED_VERSION; + } + + private static JRE determineCurrentJre(int currentVersion) { + switch (currentVersion) { + case UNDEFINED_VERSION: + return UNDEFINED; + case 8: + return JAVA_8; + case 9: + return JAVA_9; + case 10: + return JAVA_10; + case 11: + return JAVA_11; + case 12: + return JAVA_12; + case 13: + return JAVA_13; + case 14: + return JAVA_14; + case 15: + return JAVA_15; + case 16: + return JAVA_16; + case 17: + return JAVA_17; + case 18: + return JAVA_18; + case 19: + return JAVA_19; + case 20: + return JAVA_20; + case 21: + return JAVA_21; + case 22: + return JAVA_22; + case 23: + return JAVA_23; + case 24: + return JAVA_24; + case 25: + return JAVA_25; + case 26: + return JAVA_26; + default: + return OTHER; + } + } + + private final int version; + + private JRE(int version) { + this.version = version; + } + + /** + * Get the version of this {@code JRE}. + * + *

If this {@code JRE} is {@link #UNDEFINED}, this method returns + * {@code -1}. If this {@code JRE} is {@link #OTHER}, this method returns + * {@link Integer#MAX_VALUE}. + * + * @return the version of this {@code JRE} + * @since 5.12 + * @see Runtime.Version#feature() + * @see #currentVersionNumber() + */ + @API(status = MAINTAINED, since = "5.13.3") + public int version() { + return this.version; + } + + /** + * @return {@code true} if this {@code JRE} is known to be the + * Java Runtime Environment version for the currently executing JVM or if + * the version is {@link #OTHER} or {@link #UNDEFINED} + * + * @see #currentJre() + * @see #currentVersionNumber() + */ + public boolean isCurrentVersion() { + return this == CURRENT_JRE; + } + + /** + * @return the {@link JRE} for the currently executing JVM, potentially + * {@link #OTHER} or {@link #UNDEFINED} + * + * @since 5.7 + * @see #currentVersionNumber() + * @deprecated in favor of {@link #currentJre()} + */ + @API(status = DEPRECATED, since = "5.12") + @Deprecated + public static JRE currentVersion() { + return currentJre(); + } + + /** + * @return the {@link JRE} for the currently executing JVM, potentially + * {@link #OTHER} or {@link #UNDEFINED} + * + * @since 5.12 + * @see #currentVersionNumber() + */ + @API(status = STABLE, since = "5.12") + public static JRE currentJre() { + return CURRENT_JRE; + } + + /** + * @return the version number for the currently executing JVM, or {@code -1} + * if the current JVM version could not be determined + * + * @since 5.12 + * @see Runtime.Version#feature() + * @see #currentJre() + */ + @API(status = MAINTAINED, since = "5.13.3") + public static int currentVersionNumber() { + return CURRENT_VERSION; + } + + /** + * @return {@code true} if the supplied version number is known to be the + * Java Runtime Environment version for the currently executing JVM or if + * the supplied version number is {@code -1} and the current JVM version + * could not be determined + * + * @since 5.12 + * @see Runtime.Version#feature() + */ + @API(status = MAINTAINED, since = "5.13.3") + public static boolean isCurrentVersion(int version) { + return version == CURRENT_VERSION; + } + + static boolean isCurrentVersionWithinRange(int min, int max) { + return CURRENT_VERSION >= min && CURRENT_VERSION <= max; + } + +} diff -Nru jtreg8-8.1+1+ds1/debian/junit5/junit-jupiter-api/build/generated/sources/jte/main/org/junit/jupiter/api/condition/JRE.java jtreg8-8.3+1+ds1/debian/junit5/junit-jupiter-api/build/generated/sources/jte/main/org/junit/jupiter/api/condition/JRE.java --- jtreg8-8.1+1+ds1/debian/junit5/junit-jupiter-api/build/generated/sources/jte/main/org/junit/jupiter/api/condition/JRE.java 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/junit5/junit-jupiter-api/build/generated/sources/jte/main/org/junit/jupiter/api/condition/JRE.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,299 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.api.condition; - -import static org.apiguardian.api.API.Status.STABLE; - -import java.lang.reflect.Method; -import java.util.EnumSet; - -import org.apiguardian.api.API; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.commons.util.StringUtils; - -/** - * Enumeration of Java Runtime Environment (JRE) versions. - * - *

If the current JRE version cannot be detected — for example, if the - * {@code java.version} JVM system property is undefined — then none of - * the constants defined in this enum will be considered to be the - * {@linkplain #isCurrentVersion current JRE version}. - * - * @since 5.1 - * @see #JAVA_8 - * @see #JAVA_9 - * @see #JAVA_10 - * @see #JAVA_11 - * @see #JAVA_12 - * @see #JAVA_13 - * @see #JAVA_14 - * @see #JAVA_15 - * @see #JAVA_16 - * @see #JAVA_17 - * @see #JAVA_18 - * @see #JAVA_19 - * @see #JAVA_20 - * @see #JAVA_21 - * @see #JAVA_22 - * @see #JAVA_23 - * @see #JAVA_24 - * @see #JAVA_25 - * @see #OTHER - * @see EnabledOnJre - * @see DisabledOnJre - * @see EnabledForJreRange - * @see DisabledForJreRange - */ -@API(status = STABLE, since = "5.1") -public enum JRE { - - /** - * Java 8. - */ - JAVA_8, - - /** - * Java 9. - */ - JAVA_9, - - /** - * Java 10. - */ - JAVA_10, - - /** - * Java 11. - */ - JAVA_11, - - /** - * Java 12. - * - * @since 5.4 - */ - @API(status = STABLE, since = "5.4") - JAVA_12, - - /** - * Java 13. - * - * @since 5.4 - */ - @API(status = STABLE, since = "5.4") - JAVA_13, - - /** - * Java 14. - * - * @since 5.5 - */ - @API(status = STABLE, since = "5.5") - JAVA_14, - - /** - * Java 15. - * - * @since 5.6 - */ - @API(status = STABLE, since = "5.6") - JAVA_15, - - /** - * Java 16. - * - * @since 5.7 - */ - @API(status = STABLE, since = "5.7") - JAVA_16, - - /** - * Java 17. - * - * @since 5.7.1 - */ - @API(status = STABLE, since = "5.7.1") - JAVA_17, - - /** - * Java 18. - * - * @since 5.8.1 - */ - @API(status = STABLE, since = "5.8.1") - JAVA_18, - - /** - * Java 19. - * - * @since 5.9 - */ - @API(status = STABLE, since = "5.9") - JAVA_19, - - /** - * Java 20. - * - * @since 5.9 - */ - @API(status = STABLE, since = "5.9") - JAVA_20, - - /** - * Java 21. - * - * @since 5.9.2 - */ - @API(status = STABLE, since = "5.9.2") - JAVA_21, - - /** - * Java 22. - * - * @since 5.10 - */ - @API(status = STABLE, since = "5.10") - JAVA_22, - - /** - * Java 23. - * - * @since 5.11 - */ - @API(status = STABLE, since = "5.11") - JAVA_23, - - /** - * Java 24. - * - * @since 5.11 - */ - @API(status = STABLE, since = "5.11") - JAVA_24, - - /** - * Java 25. - * - * @since 5.11.4 - */ - @API(status = STABLE, since = "5.11.4") - JAVA_25, - - /** - * A JRE version other than {@link #JAVA_8}, {@link #JAVA_9}, - * {@link #JAVA_10}, {@link #JAVA_11}, {@link #JAVA_12}, - * {@link #JAVA_13}, {@link #JAVA_14}, {@link #JAVA_15}, - * {@link #JAVA_16}, {@link #JAVA_17}, {@link #JAVA_18}, - * {@link #JAVA_19}, {@link #JAVA_20}, {@link #JAVA_21}, - * {@link #JAVA_22}, {@link #JAVA_23}, {@link #JAVA_24}, - * or {@link #JAVA_25}. - */ - OTHER; - - private static final Logger logger = LoggerFactory.getLogger(JRE.class); - - private static final JRE CURRENT_VERSION = determineCurrentVersion(); - - private static JRE determineCurrentVersion() { - String javaVersion = System.getProperty("java.version"); - boolean javaVersionIsBlank = StringUtils.isBlank(javaVersion); - - if (javaVersionIsBlank) { - logger.debug( - () -> "JVM system property 'java.version' is undefined. It is therefore not possible to detect Java 8."); - } - - if (!javaVersionIsBlank && javaVersion.startsWith("1.8")) { - return JAVA_8; - } - - try { - // java.lang.Runtime.version() is a static method available on Java 9+ - // that returns an instance of java.lang.Runtime.Version which has the - // following method: public int major() - Method versionMethod = Runtime.class.getMethod("version"); - Object version = ReflectionUtils.invokeMethod(versionMethod, null); - Method majorMethod = version.getClass().getMethod("major"); - int major = (int) ReflectionUtils.invokeMethod(majorMethod, version); - switch (major) { - case 9: - return JAVA_9; - case 10: - return JAVA_10; - case 11: - return JAVA_11; - case 12: - return JAVA_12; - case 13: - return JAVA_13; - case 14: - return JAVA_14; - case 15: - return JAVA_15; - case 16: - return JAVA_16; - case 17: - return JAVA_17; - case 18: - return JAVA_18; - case 19: - return JAVA_19; - case 20: - return JAVA_20; - case 21: - return JAVA_21; - case 22: - return JAVA_22; - case 23: - return JAVA_23; - case 24: - return JAVA_24; - case 25: - return JAVA_25; - default: - return OTHER; - } - } - catch (Exception ex) { - logger.debug(ex, () -> "Failed to determine the current JRE version via java.lang.Runtime.Version."); - } - - // null signals that the current JRE version is "unknown" - return null; - } - - /** - * @return {@code true} if this {@code JRE} is known to be the - * Java Runtime Environment version for the currently executing JVM or if - * the version is {@link #OTHER} - */ - public boolean isCurrentVersion() { - return this == CURRENT_VERSION; - } - - /** - * @return the {@link JRE} for the currently executing JVM, potentially - * {@link #OTHER} - * - * @since 5.7 - */ - @API(status = STABLE, since = "5.7") - public static JRE currentVersion() { - return CURRENT_VERSION; - } - - static boolean isCurrentVersionWithinRange(JRE min, JRE max) { - return EnumSet.range(min, max).contains(CURRENT_VERSION); - } - -} diff -Nru jtreg8-8.1+1+ds1/debian/junit5/rules jtreg8-8.3+1+ds1/debian/junit5/rules --- jtreg8-8.1+1+ds1/debian/junit5/rules 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/junit5/rules 2026-09-30 21:11:41.000000000 +0000 @@ -3,7 +3,11 @@ %: dh $@ --buildsystem=maven --with javahelper +override_dh_auto_clean: + rm -f junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/JRE.java + dh_auto_clean + override_dh_auto_build: rsync -Lav ../debian/built-components/ debian/ || true - rsync -Lav ../debian/junit5/junit-jupiter-api/build/generated/sources/jte/main junit-jupiter-api/src/main/java + rsync -Lav ../debian/junit5/generated/ junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/ dh_auto_build $@ diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableImage.java jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableImage.java --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableImage.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableImage.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,191 @@ +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Immutable implementation of {@link Image}. + *

+ * Use the builder to create immutable instances: + * {@code new Image.Builder()}. + */ +@SuppressWarnings({"all"}) +final class ImmutableImage implements Image { + private final String content; + private final String altText; + + private ImmutableImage(String content, String altText) { + this.content = content; + this.altText = altText; + } + + /** + * @return The value of the {@code content} attribute + */ + @Override + public String getContent() { + return content; + } + + /** + * @return The value of the {@code altText} attribute + */ + @Override + public String getAltText() { + return altText; + } + + /** + * Copy the current immutable object by setting a value for the {@link Image#getContent() content} attribute. + * An equals check used to prevent copying of the same value by returning {@code this}. + * @param value A new value for content + * @return A modified copy or the {@code this} object + */ + public final ImmutableImage withContent(String value) { + String newValue = Objects.requireNonNull(value, "content"); + if (this.content.equals(newValue)) return this; + return new ImmutableImage(newValue, this.altText); + } + + /** + * Copy the current immutable object by setting a value for the {@link Image#getAltText() altText} attribute. + * An equals check used to prevent copying of the same value by returning {@code this}. + * @param value A new value for altText + * @return A modified copy or the {@code this} object + */ + public final ImmutableImage withAltText(String value) { + String newValue = Objects.requireNonNull(value, "altText"); + if (this.altText.equals(newValue)) return this; + return new ImmutableImage(this.content, newValue); + } + + /** + * This instance is equal to all instances of {@code ImmutableImage} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutableImage + && equalsByValue((ImmutableImage) another); + } + + private boolean equalsByValue(ImmutableImage another) { + return content.equals(another.content) + && altText.equals(another.altText); + } + + /** + * Computes a hash code from attributes: {@code content}, {@code altText}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + content.hashCode(); + h += (h << 5) + altText.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code Image} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + return "Image{" + + "content=" + content + + ", altText=" + altText + + "}"; + } + + /** + * Creates an immutable copy of a {@link Image} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable Image instance + */ + public static Image copyOf(Image instance) { + if (instance instanceof ImmutableImage) { + return (ImmutableImage) instance; + } + return new Image.Builder() + .content(instance.getContent()) + .altText(instance.getAltText()) + .build(); + } + + /** + * Builds instances of type {@link Image Image}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static class Builder { + private static final long INIT_BIT_CONTENT = 0x1L; + private static final long INIT_BIT_ALT_TEXT = 0x2L; + private long initBits = 0x3L; + + private String content; + private String altText; + + /** + * Creates a builder for {@link Image Image} instances. + *

+     * new Image.Builder()
+     *    .content(String) // required {@link Image#getContent() content}
+     *    .altText(String) // required {@link Image#getAltText() altText}
+     *    .build();
+     * 
+ */ + public Builder() { + if (!(this instanceof Image.Builder)) { + throw new UnsupportedOperationException("Use: new Image.Builder()"); + } + } + + /** + * Initializes the value for the {@link Image#getContent() content} attribute. + * @param content The value for content + * @return {@code this} builder for use in a chained invocation + */ + public final Image.Builder content(String content) { + this.content = Objects.requireNonNull(content, "content"); + initBits &= ~INIT_BIT_CONTENT; + return (Image.Builder) this; + } + + /** + * Initializes the value for the {@link Image#getAltText() altText} attribute. + * @param altText The value for altText + * @return {@code this} builder for use in a chained invocation + */ + public final Image.Builder altText(String altText) { + this.altText = Objects.requireNonNull(altText, "altText"); + initBits &= ~INIT_BIT_ALT_TEXT; + return (Image.Builder) this; + } + + /** + * Builds a new {@link Image Image}. + * @return An immutable instance of Image + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public Image build() { + if (initBits != 0) { + throw new IllegalStateException(formatRequiredAttributesMessage()); + } + return new ImmutableImage(content, altText); + } + + private String formatRequiredAttributesMessage() { + List attributes = new ArrayList<>(); + if ((initBits & INIT_BIT_CONTENT) != 0) attributes.add("content"); + if ((initBits & INIT_BIT_ALT_TEXT) != 0) attributes.add("altText"); + return "Cannot build Image, some of required attributes are not set " + attributes; + } + } +} diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableKeyValuePairs.java jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableKeyValuePairs.java --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableKeyValuePairs.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableKeyValuePairs.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,221 @@ +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Immutable implementation of {@link KeyValuePairs}. + *

+ * Use the builder to create immutable instances: + * {@code new KeyValuePairs.Builder()}. + */ +@SuppressWarnings({"all"}) +final class ImmutableKeyValuePairs + implements KeyValuePairs { + private final Map content; + + private ImmutableKeyValuePairs(Map content) { + this.content = content; + } + + /** + * @return The value of the {@code content} attribute + */ + @Override + public Map getContent() { + return content; + } + + /** + * Copy the current immutable object by replacing the {@link KeyValuePairs#getContent() content} map with the specified map. + * Nulls are not permitted as keys or values. + * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. + * @param entries The entries to replace the content map + * @return A modified copy or {@code this} if not changed + */ + public final ImmutableKeyValuePairs withContent(Map entries) { + if (this.content == entries) return this; + Map newValue = createUnmodifiableMap(true, false, entries); + return new ImmutableKeyValuePairs(newValue); + } + + /** + * This instance is equal to all instances of {@code ImmutableKeyValuePairs} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutableKeyValuePairs + && equalsByValue((ImmutableKeyValuePairs) another); + } + + private boolean equalsByValue(ImmutableKeyValuePairs another) { + return content.equals(another.content); + } + + /** + * Computes a hash code from attributes: {@code content}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + content.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code KeyValuePairs} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + return "KeyValuePairs{" + + "content=" + content + + "}"; + } + + /** + * Creates an immutable copy of a {@link KeyValuePairs} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable KeyValuePairs instance + */ + public static KeyValuePairs copyOf(KeyValuePairs instance) { + if (instance instanceof ImmutableKeyValuePairs) { + return (ImmutableKeyValuePairs) instance; + } + return new KeyValuePairs.Builder() + .putAllContent(instance.getContent()) + .build(); + } + + /** + * Builds instances of type {@link KeyValuePairs KeyValuePairs}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static class Builder { + private Map content = new LinkedHashMap(); + + /** + * Creates a builder for {@link KeyValuePairs KeyValuePairs} instances. + *

+     * new KeyValuePairs.Builder()
+     *    .putContent|putAllContent(String => String) // {@link KeyValuePairs#getContent() content} mappings
+     *    .build();
+     * 
+ */ + public Builder() { + if (!(this instanceof KeyValuePairs.Builder)) { + throw new UnsupportedOperationException("Use: new KeyValuePairs.Builder()"); + } + } + + /** + * Put one entry to the {@link KeyValuePairs#getContent() content} map. + * @param key The key in the content map + * @param value The associated value in the content map + * @return {@code this} builder for use in a chained invocation + */ + public final KeyValuePairs.Builder putContent(String key, String value) { + this.content.put( + Objects.requireNonNull(key, "content key"), + Objects.requireNonNull(value, value == null ? "content value for key: " + key : null)); + return (KeyValuePairs.Builder) this; + } + + /** + * Put one entry to the {@link KeyValuePairs#getContent() content} map. Nulls are not permitted + * @param entry The key and value entry + * @return {@code this} builder for use in a chained invocation + */ + public final KeyValuePairs.Builder putContent(Map.Entry entry) { + String k = entry.getKey(); + String v = entry.getValue(); + this.content.put( + Objects.requireNonNull(k, "content key"), + Objects.requireNonNull(v, v == null ? "content value for key: " + k : null)); + return (KeyValuePairs.Builder) this; + } + + /** + * Sets or replaces all mappings from the specified map as entries for the {@link KeyValuePairs#getContent() content} map. Nulls are not permitted + * @param entries The entries that will be added to the content map + * @return {@code this} builder for use in a chained invocation + */ + public final KeyValuePairs.Builder content(Map entries) { + this.content.clear(); + return putAllContent(entries); + } + + /** + * Put all mappings from the specified map as entries to {@link KeyValuePairs#getContent() content} map. Nulls are not permitted + * @param entries The entries that will be added to the content map + * @return {@code this} builder for use in a chained invocation + */ + public final KeyValuePairs.Builder putAllContent(Map entries) { + for (Map.Entry e : entries.entrySet()) { + String k = e.getKey(); + String v = e.getValue(); + this.content.put( + Objects.requireNonNull(k, "content key"), + Objects.requireNonNull(v, v == null ? "content value for key: " + k : null)); + } + return (KeyValuePairs.Builder) this; + } + + /** + * Builds a new {@link KeyValuePairs KeyValuePairs}. + * @return An immutable instance of KeyValuePairs + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public KeyValuePairs build() { + return new ImmutableKeyValuePairs(createUnmodifiableMap(false, false, content)); + } + } + + private static Map createUnmodifiableMap(boolean checkNulls, boolean skipNulls, Map map) { + switch (map.size()) { + case 0: return Collections.emptyMap(); + case 1: { + Map.Entry e = map.entrySet().iterator().next(); + K k = e.getKey(); + V v = e.getValue(); + if (checkNulls) { + Objects.requireNonNull(k, "key"); + Objects.requireNonNull(v, v == null ? "value for key: " + k : null); + } + if (skipNulls && (k == null || v == null)) { + return Collections.emptyMap(); + } + return Collections.singletonMap(k, v); + } + default: { + Map linkedMap = new LinkedHashMap<>(map.size() * 4 / 3 + 1); + if (skipNulls || checkNulls) { + for (Map.Entry e : map.entrySet()) { + K k = e.getKey(); + V v = e.getValue(); + if (skipNulls) { + if (k == null || v == null) continue; + } else if (checkNulls) { + Objects.requireNonNull(k, "key"); + Objects.requireNonNull(v, v == null ? "value for key: " + k : null); + } + linkedMap.put(k, v); + } + } else { + linkedMap.putAll(map); + } + return Collections.unmodifiableMap(linkedMap); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableLabels.java jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableLabels.java --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableLabels.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableLabels.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,218 @@ +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Immutable implementation of {@link Labels}. + *

+ * Use the builder to create immutable instances: + * {@code new Labels.Builder()}. + */ +@SuppressWarnings({"all"}) +final class ImmutableLabels implements Labels { + private final List content; + + private ImmutableLabels(List content) { + this.content = content; + } + + /** + * @return The value of the {@code content} attribute + */ + @Override + public List getContent() { + return content; + } + + /** + * Copy the current immutable object with elements that replace the content of {@link Labels#getContent() content}. + * @param elements The elements to set + * @return A modified copy of {@code this} object + */ + public final ImmutableLabels withContent(String... elements) { + List newValue = createUnmodifiableList(false, createSafeList(Arrays.asList(elements), true, false)); + return new ImmutableLabels(newValue); + } + + /** + * Copy the current immutable object with elements that replace the content of {@link Labels#getContent() content}. + * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. + * @param elements An iterable of content elements to set + * @return A modified copy or {@code this} if not changed + */ + public final ImmutableLabels withContent(Iterable elements) { + if (this.content == elements) return this; + List newValue = createUnmodifiableList(false, createSafeList(elements, true, false)); + return new ImmutableLabels(newValue); + } + + /** + * This instance is equal to all instances of {@code ImmutableLabels} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutableLabels + && equalsByValue((ImmutableLabels) another); + } + + private boolean equalsByValue(ImmutableLabels another) { + return content.equals(another.content); + } + + /** + * Computes a hash code from attributes: {@code content}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + content.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code Labels} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + return "Labels{" + + "content=" + content + + "}"; + } + + /** + * Creates an immutable copy of a {@link Labels} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable Labels instance + */ + public static Labels copyOf(Labels instance) { + if (instance instanceof ImmutableLabels) { + return (ImmutableLabels) instance; + } + return new Labels.Builder() + .addAllContent(instance.getContent()) + .build(); + } + + /** + * Builds instances of type {@link Labels Labels}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static class Builder { + private List content = new ArrayList(); + + /** + * Creates a builder for {@link Labels Labels} instances. + *

+     * new Labels.Builder()
+     *    .addContent|addAllContent(String) // {@link Labels#getContent() content} elements
+     *    .build();
+     * 
+ */ + public Builder() { + if (!(this instanceof Labels.Builder)) { + throw new UnsupportedOperationException("Use: new Labels.Builder()"); + } + } + + /** + * Adds one element to {@link Labels#getContent() content} list. + * @param element A content element + * @return {@code this} builder for use in a chained invocation + */ + public final Labels.Builder addContent(String element) { + this.content.add(Objects.requireNonNull(element, "content element")); + return (Labels.Builder) this; + } + + /** + * Adds elements to {@link Labels#getContent() content} list. + * @param elements An array of content elements + * @return {@code this} builder for use in a chained invocation + */ + public final Labels.Builder addContent(String... elements) { + for (String element : elements) { + this.content.add(Objects.requireNonNull(element, "content element")); + } + return (Labels.Builder) this; + } + + + /** + * Sets or replaces all elements for {@link Labels#getContent() content} list. + * @param elements An iterable of content elements + * @return {@code this} builder for use in a chained invocation + */ + public final Labels.Builder content(Iterable elements) { + this.content.clear(); + return addAllContent(elements); + } + + /** + * Adds elements to {@link Labels#getContent() content} list. + * @param elements An iterable of content elements + * @return {@code this} builder for use in a chained invocation + */ + public final Labels.Builder addAllContent(Iterable elements) { + for (String element : elements) { + this.content.add(Objects.requireNonNull(element, "content element")); + } + return (Labels.Builder) this; + } + + /** + * Builds a new {@link Labels Labels}. + * @return An immutable instance of Labels + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public Labels build() { + return new ImmutableLabels(createUnmodifiableList(true, content)); + } + } + + private static List createSafeList(Iterable iterable, boolean checkNulls, boolean skipNulls) { + ArrayList list; + if (iterable instanceof Collection) { + int size = ((Collection) iterable).size(); + if (size == 0) return Collections.emptyList(); + list = new ArrayList<>(size); + } else { + list = new ArrayList<>(); + } + for (T element : iterable) { + if (skipNulls && element == null) continue; + if (checkNulls) Objects.requireNonNull(element, "element"); + list.add(element); + } + return list; + } + + private static List createUnmodifiableList(boolean clone, List list) { + switch(list.size()) { + case 0: return Collections.emptyList(); + case 1: return Collections.singletonList(list.get(0)); + default: + if (clone) { + return Collections.unmodifiableList(new ArrayList<>(list)); + } else { + if (list instanceof ArrayList) { + ((ArrayList) list).trimToSize(); + } + return Collections.unmodifiableList(list); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableParagraph.java jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableParagraph.java --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableParagraph.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableParagraph.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,150 @@ +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Immutable implementation of {@link Paragraph}. + *

+ * Use the builder to create immutable instances: + * {@code new Paragraph.Builder()}. + */ +@SuppressWarnings({"all"}) +final class ImmutableParagraph implements Paragraph { + private final String content; + + private ImmutableParagraph(String content) { + this.content = content; + } + + /** + * @return The value of the {@code content} attribute + */ + @Override + public String getContent() { + return content; + } + + /** + * Copy the current immutable object by setting a value for the {@link Paragraph#getContent() content} attribute. + * An equals check used to prevent copying of the same value by returning {@code this}. + * @param value A new value for content + * @return A modified copy or the {@code this} object + */ + public final ImmutableParagraph withContent(String value) { + String newValue = Objects.requireNonNull(value, "content"); + if (this.content.equals(newValue)) return this; + return new ImmutableParagraph(newValue); + } + + /** + * This instance is equal to all instances of {@code ImmutableParagraph} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutableParagraph + && equalsByValue((ImmutableParagraph) another); + } + + private boolean equalsByValue(ImmutableParagraph another) { + return content.equals(another.content); + } + + /** + * Computes a hash code from attributes: {@code content}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + content.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code Paragraph} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + return "Paragraph{" + + "content=" + content + + "}"; + } + + /** + * Creates an immutable copy of a {@link Paragraph} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable Paragraph instance + */ + public static Paragraph copyOf(Paragraph instance) { + if (instance instanceof ImmutableParagraph) { + return (ImmutableParagraph) instance; + } + return new Paragraph.Builder() + .content(instance.getContent()) + .build(); + } + + /** + * Builds instances of type {@link Paragraph Paragraph}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static class Builder { + private static final long INIT_BIT_CONTENT = 0x1L; + private long initBits = 0x1L; + + private String content; + + /** + * Creates a builder for {@link Paragraph Paragraph} instances. + *

+     * new Paragraph.Builder()
+     *    .content(String) // required {@link Paragraph#getContent() content}
+     *    .build();
+     * 
+ */ + public Builder() { + if (!(this instanceof Paragraph.Builder)) { + throw new UnsupportedOperationException("Use: new Paragraph.Builder()"); + } + } + + /** + * Initializes the value for the {@link Paragraph#getContent() content} attribute. + * @param content The value for content + * @return {@code this} builder for use in a chained invocation + */ + public final Paragraph.Builder content(String content) { + this.content = Objects.requireNonNull(content, "content"); + initBits &= ~INIT_BIT_CONTENT; + return (Paragraph.Builder) this; + } + + /** + * Builds a new {@link Paragraph Paragraph}. + * @return An immutable instance of Paragraph + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public Paragraph build() { + if (initBits != 0) { + throw new IllegalStateException(formatRequiredAttributesMessage()); + } + return new ImmutableParagraph(content); + } + + private String formatRequiredAttributesMessage() { + List attributes = new ArrayList<>(); + if ((initBits & INIT_BIT_CONTENT) != 0) attributes.add("content"); + return "Cannot build Paragraph, some of required attributes are not set " + attributes; + } + } +} diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutablePreFormattedOutput.java jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutablePreFormattedOutput.java --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutablePreFormattedOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutablePreFormattedOutput.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,151 @@ +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Immutable implementation of {@link PreFormattedOutput}. + *

+ * Use the builder to create immutable instances: + * {@code new PreFormattedOutput.Builder()}. + */ +@SuppressWarnings({"all"}) +final class ImmutablePreFormattedOutput + implements PreFormattedOutput { + private final String content; + + private ImmutablePreFormattedOutput(String content) { + this.content = content; + } + + /** + * @return The value of the {@code content} attribute + */ + @Override + public String getContent() { + return content; + } + + /** + * Copy the current immutable object by setting a value for the {@link PreFormattedOutput#getContent() content} attribute. + * An equals check used to prevent copying of the same value by returning {@code this}. + * @param value A new value for content + * @return A modified copy or the {@code this} object + */ + public final ImmutablePreFormattedOutput withContent(String value) { + String newValue = Objects.requireNonNull(value, "content"); + if (this.content.equals(newValue)) return this; + return new ImmutablePreFormattedOutput(newValue); + } + + /** + * This instance is equal to all instances of {@code ImmutablePreFormattedOutput} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutablePreFormattedOutput + && equalsByValue((ImmutablePreFormattedOutput) another); + } + + private boolean equalsByValue(ImmutablePreFormattedOutput another) { + return content.equals(another.content); + } + + /** + * Computes a hash code from attributes: {@code content}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + content.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code PreFormattedOutput} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + return "PreFormattedOutput{" + + "content=" + content + + "}"; + } + + /** + * Creates an immutable copy of a {@link PreFormattedOutput} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable PreFormattedOutput instance + */ + public static PreFormattedOutput copyOf(PreFormattedOutput instance) { + if (instance instanceof ImmutablePreFormattedOutput) { + return (ImmutablePreFormattedOutput) instance; + } + return new PreFormattedOutput.Builder() + .content(instance.getContent()) + .build(); + } + + /** + * Builds instances of type {@link PreFormattedOutput PreFormattedOutput}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static class Builder { + private static final long INIT_BIT_CONTENT = 0x1L; + private long initBits = 0x1L; + + private String content; + + /** + * Creates a builder for {@link PreFormattedOutput PreFormattedOutput} instances. + *

+     * new PreFormattedOutput.Builder()
+     *    .content(String) // required {@link PreFormattedOutput#getContent() content}
+     *    .build();
+     * 
+ */ + public Builder() { + if (!(this instanceof PreFormattedOutput.Builder)) { + throw new UnsupportedOperationException("Use: new PreFormattedOutput.Builder()"); + } + } + + /** + * Initializes the value for the {@link PreFormattedOutput#getContent() content} attribute. + * @param content The value for content + * @return {@code this} builder for use in a chained invocation + */ + public final PreFormattedOutput.Builder content(String content) { + this.content = Objects.requireNonNull(content, "content"); + initBits &= ~INIT_BIT_CONTENT; + return (PreFormattedOutput.Builder) this; + } + + /** + * Builds a new {@link PreFormattedOutput PreFormattedOutput}. + * @return An immutable instance of PreFormattedOutput + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public PreFormattedOutput build() { + if (initBits != 0) { + throw new IllegalStateException(formatRequiredAttributesMessage()); + } + return new ImmutablePreFormattedOutput(content); + } + + private String formatRequiredAttributesMessage() { + List attributes = new ArrayList<>(); + if ((initBits & INIT_BIT_CONTENT) != 0) attributes.add("content"); + return "Cannot build PreFormattedOutput, some of required attributes are not set " + attributes; + } + } +} diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableSection.java jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableSection.java --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableSection.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableSection.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,394 @@ +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * Immutable implementation of {@link Section}. + *

+ * Use the builder to create immutable instances: + * {@code new Section.Builder()}. + */ +@SuppressWarnings({"all"}) +final class ImmutableSection implements Section { + private final String title; + private final String metaInfo; + private final List> blocks; + private final int order; + + private ImmutableSection(ImmutableSection.Builder builder) { + this.title = builder.title; + this.metaInfo = builder.metaInfo; + this.blocks = createUnmodifiableList(true, builder.blocks); + this.order = builder.orderIsSet() + ? builder.order + : Section.super.getOrder(); + } + + private ImmutableSection( + String title, + String metaInfo, + List> blocks, + int order) { + this.title = title; + this.metaInfo = metaInfo; + this.blocks = blocks; + this.order = order; + } + + /** + * @return The value of the {@code title} attribute + */ + @Override + public String getTitle() { + return title; + } + + /** + * @return The value of the {@code metaInfo} attribute + */ + @Override + public Optional getMetaInfo() { + return Optional.ofNullable(metaInfo); + } + + /** + * @return The value of the {@code blocks} attribute + */ + @Override + public List> getBlocks() { + return blocks; + } + + /** + * @return The value of the {@code order} attribute + */ + @Override + public int getOrder() { + return order; + } + + /** + * Copy the current immutable object by setting a value for the {@link Section#getTitle() title} attribute. + * An equals check used to prevent copying of the same value by returning {@code this}. + * @param value A new value for title + * @return A modified copy or the {@code this} object + */ + public final ImmutableSection withTitle(String value) { + String newValue = Objects.requireNonNull(value, "title"); + if (this.title.equals(newValue)) return this; + return new ImmutableSection(newValue, this.metaInfo, this.blocks, this.order); + } + + /** + * Copy the current immutable object by setting a present value for the optional {@link Section#getMetaInfo() metaInfo} attribute. + * @param value The value for metaInfo + * @return A modified copy or {@code this} if not changed + */ + public final ImmutableSection withMetaInfo(String value) { + String newValue = Objects.requireNonNull(value, "metaInfo"); + if (Objects.equals(this.metaInfo, newValue)) return this; + return new ImmutableSection(this.title, newValue, this.blocks, this.order); + } + + /** + * Copy the current immutable object by setting an optional value for the {@link Section#getMetaInfo() metaInfo} attribute. + * An equality check is used on inner value to prevent copying of the same value by returning {@code this}. + * @param optional An optional value for metaInfo + * @return A modified copy or {@code this} if not changed + */ + public final ImmutableSection withMetaInfo(Optional optional) { + String value = optional.orElse(null); + if (Objects.equals(this.metaInfo, value)) return this; + return new ImmutableSection(this.title, value, this.blocks, this.order); + } + + /** + * Copy the current immutable object with elements that replace the content of {@link Section#getBlocks() blocks}. + * @param elements The elements to set + * @return A modified copy of {@code this} object + */ + @SafeVarargs @SuppressWarnings("varargs") + public final ImmutableSection withBlocks(Block... elements) { + List> newValue = createUnmodifiableList(false, createSafeList(Arrays.asList(elements), true, false)); + return new ImmutableSection(this.title, this.metaInfo, newValue, this.order); + } + + /** + * Copy the current immutable object with elements that replace the content of {@link Section#getBlocks() blocks}. + * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. + * @param elements An iterable of blocks elements to set + * @return A modified copy or {@code this} if not changed + */ + public final ImmutableSection withBlocks(Iterable> elements) { + if (this.blocks == elements) return this; + List> newValue = createUnmodifiableList(false, createSafeList(elements, true, false)); + return new ImmutableSection(this.title, this.metaInfo, newValue, this.order); + } + + /** + * Copy the current immutable object by setting a value for the {@link Section#getOrder() order} attribute. + * A value equality check is used to prevent copying of the same value by returning {@code this}. + * @param value A new value for order + * @return A modified copy or the {@code this} object + */ + public final ImmutableSection withOrder(int value) { + if (this.order == value) return this; + return new ImmutableSection(this.title, this.metaInfo, this.blocks, value); + } + + /** + * This instance is equal to all instances of {@code ImmutableSection} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutableSection + && equalsByValue((ImmutableSection) another); + } + + private boolean equalsByValue(ImmutableSection another) { + return title.equals(another.title) + && Objects.equals(metaInfo, another.metaInfo) + && blocks.equals(another.blocks) + && order == another.order; + } + + /** + * Computes a hash code from attributes: {@code title}, {@code metaInfo}, {@code blocks}, {@code order}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + title.hashCode(); + h += (h << 5) + Objects.hashCode(metaInfo); + h += (h << 5) + blocks.hashCode(); + h += (h << 5) + order; + return h; + } + + /** + * Prints the immutable value {@code Section} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder("Section{"); + builder.append("title=").append(title); + if (metaInfo != null) { + builder.append(", "); + builder.append("metaInfo=").append(metaInfo); + } + builder.append(", "); + builder.append("blocks=").append(blocks); + builder.append(", "); + builder.append("order=").append(order); + return builder.append("}").toString(); + } + + /** + * Creates an immutable copy of a {@link Section} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable Section instance + */ + public static Section copyOf(Section instance) { + if (instance instanceof ImmutableSection) { + return (ImmutableSection) instance; + } + return new Section.Builder() + .title(instance.getTitle()) + .metaInfo(instance.getMetaInfo()) + .addAllBlocks(instance.getBlocks()) + .order(instance.getOrder()) + .build(); + } + + /** + * Builds instances of type {@link Section Section}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static class Builder { + private static final long INIT_BIT_TITLE = 0x1L; + private static final long OPT_BIT_ORDER = 0x1L; + private long initBits = 0x1L; + private long optBits; + + private String title; + private String metaInfo; + private List> blocks = new ArrayList>(); + private int order; + + /** + * Creates a builder for {@link Section Section} instances. + *

+     * new Section.Builder()
+     *    .title(String) // required {@link Section#getTitle() title}
+     *    .metaInfo(Optional<String>) // optional {@link Section#getMetaInfo() metaInfo}
+     *    .addBlock|addAllBlocks(org.opentest4j.reporting.tooling.spi.htmlreport.Block<?>) // {@link Section#getBlocks() blocks} elements
+     *    .order(int) // optional {@link Section#getOrder() order}
+     *    .build();
+     * 
+ */ + public Builder() { + if (!(this instanceof Section.Builder)) { + throw new UnsupportedOperationException("Use: new Section.Builder()"); + } + } + + /** + * Initializes the value for the {@link Section#getTitle() title} attribute. + * @param title The value for title + * @return {@code this} builder for use in a chained invocation + */ + public final Section.Builder title(String title) { + this.title = Objects.requireNonNull(title, "title"); + initBits &= ~INIT_BIT_TITLE; + return (Section.Builder) this; + } + + /** + * Initializes the optional value {@link Section#getMetaInfo() metaInfo} to metaInfo. + * @param metaInfo The value for metaInfo + * @return {@code this} builder for chained invocation + */ + public final Section.Builder metaInfo(String metaInfo) { + this.metaInfo = Objects.requireNonNull(metaInfo, "metaInfo"); + return (Section.Builder) this; + } + + /** + * Initializes the optional value {@link Section#getMetaInfo() metaInfo} to metaInfo. + * @param metaInfo The value for metaInfo + * @return {@code this} builder for use in a chained invocation + */ + public final Section.Builder metaInfo(Optional metaInfo) { + this.metaInfo = metaInfo.orElse(null); + return (Section.Builder) this; + } + + /** + * Adds one element to {@link Section#getBlocks() blocks} list. + * @param element A blocks element + * @return {@code this} builder for use in a chained invocation + */ + public final Section.Builder addBlock(Block element) { + this.blocks.add(Objects.requireNonNull(element, "blocks element")); + return (Section.Builder) this; + } + + /** + * Adds elements to {@link Section#getBlocks() blocks} list. + * @param elements An array of blocks elements + * @return {@code this} builder for use in a chained invocation + */ + @SafeVarargs @SuppressWarnings("varargs") + public final Section.Builder addBlocks(Block... elements) { + for (Block element : elements) { + this.blocks.add(Objects.requireNonNull(element, "blocks element")); + } + return (Section.Builder) this; + } + + + /** + * Sets or replaces all elements for {@link Section#getBlocks() blocks} list. + * @param elements An iterable of blocks elements + * @return {@code this} builder for use in a chained invocation + */ + public final Section.Builder blocks(Iterable> elements) { + this.blocks.clear(); + return addAllBlocks(elements); + } + + /** + * Adds elements to {@link Section#getBlocks() blocks} list. + * @param elements An iterable of blocks elements + * @return {@code this} builder for use in a chained invocation + */ + public final Section.Builder addAllBlocks(Iterable> elements) { + for (Block element : elements) { + this.blocks.add(Objects.requireNonNull(element, "blocks element")); + } + return (Section.Builder) this; + } + + /** + * Initializes the value for the {@link Section#getOrder() order} attribute. + *

If not set, this attribute will have a default value as returned by the initializer of {@link Section#getOrder() order}. + * @param order The value for order + * @return {@code this} builder for use in a chained invocation + */ + public final Section.Builder order(int order) { + this.order = order; + optBits |= OPT_BIT_ORDER; + return (Section.Builder) this; + } + + /** + * Builds a new {@link Section Section}. + * @return An immutable instance of Section + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public Section build() { + if (initBits != 0) { + throw new IllegalStateException(formatRequiredAttributesMessage()); + } + return new ImmutableSection(this); + } + + private boolean orderIsSet() { + return (optBits & OPT_BIT_ORDER) != 0; + } + + private String formatRequiredAttributesMessage() { + List attributes = new ArrayList<>(); + if ((initBits & INIT_BIT_TITLE) != 0) attributes.add("title"); + return "Cannot build Section, some of required attributes are not set " + attributes; + } + } + + private static List createSafeList(Iterable iterable, boolean checkNulls, boolean skipNulls) { + ArrayList list; + if (iterable instanceof Collection) { + int size = ((Collection) iterable).size(); + if (size == 0) return Collections.emptyList(); + list = new ArrayList<>(size); + } else { + list = new ArrayList<>(); + } + for (T element : iterable) { + if (skipNulls && element == null) continue; + if (checkNulls) Objects.requireNonNull(element, "element"); + list.add(element); + } + return list; + } + + private static List createUnmodifiableList(boolean clone, List list) { + switch(list.size()) { + case 0: return Collections.emptyList(); + case 1: return Collections.singletonList(list.get(0)); + default: + if (clone) { + return Collections.unmodifiableList(new ArrayList<>(list)); + } else { + if (list instanceof ArrayList) { + ((ArrayList) list).trimToSize(); + } + return Collections.unmodifiableList(list); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableSubsections.java jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableSubsections.java --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/generated/ImmutableSubsections.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/generated/ImmutableSubsections.java 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,218 @@ +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Immutable implementation of {@link Subsections}. + *

+ * Use the builder to create immutable instances: + * {@code new Subsections.Builder()}. + */ +@SuppressWarnings({"all"}) +final class ImmutableSubsections implements Subsections { + private final List

content; + + private ImmutableSubsections(List
content) { + this.content = content; + } + + /** + * @return The value of the {@code content} attribute + */ + @Override + public List
getContent() { + return content; + } + + /** + * Copy the current immutable object with elements that replace the content of {@link Subsections#getContent() content}. + * @param elements The elements to set + * @return A modified copy of {@code this} object + */ + public final ImmutableSubsections withContent(Section... elements) { + List
newValue = createUnmodifiableList(false, createSafeList(Arrays.asList(elements), true, false)); + return new ImmutableSubsections(newValue); + } + + /** + * Copy the current immutable object with elements that replace the content of {@link Subsections#getContent() content}. + * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. + * @param elements An iterable of content elements to set + * @return A modified copy or {@code this} if not changed + */ + public final ImmutableSubsections withContent(Iterable elements) { + if (this.content == elements) return this; + List
newValue = createUnmodifiableList(false, createSafeList(elements, true, false)); + return new ImmutableSubsections(newValue); + } + + /** + * This instance is equal to all instances of {@code ImmutableSubsections} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutableSubsections + && equalsByValue((ImmutableSubsections) another); + } + + private boolean equalsByValue(ImmutableSubsections another) { + return content.equals(another.content); + } + + /** + * Computes a hash code from attributes: {@code content}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + content.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code Subsections} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + return "Subsections{" + + "content=" + content + + "}"; + } + + /** + * Creates an immutable copy of a {@link Subsections} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable Subsections instance + */ + public static Subsections copyOf(Subsections instance) { + if (instance instanceof ImmutableSubsections) { + return (ImmutableSubsections) instance; + } + return new Subsections.Builder() + .addAllContent(instance.getContent()) + .build(); + } + + /** + * Builds instances of type {@link Subsections Subsections}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static class Builder { + private List

content = new ArrayList
(); + + /** + * Creates a builder for {@link Subsections Subsections} instances. + *
+     * new Subsections.Builder()
+     *    .addContent|addAllContent(org.opentest4j.reporting.tooling.spi.htmlreport.Section) // {@link Subsections#getContent() content} elements
+     *    .build();
+     * 
+ */ + public Builder() { + if (!(this instanceof Subsections.Builder)) { + throw new UnsupportedOperationException("Use: new Subsections.Builder()"); + } + } + + /** + * Adds one element to {@link Subsections#getContent() content} list. + * @param element A content element + * @return {@code this} builder for use in a chained invocation + */ + public final Subsections.Builder addContent(Section element) { + this.content.add(Objects.requireNonNull(element, "content element")); + return (Subsections.Builder) this; + } + + /** + * Adds elements to {@link Subsections#getContent() content} list. + * @param elements An array of content elements + * @return {@code this} builder for use in a chained invocation + */ + public final Subsections.Builder addContent(Section... elements) { + for (Section element : elements) { + this.content.add(Objects.requireNonNull(element, "content element")); + } + return (Subsections.Builder) this; + } + + + /** + * Sets or replaces all elements for {@link Subsections#getContent() content} list. + * @param elements An iterable of content elements + * @return {@code this} builder for use in a chained invocation + */ + public final Subsections.Builder content(Iterable elements) { + this.content.clear(); + return addAllContent(elements); + } + + /** + * Adds elements to {@link Subsections#getContent() content} list. + * @param elements An iterable of content elements + * @return {@code this} builder for use in a chained invocation + */ + public final Subsections.Builder addAllContent(Iterable elements) { + for (Section element : elements) { + this.content.add(Objects.requireNonNull(element, "content element")); + } + return (Subsections.Builder) this; + } + + /** + * Builds a new {@link Subsections Subsections}. + * @return An immutable instance of Subsections + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public Subsections build() { + return new ImmutableSubsections(createUnmodifiableList(true, content)); + } + } + + private static List createSafeList(Iterable iterable, boolean checkNulls, boolean skipNulls) { + ArrayList list; + if (iterable instanceof Collection) { + int size = ((Collection) iterable).size(); + if (size == 0) return Collections.emptyList(); + list = new ArrayList<>(size); + } else { + list = new ArrayList<>(); + } + for (T element : iterable) { + if (skipNulls && element == null) continue; + if (checkNulls) Objects.requireNonNull(element, "element"); + list.add(element); + } + return list; + } + + private static List createUnmodifiableList(boolean clone, List list) { + switch(list.size()) { + case 0: return Collections.emptyList(); + case 1: return Collections.singletonList(list.get(0)); + default: + if (clone) { + return Collections.unmodifiableList(new ArrayList<>(list)); + } else { + if (list instanceof ArrayList) { + ((ArrayList) list).trimToSize(); + } + return Collections.unmodifiableList(list); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/poms jtreg8-8.3+1+ds1/debian/opentest4j-reporting/poms --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/poms 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/poms 2026-09-30 21:11:41.000000000 +0000 @@ -1,2 +1,32 @@ +# List of POM files for the package +# Format of this file is: +# [option]* +# where option can be: +# --ignore: ignore this POM and its artifact if any +# --ignore-pom: don't install the POM. To use on POM files that are created +# temporarily for certain artifacts such as Javadoc jars. [mh_install, mh_installpoms] +# --no-parent: remove the tag from the POM +# --package=: an alternative package to use when installing this POM +# and its artifact +# --has-package-version: to indicate that the original version of the POM is the same as the upstream part +# of the version for the package. +# --keep-elements=: a list of XML elements to keep in the POM +# during a clean operation with mh_cleanpom or mh_installpom +# --artifact=: path to the build artifact associated with this POM, +# it will be installed when using the command mh_install. [mh_install] +# --java-lib: install the jar into /usr/share/java to comply with Debian +# packaging guidelines +# --usj-name=: name to use when installing the library in /usr/share/java +# --usj-version=: version to use when installing the library in /usr/share/java +# --no-usj-versionless: don't install the versionless link in /usr/share/java +# --dest-jar=: the destination for the real jar. +# It will be installed with mh_install. [mh_install] +# --classifier=: Optional, the classifier for the jar. Empty by default. +# --site-xml=: Optional, the location for site.xml if it needs to be installed. +# Empty by default. [mh_install] +# + schema/build/debian/schema.pom --has-package-version --java-lib --usj-name=opentest4j-reporting-schema --artifact=schema/build/libs/schema-*.jar events/build/debian/events.pom --has-package-version --java-lib --usj-name=opentest4j-reporting-events --artifact=events/build/libs/events-*.jar +tooling-core/build/debian/tooling-core.pom --has-package-version --java-lib --usj-name=opentest4j-reporting-tooling-core --artifact=tooling-core/build/libs/tooling-core-*.jar +tooling-spi/build/debian/tooling-spi.pom --has-package-version --java-lib --usj-name=opentest4j-reporting-tooling-spi --artifact=tooling-spi/build/libs/tooling-spi-*.jar diff -Nru jtreg8-8.1+1+ds1/debian/opentest4j-reporting/rules jtreg8-8.3+1+ds1/debian/opentest4j-reporting/rules --- jtreg8-8.1+1+ds1/debian/opentest4j-reporting/rules 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/opentest4j-reporting/rules 2026-09-30 21:11:41.000000000 +0000 @@ -1,10 +1,24 @@ #!/usr/bin/make -f +SPI_DIR=tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/ + %: dh $@ --buildsystem=gradle --with maven-repo-helper +override_dh_auto_clean: + for file in ../debian/opentest4j-reporting/generated/*; do \ + rm -f "$(SPI_DIR)/$$(basename "$$file")"; \ + done + dh_auto_clean + +override_dh_auto_build: + # Copy generated sources to the appropriate location + cp ../debian/opentest4j-reporting/generated/* "$(SPI_DIR)/" + find . -name "*.gradle.kts" -delete + dh_auto_build + override_dh_auto_test: override_dh_auto_configure: dh_auto_configure $@ - rsync -Lav ../debian/built-components/ debian/ || true \ No newline at end of file + rsync -Lav ../debian/built-components/ debian/ || true diff -Nru jtreg8-8.1+1+ds1/debian/patches/codetools-7904105-proposed.patch jtreg8-8.3+1+ds1/debian/patches/codetools-7904105-proposed.patch --- jtreg8-8.1+1+ds1/debian/patches/codetools-7904105-proposed.patch 2025-10-28 04:51:41.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/codetools-7904105-proposed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -Description: intermittent test failure in CleanupDirTests.agentvm.conc - jtharness does not synchronize calls to Observer. Synchronized keyword - needs to be added when processing shared state. -Author: Vladimir Petko -Origin: upstream, https://github.com/openjdk/jtreg/pull/297 -Bug: https://bugs.openjdk.org/browse/CODETOOLS-7904105 -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1115694 -Last-Update: 2025-10-28 - ---- a/src/share/classes/com/sun/javatest/regtest/report/TestStats.java -+++ b/src/share/classes/com/sun/javatest/regtest/report/TestStats.java -@@ -99,7 +99,7 @@ - } - - @Override -- public void finishedTest(TestResult tr) { -+ public synchronized void finishedTest(TestResult tr) { - add(tr); - } - ---- a/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java -+++ b/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java -@@ -365,7 +365,7 @@ - } - - @Override -- public void finishedTest(TestResult tr) { -+ public synchronized void finishedTest(TestResult tr) { - try { - super.finishedTest(tr); - new XMLWriter(tr, mustVerify, harnessOut, harnessErr).toXML(); ---- a/src/share/classes/com/sun/javatest/regtest/tool/Tool.java -+++ b/src/share/classes/com/sun/javatest/regtest/tool/Tool.java -@@ -1946,7 +1946,7 @@ - - h.addObserver(new BasicObserver() { - @Override -- public void error(String msg) { -+ public synchronized void error(String msg) { - Tool.this.error(msg); - } - }); diff -Nru jtreg8-8.1+1+ds1/debian/patches/codetools-7904106-proposed.patch jtreg8-8.3+1+ds1/debian/patches/codetools-7904106-proposed.patch --- jtreg8-8.1+1+ds1/debian/patches/codetools-7904106-proposed.patch 2025-10-28 04:51:41.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/codetools-7904106-proposed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -Description: TestNativePath: use different work directories - Both agentvm and othervm targets in TestNativePath use the same work path - $(BUILDTESTDIR)/nativepath.othervm/work. - This causes intermittent test failures when the tests are run in parallel. -Author: Vladimir Petko -Origin: upstream, https://github.com/openjdk/jtreg/pull/298 -Bug: https://bugs.openjdk.org/browse/CODETOOLS-7904106 -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1115694 -Last-Update: 2025-10-28 - ---- a/test/nativepath/TestNativePath.gmk -+++ b/test/nativepath/TestNativePath.gmk -@@ -39,16 +39,16 @@ - -jdk:$(JDKHOME) \ - -nativepath:$(NATIVEPATH) \ - -vmoption:-Dcorrect.nativepath=$(NATIVEPATH) \ -- -w:$(BUILDTESTDIR)/nativepath.othervm/work \ -- -r:$(BUILDTESTDIR)/nativepath.othervm/report \ -+ -w:$(@:%.ok=%nativepath.othervm)/work \ -+ -r:$(@:%.ok=%nativepath.othervm)/report \ - -verbose:fail \ - $(@:$(BUILDTESTDIR)/TestNativePath.%.ok=-%) \ - $(TESTDIR)/nativepath/NativesOK.java - - $(JTREG_IMAGEDIR)/bin/jtreg $(JTREG_OPTS) \ - -jdk:$(JDKHOME) \ -- -w:$(BUILDTESTDIR)/nativepath.othervm2/work \ -- -r:$(BUILDTESTDIR)/nativepath.othervm2/report \ -+ -w:$(@:%.ok=%nativepath.othervm2)/work \ -+ -r:$(@:%.ok=%nativepath.othervm2)/report \ - -verbose:fail \ - $(@:$(BUILDTESTDIR)/TestNativePath.%.ok=-%) \ - $(TESTDIR)/nativepath/NativesEmpty.java -@@ -83,8 +83,8 @@ - # should yield an error - $(JTREG_IMAGEDIR)/bin/jtreg $(JTREG_OPTS) \ - -jdk:$(JDKHOME) \ -- -w:$(BUILDTESTDIR)/nativepath.othervm2/work \ -- -r:$(BUILDTESTDIR)/nativepath.othervm2/report \ -+ -w:$(@:%.ok=%nativepath.othervm2)/work \ -+ -r:$(@:%.ok=%nativepath.othervm2)/report \ - -verbose:fail \ - $(TESTDIR)/nativepath/NativesOK.java \ - 2>&1 | grep -q "Use -nativepath to specify the location of native code" -@@ -92,8 +92,8 @@ - # Exclude all tests with native code - $(JTREG_IMAGEDIR)/bin/jtreg $(JTREG_OPTS) \ - -jdk:$(JDKHOME) \ -- -w:$(BUILDTESTDIR)/nativepath.othervm2/work \ -- -r:$(BUILDTESTDIR)/nativepath.othervm2/report \ -+ -w:$(@:%.ok=%nativepath.othervm2)/work \ -+ -r:$(@:%.ok=%nativepath.othervm2)/report \ - -k:!native \ - -verbose:fail \ - $(TESTDIR)/nativepath/NativesOK.java \ -@@ -104,15 +104,15 @@ - -jdk:$(JDKHOME) \ - -nativepath:$(NATIVEPATH) \ - -e:CORRECTNATIVEPATH=$(NATIVEPATH) \ -- -w:$(BUILDTESTDIR)/nativepath.shell/work \ -- -r:$(BUILDTESTDIR)/nativepath.shell/report \ -+ -w:$(@:%.ok=%nativepath.shell)/work \ -+ -r:$(@:%.ok=%nativepath.shell)/report \ - -verbose:fail \ - $(TESTDIR)/nativepath/NativesOKShell.sh - - $(JTREG_IMAGEDIR)/bin/jtreg $(JTREG_OPTS) \ - -jdk:$(JDKHOME) \ -- -w:$(BUILDTESTDIR)/nativepath.shell/work \ -- -r:$(BUILDTESTDIR)/nativepath.shell/report \ -+ -w:$(@:%.ok=%nativepath.shell)/work \ -+ -r:$(@:%.ok=%nativepath.shell)/report \ - -verbose:fail \ - $(TESTDIR)/nativepath/NativesEmptyShell.sh - -@@ -125,15 +125,15 @@ - $(JTREG_IMAGEDIR)/lib/jtreg.jar \ - $(JTREG_IMAGEDIR)/bin/jtreg - -- $(RM) $(BUILDTESTDIR)/nativepath.relative/ -- $(MKDIR) $(BUILDTESTDIR)/nativepath.relative/foobar/hello/world -+ $(RM) $(@:%.ok=%nativepath.relative) -+ $(MKDIR) $(@:%.ok=%nativepath.relative)/foobar/hello/world - - cd $(BUILDTESTDIR); $(JTREG_IMAGEDIR)/bin/jtreg $(JTREG_OPTS) \ - -jdk:$(JDKHOME) \ -- -nativepath:nativepath.relative/foobar/hello/world \ -- -vmoption:-Dcorrect.nativepath=$(BUILDTESTDIR)/nativepath.relative/foobar/hello/world \ -- -w:$(BUILDTESTDIR)/nativepath.relative/work \ -- -r:$(BUILDTESTDIR)/nativepath.relative/report \ -+ -nativepath:$(@:$(BUILDTESTDIR)/%.ok=%nativepath.relative)/foobar/hello/world \ -+ -vmoption:-Dcorrect.nativepath=$(@:%.ok=%nativepath.relative)/foobar/hello/world \ -+ -w:$(@:%.ok=%nativepath.relative)/work \ -+ -r:$(@:%.ok=%nativepath.relative)/report \ - -verbose:fail \ - $(ABS_TESTDIR)/nativepath/NativesOK.java - -@@ -150,4 +150,3 @@ - $(BUILDTESTDIR)/TestNativePath.agentvm.ok \ - $(BUILDTESTDIR)/TestNativePath.othervm.ok \ - $(BUILDTESTDIR)/TestRelativeNativePath.ok -- diff -Nru jtreg8-8.1+1+ds1/debian/patches/codetools-7904107-proposed.patch jtreg8-8.3+1+ds1/debian/patches/codetools-7904107-proposed.patch --- jtreg8-8.1+1+ds1/debian/patches/codetools-7904107-proposed.patch 2025-10-28 04:51:41.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/codetools-7904107-proposed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -Description: AgentOut.othervm.ok should not access $(BUILDTESTDIR)/AgentOut.agentvm - AgentOut.othervm.ok tries to access $(BUILDTESTDIR)/AgentOut.agentvm. - This should only happen in AgentOut.agentvm.ok. - Add a new target to filter log lines that depends on AgentOut.agentvm.ok. -Author: Vladimir Petko -Origin: upstream, https://github.com/openjdk/jtreg/pull/299 -Bug: https://bugs.openjdk.org/browse/CODETOOLS-7904107 -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1115694 -Last-Update: 2025-10-28 - ---- a/test/agentout/AgentOut.gmk -+++ b/test/agentout/AgentOut.gmk -@@ -78,6 +78,10 @@ - < $$i \ - > `dirname $$i`-filtered/`basename $$i` ; \ - done -+ # -+ echo "run at `date`" > $@ -+ -+$(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered.ok: $(BUILDTESTDIR)/AgentOut.agentvm.ok - # merge direct and stderr from agent CompileTest to match stderr from othervm CompileTest - $(CAT) $(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered/CompileTest-direct.log \ - $(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered/CompileTest-System.err.log \ -@@ -85,12 +89,10 @@ - $(MV) $(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered/tmp.log \ - $(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered/CompileTest-System.err.log - $(CAT) < $(DEV_NULL) > $(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered/CompileTest-direct.log -- # -- echo "run at `date`" > $@ - - $(BUILDTESTDIR)/AgentOut.ok: \ -- $(BUILDTESTDIR)/AgentOut.agentvm.ok \ -- $(BUILDTESTDIR)/AgentOut.othervm.ok -+ $(BUILDTESTDIR)/AgentOut.othervm.ok \ -+ $(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered.ok - $(DIFF) --strip-trailing-cr --recursive \ - $(BUILDTESTDIR)/AgentOut.agentvm/logs-filtered \ - $(BUILDTESTDIR)/AgentOut.othervm/logs-filtered diff -Nru jtreg8-8.1+1+ds1/debian/patches/codetools-7904157-proposed.patch jtreg8-8.3+1+ds1/debian/patches/codetools-7904157-proposed.patch --- jtreg8-8.1+1+ds1/debian/patches/codetools-7904157-proposed.patch 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/codetools-7904157-proposed.patch 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,18 @@ +Description: Set compile timeout for TimeoutDefaultSecondsWaiter on zero vm + The TimeoutDefaultSecondsWaiter test fails on zero vm because the + compilation times out. Add override for the compilation timeout. +Author: Vladimir Petko +Bug: https://bugs.openjdk.org/browse/CODETOOLS-7904157 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1128797 +Last-Update: 2026-02-23 + +--- a/test/timeoutDefaultSeconds/TimeoutDefaultSecondsWaiter.java ++++ b/test/timeoutDefaultSeconds/TimeoutDefaultSecondsWaiter.java +@@ -30,6 +30,7 @@ + /* + * @test id=one + * @summary Test should be interrupted after 1 second, configured in main action ++ * @compile/timeout=1 TimeoutDefaultSecondsWaiter.java + * @run main/timeout=1 TimeoutDefaultSecondsWaiter + */ + public class TimeoutDefaultSecondsWaiter { diff -Nru jtreg8-8.1+1+ds1/debian/patches/fix_junit5_error_message.patch jtreg8-8.3+1+ds1/debian/patches/fix_junit5_error_message.patch --- jtreg8-8.1+1+ds1/debian/patches/fix_junit5_error_message.patch 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/fix_junit5_error_message.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Description: Update test assertion to use older JUnit5 exception message - Updating JUnit to 5.13.4 requires updating opentest4j-reporting to 0.2.4 - and packaging immutables library (https://github.com/immutables/immutables). - Add a temporary patch that reverts the assertion. - The patch is not needed upstream, as it workarounds an outdated dependency - issue. -Author: Vladimir Petko -Forwarded: not-needed -Last-Update: 2025-08-05 - ---- a/test/junitQueryTest/JUnitQueryTest.gmk -+++ b/test/junitQueryTest/JUnitQueryTest.gmk -@@ -325,7 +325,7 @@ - > $(@:%.ok=%)/jt.log 2>&1 || \ - true "non-zero exit code from jtreg intentionally ignored" - $(GREP) -s 'Could not find method with name \[m14] in class \[Test1]' $(@:%.ok=%)/jt.log -- $(GREP) -s "TEST RESULT: Failed. Execution failed: .* JUnit test failure" $(@:%.ok=%)/jt.log -+ $(GREP) -s "TEST RESULT: Failed. Execution failed: .*JUnitException: .* failed to discover tests" $(@:%.ok=%)/jt.log - echo $@ passed at `date` > $@ - - TESTS.jtreg += $(BUILDTESTDIR)/JUnitQueryTest.invalidMethod.ok diff -Nru jtreg8-8.1+1+ds1/debian/patches/junit5-16-maven-build.patch jtreg8-8.3+1+ds1/debian/patches/junit5-16-maven-build.patch --- jtreg8-8.1+1+ds1/debian/patches/junit5-16-maven-build.patch 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/junit5-16-maven-build.patch 2026-09-30 21:11:41.000000000 +0000 @@ -12,12 +12,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit + junit-bom -+ 5.9.2 ++ 5.14.2 + pom + JUnit 5 (Bill of Materials) + This Bill of Materials POM can be used to ease dependency management when referencing multiple JUnit artifacts using Gradle or Maven. @@ -126,12 +126,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.jupiter + junit-jupiter-api -+ 5.9.2 ++ 5.14.2 + JUnit Jupiter API + Module "junit-jupiter-api" of JUnit 5. + @@ -192,12 +192,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.jupiter + junit-jupiter-engine -+ 5.9.2 ++ 5.14.2 + JUnit Jupiter Engine + Module "junit-jupiter-engine" of JUnit 5. + @@ -205,7 +205,7 @@ + + org.junit.platform + junit-platform-engine -+ 1.9.1 ++ 1.14.2 + + + org.junit.jupiter @@ -242,12 +242,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.jupiter + junit-jupiter-migrationsupport -+ 5.9.2 ++ 5.14.2 + JUnit Jupiter Migration Support + Module "junit-jupiter-migrationsupport" of JUnit 5. + @@ -255,7 +255,7 @@ + + junit + junit -+ 4.x ++ 4.13.2 + + + org.junit.jupiter @@ -273,12 +273,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.jupiter + junit-jupiter-params -+ 5.9.2 ++ 5.14.2 + JUnit Jupiter Params + Module "junit-jupiter-params" of JUnit 5. + @@ -336,12 +336,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.jupiter + junit-jupiter -+ 5.9.2 ++ 5.14.2 + JUnit Jupiter (Aggregator) + Module "junit-jupiter" of JUnit 5. + @@ -374,31 +374,31 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-commons -+ 1.9.1 ++ 1.14.2 + JUnit Platform Commons + Module "junit-platform-commons" of JUnit 5. + + --- /dev/null +++ b/junit5/junit-platform-console-standalone/pom.xml -@@ -0,0 +1,106 @@ +@@ -0,0 +1,111 @@ + + 4.0.0 + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-console-standalone -+ 1.9.1 ++ 1.14.2 + JUnit Platform Console Standalone + Module "junit-platform-console-standalone" of JUnit 5. + @@ -484,6 +484,11 @@ + + + ++ ++ ++ org.junit.platform.console.standalone ++ ++ + + + @@ -502,12 +507,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-console -+ 1.9.1 ++ 1.14.2 + JUnit Platform Console + Module "junit-platform-console" of JUnit 5. + @@ -576,12 +581,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-engine -+ 1.9.1 ++ 1.14.2 + JUnit Platform Engine API + Module "junit-platform-engine" of JUnit 5. + @@ -607,12 +612,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-launcher -+ 1.9.1 ++ 1.14.2 + JUnit Platform Launcher + Module "junit-platform-launcher" of JUnit 5. + @@ -626,19 +631,19 @@ + --- /dev/null +++ b/junit5/junit-platform-reporting/pom.xml -@@ -0,0 +1,60 @@ +@@ -0,0 +1,70 @@ + + 4.0.0 + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-reporting -+ 1.9.1 ++ 1.14.2 + JUnit Platform Reporting + Module "junit-platform-reporting" of JUnit 5. + @@ -651,7 +656,17 @@ + + org.opentest4j.reporting + open-test-reporting-events -+ 0.1.0-M1 ++ debian ++ ++ ++ org.opentest4j.reporting ++ tooling-core ++ debian ++ ++ ++ org.opentest4j.reporting ++ tooling-spi ++ debian + + + @@ -696,12 +711,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-runner -+ 1.9.1 ++ 1.14.2 + JUnit Platform Runner + Module "junit-platform-runner" of JUnit 5. + @@ -738,12 +753,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-suite-api -+ 1.9.1 ++ 1.14.2 + JUnit Platform Suite API + Module "junit-platform-suite-api" of JUnit 5. + @@ -765,12 +780,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-suite-commons -+ 1.9.1 ++ 1.14.2 + JUnit Platform Suite Commons + Module "junit-platform-suite-commons" of JUnit 5. + @@ -802,12 +817,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-suite-engine -+ 1.9.1 ++ 1.14.2 + JUnit Platform Suite Engine + Module "junit-platform-suite-engine" of JUnit 5. + @@ -839,12 +854,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.platform + junit-platform-suite -+ 1.9.1 ++ 1.14.2 + JUnit Platform Suite (Aggregator) + Module "junit-platform-suite" of JUnit 5. + @@ -871,12 +886,12 @@ + + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + ../pom.xml + + org.junit.vintage + junit-vintage-engine -+ 5.9.2 ++ 5.14.2 + JUnit Vintage Engine + Module "junit-vintage-engine" of JUnit 5. + @@ -902,7 +917,7 @@ + 4.0.0 + org.junit + junit-parent -+ 5.9.2 ++ 5.14.2 + pom + JUnit 5 (Parent) + @@ -961,7 +976,7 @@ + + + UTF-8 -+ 1.9.1 ++ 1.14.2 + + + diff -Nru jtreg8-8.1+1+ds1/debian/patches/junit5-17-backward-compatibility.patch jtreg8-8.3+1+ds1/debian/patches/junit5-17-backward-compatibility.patch --- jtreg8-8.1+1+ds1/debian/patches/junit5-17-backward-compatibility.patch 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/junit5-17-backward-compatibility.patch 2026-09-30 21:11:41.000000000 +0000 @@ -3,47 +3,72 @@ Forwarded: not-needed --- a/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java +++ b/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java -@@ -109,7 +109,6 @@ +@@ -113,7 +113,6 @@ * the {@code junit-platform-suite-engine} module; to be removed in JUnit Platform 2.0 */ @API(status = DEPRECATED, since = "1.8") -@Deprecated public class JUnitPlatform extends Runner implements Filterable { - + // @formatter:off --- a/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestPlan.java +++ b/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestPlan.java -@@ -96,6 +96,33 @@ +@@ -25,6 +25,7 @@ + import java.util.Set; + import java.util.concurrent.ConcurrentHashMap; + import java.util.function.Predicate; ++import java.nio.file.Paths; + + import org.apiguardian.api.API; + import org.junit.platform.commons.JUnitException; +@@ -96,6 +97,50 @@ return testPlan; } - + + @API(status = INTERNAL, since = "1.0") -+ public static TestPlan from(Collection engineDescriptors) { -+ return from(engineDescriptors, new ConfigurationParameters() { ++ public static TestPlan from(Collection engineDescriptors, ConfigurationParameters parameters) { ++ return from(true, engineDescriptors, parameters, new OutputDirectoryCreator() { + @Override -+ public Optional get(String key) { -+ return Optional.empty(); ++ public java.nio.file.Path createOutputDirectory(org.junit.platform.engine.TestDescriptor testDescriptor) throws java.io.IOException { ++ return Paths.get("."); + } + + @Override -+ public Optional getBoolean(String key) { -+ return Optional.empty(); ++ public java.nio.file.Path getRootDirectory() { ++ return Paths.get("."); + } ++ }); ++ } + -+ @Override -+ @SuppressWarnings("deprecation") -+ public int size() { -+ return 0; -+ } + -+ @Override -+ public Set keySet() { -+ return java.util.Collections.emptySet(); -+ } ++ @API(status = INTERNAL, since = "1.0") ++ public static TestPlan from(Collection engineDescriptors) { + -+ }); ++ return from(engineDescriptors, new ConfigurationParameters() { ++ @Override ++ public Optional get(String key) { ++ return Optional.empty(); ++ } ++ ++ @Override ++ public Optional getBoolean(String key) { ++ return Optional.empty(); ++ } ++ ++ @Override ++ @SuppressWarnings("deprecation") ++ public int size() { ++ return 0; ++ } ++ ++ @Override ++ public Set keySet() { ++ return java.util.Collections.emptySet(); ++ } ++ ++ }); + } + @API(status = INTERNAL, since = "1.4") - protected TestPlan(boolean containsTests, ConfigurationParameters configurationParameters) { - this.containsTests = containsTests; + protected TestPlan(boolean containsTests, ConfigurationParameters configurationParameters, + OutputDirectoryCreator outputDirectoryCreator) { diff -Nru jtreg8-8.1+1+ds1/debian/patches/opentest4j-reporting-01-gradle-compatibility.patch jtreg8-8.3+1+ds1/debian/patches/opentest4j-reporting-01-gradle-compatibility.patch --- jtreg8-8.1+1+ds1/debian/patches/opentest4j-reporting-01-gradle-compatibility.patch 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/opentest4j-reporting-01-gradle-compatibility.patch 2026-09-30 21:11:41.000000000 +0000 @@ -3,39 +3,23 @@ Forwarded: not-needed --- /dev/null +++ b/opentest4j-reporting/build.gradle -@@ -0,0 +1,10 @@ -+plugins { -+ id 'java' -+} -+ +@@ -0,0 +1,7 @@ +allprojects { + apply plugin: 'java' ++ tasks.withType(JavaCompile) { ++ sourceCompatibility = '17' ++ targetCompatibility = '17' ++ } +} -+ -+sourceCompatibility = "1.8" -+targetCompatibility = "1.8" --- /dev/null +++ b/opentest4j-reporting/events/build.gradle -@@ -0,0 +1,16 @@ -+/* -+plugins { -+ `java-conventions` -+} -+*/ -+ -+sourceCompatibility = "1.8" -+targetCompatibility = "1.8" -+ +@@ -0,0 +1,3 @@ +dependencies { + compile(project(":schema")) -+// testImplementation(libs.archunit) -+// testImplementation(libs.assertj.core) -+// testImplementation(libs.junit.jupiter) -+// testImplementation(libs.xmlunit.assertj) +} --- /dev/null +++ b/opentest4j-reporting/settings.gradle -@@ -0,0 +1,17 @@ +@@ -0,0 +1,18 @@ +rootProject.name = "open-test-reporting" +/* +dependencyResolutionManagement { @@ -49,7 +33,30 @@ +//include("documentation") +include("events") +include("schema") -+//include("tooling") ++include("tooling-spi") ++include("tooling-core") + +//enableFeaturePreview("VERSION_CATALOGS") +//enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +--- /dev/null ++++ b/opentest4j-reporting/schema/build.gradle +@@ -0,0 +1,3 @@ ++dependencies { ++ compile("org.apiguardian:apiguardian-api:debian") ++} +--- /dev/null ++++ b/opentest4j-reporting/tooling-core/build.gradle +@@ -0,0 +1,7 @@ ++dependencies { ++ compile("org.apiguardian:apiguardian-api:debian") ++ compile("com.google.code.gson:gson:debian") ++ compile(project(":schema")) ++ compile(project(":events")) ++ compile(project(":tooling-spi")) ++} +--- /dev/null ++++ b/opentest4j-reporting/tooling-spi/build.gradle +@@ -0,0 +1,3 @@ ++dependencies { ++ compile("org.apiguardian:apiguardian-api:debian") ++} diff -Nru jtreg8-8.1+1+ds1/debian/patches/opentest4j-reporting-02-disable-immutables.patch jtreg8-8.3+1+ds1/debian/patches/opentest4j-reporting-02-disable-immutables.patch --- jtreg8-8.1+1+ds1/debian/patches/opentest4j-reporting-02-disable-immutables.patch 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/opentest4j-reporting-02-disable-immutables.patch 2026-09-30 21:11:41.000000000 +0000 @@ -0,0 +1,158 @@ +Description: Disable immutables annotations + Immutables https://github.com/immutables/immutables is not packaged yet. + Disable immutables annotations. +Author: Vladimir Petko +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1108557 +Forwarded: not-needed +Last-Update: 2026-01-29 + +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Image.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Image.java +@@ -17,7 +17,6 @@ + package org.opentest4j.reporting.tooling.spi.htmlreport; + + import org.apiguardian.api.API; +-import org.immutables.value.Value.Immutable; + + import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +@@ -26,7 +25,6 @@ + * + * @since 0.2.0 + */ +-@Immutable + @API(status = EXPERIMENTAL, since = "0.2.0") + public interface Image extends Block { + +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/KeyValuePairs.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/KeyValuePairs.java +@@ -17,7 +17,6 @@ + package org.opentest4j.reporting.tooling.spi.htmlreport; + + import org.apiguardian.api.API; +-import org.immutables.value.Value.Immutable; + + import java.util.Map; + +@@ -28,7 +27,6 @@ + * + * @since 0.2.0 + */ +-@Immutable + @API(status = EXPERIMENTAL, since = "0.2.0") + public interface KeyValuePairs extends Block> { + +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Labels.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Labels.java +@@ -17,7 +17,6 @@ + package org.opentest4j.reporting.tooling.spi.htmlreport; + + import org.apiguardian.api.API; +-import org.immutables.value.Value.Immutable; + + import java.util.List; + +@@ -28,7 +27,6 @@ + * + * @since 0.2.0 + */ +-@Immutable + @API(status = EXPERIMENTAL, since = "0.2.0") + public interface Labels extends Block> { + +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Paragraph.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Paragraph.java +@@ -17,7 +17,6 @@ + package org.opentest4j.reporting.tooling.spi.htmlreport; + + import org.apiguardian.api.API; +-import org.immutables.value.Value.Immutable; + + import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +@@ -26,7 +25,6 @@ + * + * @since 0.2.0 + */ +-@Immutable + @API(status = EXPERIMENTAL, since = "0.2.0") + public interface Paragraph extends Block { + +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/PreFormattedOutput.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/PreFormattedOutput.java +@@ -16,9 +16,8 @@ + + package org.opentest4j.reporting.tooling.spi.htmlreport; + +-import org.apiguardian.api.API; +-import org.immutables.value.Value.Immutable; + ++import org.apiguardian.api.API; + import static org.apiguardian.api.API.Status.EXPERIMENTAL; + + /** +@@ -26,7 +25,6 @@ + * + * @since 0.2.0 + */ +-@Immutable + @API(status = EXPERIMENTAL, since = "0.2.0") + public interface PreFormattedOutput extends Block { + +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Section.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Section.java +@@ -17,8 +17,6 @@ + package org.opentest4j.reporting.tooling.spi.htmlreport; + + import org.apiguardian.api.API; +-import org.immutables.value.Value.Default; +-import org.immutables.value.Value.Immutable; + + import java.util.List; + import java.util.Optional; +@@ -30,7 +28,6 @@ + * + * @since 0.2.0 + */ +-@Immutable + @API(status = EXPERIMENTAL, since = "0.2.0") + public interface Section { + +@@ -72,7 +69,6 @@ + *

This is used to sort the all {@linkplain Contributor contributed} + * sections in the HTML report. + */ +- @Default + default int getOrder() { + return 0; + } +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Subsections.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Subsections.java +@@ -17,7 +17,6 @@ + package org.opentest4j.reporting.tooling.spi.htmlreport; + + import org.apiguardian.api.API; +-import org.immutables.value.Value.Immutable; + + import java.util.List; + +@@ -28,7 +27,6 @@ + * + * @since 0.2.0 + */ +-@Immutable + @API(status = EXPERIMENTAL, since = "0.2.0") + public interface Subsections extends Block> { + +--- a/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/package-info.java ++++ b/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/package-info.java +@@ -4,9 +4,4 @@ + * @see org.opentest4j.reporting.tooling.spi.htmlreport.Contributor + */ + +-@Style(visibility = ImplementationVisibility.PACKAGE, jdkOnly = true, overshadowImplementation = true, from = "", depluralize = true, allowedClasspathAnnotations = { +- Override.class }) + package org.opentest4j.reporting.tooling.spi.htmlreport; +- +-import org.immutables.value.Value.Style; +-import org.immutables.value.Value.Style.ImplementationVisibility; diff -Nru jtreg8-8.1+1+ds1/debian/patches/series jtreg8-8.3+1+ds1/debian/patches/series --- jtreg8-8.1+1+ds1/debian/patches/series 2025-10-28 04:51:40.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/patches/series 2026-09-30 21:11:41.000000000 +0000 @@ -8,6 +8,7 @@ opentest4j-04-reproducible-builds-timestamp.patch opentest4j-05-build-on-java-17.patch opentest4j-reporting-01-gradle-compatibility.patch +opentest4j-reporting-02-disable-immutables.patch hawt-jni-02-commons-lang-dependency.patch jline3-01-ignore-warnings.patch jline3-02-ignore-remote-modules.patch @@ -26,9 +27,6 @@ testng-build-with-gradle.patch jtdiff-version.patch java21-codetools-7903646.patch -fix_junit5_error_message.patch codetools-7904101-proposed.patch codetools-7904104-proposed.patch -codetools-7904105-proposed.patch -codetools-7904106-proposed.patch -codetools-7904107-proposed.patch +codetools-7904157-proposed.patch diff -Nru jtreg8-8.1+1+ds1/debian/rules jtreg8-8.3+1+ds1/debian/rules --- jtreg8-8.1+1+ds1/debian/rules 2026-01-23 00:06:17.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/rules 2026-09-30 21:11:41.000000000 +0000 @@ -26,7 +26,7 @@ head -n 1 | \ sed -e 's/^[^0-9]*\(1\.\)*\([1-9][0-9]*\).*/\2/' ) -components:=apiguardian hawt-jni jansi1 jline3 picocli univocity-parsers libhamcrest-java junit4 opentest4j opentest4j-reporting junit5 testng +components:=asmtools apiguardian hawt-jni jansi1 jline3 picocli univocity-parsers libhamcrest-java junit4 opentest4j opentest4j-reporting junit5 testng %: dh $@ @@ -42,7 +42,7 @@ mkdir -p build/classes/com/sun/javatest/regtest/tool mkdir -p build/test (cd make && make \ - ASMTOOLS_JAR=/usr/share/java/asmtools.jar \ + ASMTOOLS_JAR=../asmtools/build/asmtools/binaries/lib/asmtools.jar \ BUILD_DIR=../build \ JUNIT_JARS=../junit5/debian/jtreg8/usr/share/java/junit-platform-console-standalone.jar \ TESTNG_JARS="../testng/debian/jtreg8/usr/share/java/testng.jar /usr/share/java/guice.jar /usr/share/java/jcommander.jar /usr/share/java/slf4j-simple.jar /usr/share/java/slf4j-api.jar" \ diff -Nru jtreg8-8.1+1+ds1/debian/watch jtreg8-8.3+1+ds1/debian/watch --- jtreg8-8.1+1+ds1/debian/watch 2025-10-22 19:48:08.000000000 +0000 +++ jtreg8-8.3+1+ds1/debian/watch 2026-09-30 21:11:41.000000000 +0000 @@ -12,13 +12,13 @@ https://github.com/junit-team/junit4/tags .*/r?(4.13.2)\.tar\.gz 4.13.2 opts="compression=gzip,component=junit5,repack" \ -https://github.com/junit-team/junit5/tags?after=r5.12.2 .*/r(5.11.4)\.tar\.gz 5.11.4 +https://github.com/junit-team/junit5/tags .*/r(5.14.2)\.tar\.gz 5.14.2 opts="compression=gzip,component=libhamcrest-java,repack" \ https://github.com/hamcrest/JavaHamcrest/tags .*/(?:hamcrest-java-|v)(2.2)\.tar\.gz 2.2 opts="compression=gzip,component=opentest4j-reporting,repack" \ -https://github.com/ota4j-team/open-test-reporting/tags .*/r(0.1.0-M2)\.tar\.gz 0.1.0-M2 +https://github.com/ota4j-team/open-test-reporting/tags .*/r(0.2.5)\.tar\.gz 0.2.5 opts="compression=gzip,component=picocli,repack" \ https://github.com/remkop/picocli/tags (?:.*?/)?v?(4.6.2)\.tar\.gz 4.6.2 @@ -37,3 +37,6 @@ opts="compression=gzip,component=apiguardian,repack" \ https://github.com/apiguardian-team/apiguardian/tags .*/r(1.1.2)\.tar\.gz 1.1.2 + +opts="compression=gzip,component=asmtools,repack" \ +https://github.com/openjdk/asmtools/tags .*/(9.1-b01)\.tar\.gz 9.1-b01 diff -Nru jtreg8-8.1+1+ds1/doc/building.md jtreg8-8.3+1+ds1/doc/building.md --- jtreg8-8.1+1+ds1/doc/building.md 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/doc/building.md 2026-06-21 20:26:05.000000000 +0000 @@ -111,7 +111,13 @@ ``` Some tests depend on specific versions of JDK being available, specified -by the following variables: `JDK8HOME`, `JDK9HOME`, `JDK14HOME`, `JDK18HOME`. +by the following variables: +- `JDK8HOME` +- `JDK9HOME` +- `JDK14HOME` +- `JDK18HOME` +- `JDK21HOME` +- `JDK25HOME` A test that requires any of these version of JDK will be skipped if the variable is not set. diff -Nru jtreg8-8.1+1+ds1/junit5/.github/FUNDING.yml jtreg8-8.3+1+ds1/junit5/.github/FUNDING.yml --- jtreg8-8.1+1+ds1/junit5/.github/FUNDING.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/FUNDING.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -custom: https://junit.org/sponsoring diff -Nru jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/bug_report.md jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/bug_report.md --- jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/bug_report.md 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/bug_report.md 2026-06-21 20:26:05.000000000 +0000 @@ -1,10 +1,11 @@ --- -name: Bug report +name: Report a bug or regression about: Create a report to help us improve - +type: Bug +labels: ["type: bug"] --- - + ## Steps to reproduce diff -Nru jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/config.yml jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/config.yml --- jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/config.yml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/config.yml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Ask a question + url: https://github.com/junit-team/junit-framework/discussions/categories/q-a + about: Please ask and answer questions here + - name: Ask a question (Stack Overflow) + url: https://stackoverflow.com/questions/tagged/junit5 + about: Alternatively, ask questions here diff -Nru jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/feature_request.md jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/feature_request.md --- jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/feature_request.md 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/feature_request.md 2026-06-21 20:26:05.000000000 +0000 @@ -1,7 +1,8 @@ --- -name: Feature request +name: Request a feature or enhancement about: Suggest an idea for this project - +type: Feature +labels: ["type: new feature"] --- diff -Nru jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/question.md jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/question.md --- jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/question.md 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/question.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ ---- -name: Question -about: Please first ask on Gitter or StackOverflow before creating an issue ---- - -This issue tracker is not the place for questions. -If you want to ask how to do something, or to understand why -something isn't working the way you expect it to, please use Gitter [1] or Stack Overflow [2]. - -[1] https://gitter.im/junit-team/junit5 -[2] https://stackoverflow.com/questions/tagged/junit5 diff -Nru jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/task.md jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/task.md --- jtreg8-8.1+1+ds1/junit5/.github/ISSUE_TEMPLATE/task.md 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/ISSUE_TEMPLATE/task.md 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,12 @@ +--- +name: Create a task +about: Create a task for a specific piece of work +type: Task +labels: ["type: task"] +--- + + + +## Deliverables + +- [ ] ... diff -Nru jtreg8-8.1+1+ds1/junit5/.github/PULL_REQUEST_TEMPLATE.md jtreg8-8.3+1+ds1/junit5/.github/PULL_REQUEST_TEMPLATE.md --- jtreg8-8.1+1+ds1/junit5/.github/PULL_REQUEST_TEMPLATE.md 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/PULL_REQUEST_TEMPLATE.md 2026-06-21 20:26:05.000000000 +0000 @@ -4,15 +4,15 @@ --- -I hereby agree to the terms of the [JUnit Contributor License Agreement](https://github.com/junit-team/junit5/blob/002a0052926ddee57cf90580fa49bc37e5a72427/CONTRIBUTING.md#junit-contributor-license-agreement). +I hereby agree to the terms of the [JUnit Contributor License Agreement](https://github.com/junit-team/junit-framework/blob/002a0052926ddee57cf90580fa49bc37e5a72427/CONTRIBUTING.md#junit-contributor-license-agreement). --- ### Definition of Done - [ ] There are no TODOs left in the code -- [ ] Method [preconditions](https://junit.org/junit5/docs/snapshot/api/org.junit.platform.commons/org/junit/platform/commons/util/Preconditions.html) are checked and documented in the method's Javadoc -- [ ] [Coding conventions](https://github.com/junit-team/junit5/blob/HEAD/CONTRIBUTING.md#coding-conventions) (e.g. for logging) have been followed -- [ ] Change is covered by [automated tests](https://github.com/junit-team/junit5/blob/HEAD/CONTRIBUTING.md#tests) including corner cases, errors, and exception handling -- [ ] Public API has [Javadoc](https://github.com/junit-team/junit5/blob/HEAD/CONTRIBUTING.md#javadoc) and [`@API` annotations](https://apiguardian-team.github.io/apiguardian/docs/current/api/org/apiguardian/api/API.html) -- [ ] Change is documented in the [User Guide](https://junit.org/junit5/docs/snapshot/user-guide/) and [Release Notes](https://junit.org/junit5/docs/snapshot/user-guide/#release-notes) +- [ ] Method [preconditions](https://docs.junit.org/snapshot/api/org.junit.platform.commons/org/junit/platform/commons/util/Preconditions.html) are checked and documented in the method's Javadoc +- [ ] [Coding conventions](https://github.com/junit-team/junit-framework/blob/HEAD/CONTRIBUTING.md#coding-conventions) (e.g. for logging) have been followed +- [ ] Change is covered by [automated tests](https://github.com/junit-team/junit-framework/blob/HEAD/CONTRIBUTING.md#tests) including corner cases, errors, and exception handling +- [ ] Public API has [Javadoc](https://github.com/junit-team/junit-framework/blob/HEAD/CONTRIBUTING.md#javadoc) and [`@API` annotations](https://apiguardian-team.github.io/apiguardian/docs/current/api/org/apiguardian/api/API.html) +- [ ] Change is documented in the [User Guide](https://docs.junit.org/snapshot/user-guide/) and [Release Notes](https://docs.junit.org/snapshot/user-guide/#release-notes) diff -Nru jtreg8-8.1+1+ds1/junit5/.github/actions/main-build/action.yml jtreg8-8.3+1+ds1/junit5/.github/actions/main-build/action.yml --- jtreg8-8.1+1+ds1/junit5/.github/actions/main-build/action.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/actions/main-build/action.yml 2026-06-21 20:26:05.000000000 +0000 @@ -4,7 +4,7 @@ arguments: required: true description: Gradle arguments - default: :platform-tooling-support-tests:test build --configuration-cache + default: :platform-tooling-support-tests:test build --no-configuration-cache # Disable configuration cache due to https://github.com/diffplug/spotless/issues/2318 encryptionKey: required: true description: Gradle cache encryption key @@ -16,3 +16,8 @@ with: arguments: ${{ inputs.arguments }} encryptionKey: ${{ inputs.encryptionKey }} + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + if: ${{ always() }} + with: + name: Open Test Reports (${{ github.job }}) + path: '**/build/reports/open-test-report.html' diff -Nru jtreg8-8.1+1+ds1/junit5/.github/actions/maven-central-user-token/action.yml jtreg8-8.3+1+ds1/junit5/.github/actions/maven-central-user-token/action.yml --- jtreg8-8.1+1+ds1/junit5/.github/actions/maven-central-user-token/action.yml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/actions/maven-central-user-token/action.yml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +name: Prepare Maven Central user token +description: Compute the Maven Central user token from username and password +inputs: + username: + required: true + description: Maven Central username + password: + required: true + description: Maven Central password +runs: + using: "composite" + steps: + - shell: bash + run: | + USER_TOKEN=$(printf "${{ inputs.username }}:${{ inputs.password }}" | base64) + echo "::add-mask::$USER_TOKEN" + echo "MAVEN_CENTRAL_USER_TOKEN=$USER_TOKEN" >> $GITHUB_ENV diff -Nru jtreg8-8.1+1+ds1/junit5/.github/actions/run-gradle/action.yml jtreg8-8.3+1+ds1/junit5/.github/actions/run-gradle/action.yml --- jtreg8-8.1+1+ds1/junit5/.github/actions/run-gradle/action.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/actions/run-gradle/action.yml 2026-06-21 20:26:05.000000000 +0000 @@ -11,13 +11,13 @@ runs: using: "composite" steps: - - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 id: setup-gradle-jdk with: distribution: temurin java-version: 21 check-latest: true - - uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808 # v4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 with: cache-encryption-key: ${{ inputs.encryptionKey }} - shell: bash @@ -26,7 +26,8 @@ run: | ./gradlew \ -Porg.gradle.java.installations.auto-download=false \ - -Pjunit.develocity.predictiveTestSelection.enabled=${{ github.event_name == 'pull_request' }} \ + -Pjunit.develocity.predictiveTestSelection.enabled=true \ + -Pjunit.develocity.predictiveTestSelection.selectRemainingTests=${{ github.event_name != 'pull_request' }} \ "-Dscan.value.GitHub job=${{ github.job }}" \ javaToolchains \ ${{ inputs.arguments }} diff -Nru jtreg8-8.1+1+ds1/junit5/.github/actions/setup-test-jdk/action.yml jtreg8-8.3+1+ds1/junit5/.github/actions/setup-test-jdk/action.yml --- jtreg8-8.1+1+ds1/junit5/.github/actions/setup-test-jdk/action.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/actions/setup-test-jdk/action.yml 2026-06-21 20:26:05.000000000 +0000 @@ -8,7 +8,7 @@ runs: using: "composite" steps: - - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: ${{ inputs.distribution }} java-version: 8 diff -Nru jtreg8-8.1+1+ds1/junit5/.github/renovate.json5 jtreg8-8.3+1+ds1/junit5/.github/renovate.json5 --- jtreg8-8.1+1+ds1/junit5/.github/renovate.json5 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/renovate.json5 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +{ + $schema: 'https://docs.renovatebot.com/renovate-schema.json', + extends: [ + 'github>junit-team/renovate-config', + ], + baseBranches: ["main", "/^develop\\/.*/"], + packageRules: [ + { + matchCurrentValue: '/^2\\./', + allowedVersions: '(,3.0)', + matchPackageNames: [ + 'org.codehaus.groovy:{/,}**', + ], + }, + { + matchCurrentValue: '/^4\\./', + allowedVersions: '(,5.0)', + matchPackageNames: [ + 'org.apache.groovy:{/,}**', + ], + }, + { + matchCurrentValue: '/^1\\./', + allowedVersions: '/^1\\..*-groovy-2\\.*/', + matchPackageNames: [ + 'org.spockframework:{/,}**', + ], + }, + { + allowedVersions: '!/-SNAPSHOT$/', + matchPackageNames: [ + 'org.opentest4j.reporting:{/,}**', + ], + }, + ], +} diff -Nru jtreg8-8.1+1+ds1/junit5/.github/scripts/checkBuildReproducibility.sh jtreg8-8.3+1+ds1/junit5/.github/scripts/checkBuildReproducibility.sh --- jtreg8-8.1+1+ds1/junit5/.github/scripts/checkBuildReproducibility.sh 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/scripts/checkBuildReproducibility.sh 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ +#!/bin/bash -e + +rm -f checksums-1.txt checksums-2.txt + +SOURCE_DATE_EPOCH=$(date +%s) +export SOURCE_DATE_EPOCH + +function calculate_checksums() { + OUTPUT=$1 + + ./gradlew \ + --configuration-cache \ + --no-build-cache \ + -Porg.gradle.java.installations.auto-download=false \ + -Dscan.tag.Reproducibility \ + clean \ + assemble + + find . -name '*.jar' \ + | grep '/build/libs/' \ + | grep --invert-match 'javadoc' \ + | sort \ + | xargs sha512sum > "${OUTPUT}" +} + + +calculate_checksums checksums-1.txt +calculate_checksums checksums-2.txt + +diff checksums-1.txt checksums-2.txt diff -Nru jtreg8-8.1+1+ds1/junit5/.github/scripts/waitForUrl.sh jtreg8-8.3+1+ds1/junit5/.github/scripts/waitForUrl.sh --- jtreg8-8.1+1+ds1/junit5/.github/scripts/waitForUrl.sh 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/scripts/waitForUrl.sh 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +URL=$1 +printf 'Waiting for %s' "$URL" +until curl --output /dev/null --silent --location --head --fail "$URL"; do + printf '.' + sleep 5 +done +echo ' OK' diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/close-inactive-issues.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/close-inactive-issues.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/close-inactive-issues.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/close-inactive-issues.yml 2026-06-21 20:26:05.000000000 +0000 @@ -3,6 +3,7 @@ schedule: - cron: "30 1 * * *" workflow_dispatch: +permissions: {} jobs: close-issues: runs-on: ubuntu-latest @@ -10,7 +11,7 @@ issues: write pull-requests: write steps: - - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9 + - uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1 with: only-labels: "status: waiting-for-feedback" days-before-stale: 14 diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/codeql-analysis.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/codeql-analysis.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/codeql-analysis.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/codeql-analysis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: - - main - - 'releases/**' - pull_request: - # The branches below must be a subset of the branches above - branches: - - main - - 'releases/**' - schedule: - - cron: '0 19 * * 3' - -env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - security-events: write - strategy: - fail-fast: false - matrix: - language: - - java - - javascript - steps: - - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - - name: Initialize CodeQL - uses: github/codeql-action/init@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3 - with: - languages: ${{ matrix.language }} - tools: latest - - name: Build - uses: ./.github/actions/run-gradle - with: - encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - arguments: | - --no-build-cache \ - -Dscan.tag.CodeQL \ - allMainClasses - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3 diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/codeql.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/codeql.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/codeql.yml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/codeql.yml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,56 @@ +name: "CodeQL" + +on: + push: + branches: + - main + - 'releases/**' + pull_request: + # The branches below must be a subset of the branches above + branches: + - main + - 'releases/**' + schedule: + - cron: '0 19 * * 3' + +permissions: {} + +env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + permissions: + security-events: write + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: java-kotlin + build-mode: manual + steps: + - name: Check out repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Initialize CodeQL + uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + tools: linked + - name: Build + if: matrix.build-mode == 'manual' + uses: ./.github/actions/run-gradle + with: + encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + arguments: | + --no-build-cache \ + -Dscan.tag.CodeQL \ + allMainClasses + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + with: + category: "/language:${{matrix.language}}" diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/combine-prs.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/combine-prs.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/combine-prs.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/combine-prs.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -name: Combine PRs - -on: - schedule: - - cron: '0 0 * * *' # Every day at 00:00 UTC - workflow_dispatch: - -jobs: - combine-prs: - if: github.repository == 'junit-team/junit5' - runs-on: ubuntu-latest - steps: - - name: combine-prs - uses: github/combine-prs@20d70f9d80eeb5958667d0602da433bd04ca6713 # v5.1.0 - with: - github_token: ${{ secrets.GH_TOKEN }} diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/cross-version.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/cross-version.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/cross-version.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/cross-version.yml 2026-06-21 20:26:05.000000000 +0000 @@ -9,7 +9,9 @@ - 'releases/**' pull_request: branches: - - '*' + - '**' + +permissions: {} env: DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} @@ -20,36 +22,31 @@ fail-fast: false matrix: jdk: - - version: 22 - type: ga - - version: 23 - type: ga - - version: 24 - type: ea - version: 24 - type: ea - release: leyden + type: ga - version: 25 type: ea + - version: 26 + type: ea name: "OpenJDK ${{ matrix.jdk.version }} (${{ matrix.jdk.release || matrix.jdk.type }})" runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Set up Test JDK uses: ./.github/actions/setup-test-jdk - name: "Set up JDK ${{ matrix.jdk.version }} (${{ matrix.jdk.release || 'ea' }})" if: matrix.jdk.type == 'ea' - uses: oracle-actions/setup-java@2e744f723b003fdd759727d0ff654c8717024845 # v1.4.0 + uses: oracle-actions/setup-java@fff43251af9936a0e6a4d5d0946e14f1680e9b6b # v1.5.0 with: website: jdk.java.net release: ${{ matrix.jdk.release || matrix.jdk.version }} version: latest - name: "Set up JDK ${{ matrix.jdk.version }} (${{ matrix.jdk.distribution || 'temurin' }})" if: matrix.jdk.type == 'ga' - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4 + uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: ${{ matrix.jdk.distribution || 'temurin' }} java-version: ${{ matrix.jdk.version }} @@ -62,10 +59,16 @@ with: encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | + -Ptesting.enableJaCoCo=false \ -PjavaToolchain.version=${{ matrix.jdk.version }} \ -Dscan.tag.JDK_${{ matrix.jdk.version }} \ build \ - --configuration-cache + --no-configuration-cache #Disable configuration cache due to https://github.com/diffplug/spotless/issues/2318 + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + if: ${{ always() }} + with: + name: Open Test Reports (${{ github.job }} ${{ matrix.jdk.version }} (${{ matrix.jdk.release || matrix.jdk.type }})) + path: '**/build/reports/open-test-report.html' openj9: strategy: fail-fast: false @@ -75,7 +78,7 @@ runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Set up Test JDK @@ -83,7 +86,7 @@ with: distribution: semeru - name: 'Set up JDK ${{ matrix.jdk }}' - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4 + uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: semeru java-version: ${{ matrix.jdk }} @@ -96,9 +99,15 @@ with: encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | + -Ptesting.enableJaCoCo=false \ -PjavaToolchain.version=${{ matrix.jdk }} \ -PjavaToolchain.implementation=j9 \ -Dscan.tag.JDK_${{ matrix.jdk }} \ -Dscan.tag.OpenJ9 \ build \ - --configuration-cache + --no-configuration-cache # Disable configuration cache due to https://github.com/diffplug/spotless/issues/2318 + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + if: ${{ always() }} + with: + name: Open Test Reports (${{ github.job }}) + path: '**/build/reports/open-test-report.html' diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/gradle-dependency-submission.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/gradle-dependency-submission.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/gradle-dependency-submission.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/gradle-dependency-submission.yml 2026-06-21 20:26:05.000000000 +0000 @@ -5,23 +5,27 @@ branches: - main -permissions: - contents: write +permissions: {} + +env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} jobs: dependency-submission: - if: github.repository == 'junit-team/junit5' + if: github.repository == 'junit-team/junit-framework' runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Setup Java - uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4 + uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: temurin java-version: 21 check-latest: true - name: Generate and submit dependency graph - uses: gradle/actions/dependency-submission@16bf8bc8fe830fa669c3c9f914d3eb147c629707 # v4 + uses: gradle/actions/dependency-submission@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/issue-labels.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/issue-labels.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/issue-labels.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/issue-labels.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -name: Label new issues -on: - issues: - types: - - opened -jobs: - label_issues: - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 - with: - script: | - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ["status: new"] - }) diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/label-opened-issues.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/label-opened-issues.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/label-opened-issues.yml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/label-opened-issues.yml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ +name: Add label to opened issues +on: + issues: + types: + - opened +permissions: {} +jobs: + label_issues: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const issue = await github.rest.issues.get({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }); + const originalLabels = issue.data.labels.map(l => l.name); + const statusLabels = originalLabels.filter(l => l.startsWith("status: ")); + if (statusLabels.length === 0 && !originalLabels.includes("up-for-grabs")) { + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ["status: new"] + }) + } diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/main.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/main.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/main.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/main.yml 2026-06-21 20:26:05.000000000 +0000 @@ -5,9 +5,13 @@ branches: - main - 'releases/**' + tags-ignore: + - '**' pull_request: branches: - - '*' + - '**' + +permissions: {} env: DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} @@ -17,28 +21,26 @@ runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Install GraalVM - uses: graalvm/setup-graalvm@22cc13fe88ef133134b3798e128fb208df55e1f5 # v1 + uses: graalvm/setup-graalvm@790e28947b79a9c09c3391c0f18bf8d0f102ed69 # v1.4.4 with: distribution: graalvm-community version: 'latest' java-version: '21' - github-token: ${{ secrets.GITHUB_TOKEN }} - name: Build uses: ./.github/actions/main-build with: encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | - -Ptesting.enableJaCoCo \ :platform-tooling-support-tests:test \ build \ jacocoRootReport \ - --configuration-cache + --no-configuration-cache # Disable configuration cache due to https://github.com/diffplug/spotless/issues/2318 - name: Upload to Codecov.io - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -46,7 +48,7 @@ runs-on: windows-latest steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Build @@ -58,7 +60,7 @@ runs-on: macos-latest steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Build @@ -68,42 +70,42 @@ publish_artifacts: name: Publish Snapshot Artifacts - needs: Linux + needs: macOS runs-on: ubuntu-latest permissions: attestations: write # required for build provenance attestation id-token: write # required for build provenance attestation - if: github.event_name == 'push' && github.repository == 'junit-team/junit5' && (startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main') + if: github.event_name == 'push' && github.repository == 'junit-team/junit-framework' && (startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main') steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Publish uses: ./.github/actions/run-gradle env: - ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} - ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} with: encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | publish -x check \ prepareGitHubAttestation - name: Generate build provenance attestations - uses: actions/attest-build-provenance@210c1913531870065f03ce1f9440dd87bc0938cd # v1.4.0 + uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3.1.0 with: subject-path: documentation/build/attestation/*.jar documentation: name: Build Documentation concurrency: - group: github-pages + group: github-pages-${{ github.ref }} cancel-in-progress: true - needs: Linux + needs: macOS runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Install Graphviz @@ -115,21 +117,5 @@ with: encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | - prepareDocsForUploadToGhPages \ - -Dscan.tag.Documentation - - name: Configure Git - shell: bash - run: | - git config --global user.name "JUnit Team" - git config --global user.email "team@junit.org" - - name: Upload Documentation - if: github.event_name == 'push' && github.repository == 'junit-team/junit5' && github.ref == 'refs/heads/main' - uses: ./.github/actions/run-gradle - with: - encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - arguments: | - gitPublishPush \ + antora \ -Dscan.tag.Documentation - env: - GIT_USERNAME: git - GIT_PASSWORD: ${{ secrets.GH_TOKEN }} diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/ossf-scorecard.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/ossf-scorecard.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/ossf-scorecard.yml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/ossf-scorecard.yml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,62 @@ +name: OpenSSF Scorecard supply-chain security analysis + +on: + branch_protection_rule: + schedule: + - cron: '31 20 * * 6' + push: + branches: [ "main" ] + +permissions: {} + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard (optional). + # Commenting out will disable upload of results to your repo's Code Scanning dashboard + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + with: + sarif_file: results.sarif diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/release.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/release.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/release.yml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/release.yml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,267 @@ +name: Release + +on: + workflow_dispatch: + inputs: + releaseVersion: + description: Version to be released (e.g. "5.12.0-M1") + required: true + deploymentId: + description: ID of the Maven Central Publish Portal deployment + required: true + dryRun: + type: boolean + description: Enable dry-run mode + required: false + default: false + +permissions: {} + +env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + STAGING_REPO_URL: https://central.sonatype.com/api/v1/publisher/deployment/${{ inputs.deploymentId }}/download + RELEASE_TAG: r${{ inputs.releaseVersion }} + +jobs: + + verify_reproducibility: + name: Verify reproducibility + runs-on: ubuntu-latest + permissions: + attestations: write # required for build provenance attestation + id-token: write # required for build provenance attestation + steps: + - name: Check out repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + fetch-depth: 1 + ref: "refs/tags/${{ env.RELEASE_TAG }}" + - name: Prepare Maven Central user token + uses: ./.github/actions/maven-central-user-token + with: + username: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + password: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + - name: Download reference JAR from staging repository + id: referenceJar + run: | + curl --silent --fail --location --output /tmp/reference.jar \ + --header "Authorization: Bearer $MAVEN_CENTRAL_USER_TOKEN" \ + "${{ env.STAGING_REPO_URL }}/org/junit/jupiter/junit-jupiter-api/${{ inputs.releaseVersion }}/junit-jupiter-api-${{ inputs.releaseVersion }}.jar" + sudo apt-get update && sudo apt-get install --yes jc + unzip -c /tmp/reference.jar META-INF/MANIFEST.MF | jc --jar-manifest | jq '.[0]' > /tmp/manifest.json + echo "createdBy=$(jq --raw-output .Created_By /tmp/manifest.json)" >> "$GITHUB_OUTPUT" + echo "buildTimestamp=$(jq --raw-output .Build_Date /tmp/manifest.json) $(jq --raw-output .Build_Time /tmp/manifest.json)" >> "$GITHUB_OUTPUT" + - name: Verify artifacts + uses: ./.github/actions/run-gradle + with: + encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + arguments: | + --rerun-tasks \ + -Pmanifest.buildTimestamp="${{ steps.referenceJar.outputs.buildTimestamp }}" \ + -Pmanifest.createdBy="${{ steps.referenceJar.outputs.createdBy }}" \ + :verifyArtifactsInStagingRepositoryAreReproducible \ + --remote-repo-url=${{ env.STAGING_REPO_URL }} + - name: Generate build provenance attestations + if: ${{ inputs.dryRun == false }} + uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3.1.0 + with: + subject-path: build/repo/**/*.jar + + verify_consumability: + name: Verify consumability + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + fetch-depth: 1 + ref: "refs/tags/${{ env.RELEASE_TAG }}" + path: junit-framework + - name: Check out examples repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + repository: ${{ github.repository_owner }}/junit-examples + token: ${{ secrets.JUNIT_BUILDS_GITHUB_TOKEN_EXAMPLES_REPO }} + fetch-depth: 1 + path: junit-examples + ref: releases/5.14.x + - name: Set up JDK + uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + with: + java-version: 24 + distribution: temurin + - uses: sbt/setup-sbt@3e125ece5c3e5248e18da9ed8d2cce3d335ec8dd # v1.1.14 + - name: Update JUnit dependencies in examples + run: java src/Updater.java ${{ inputs.releaseVersion }} + working-directory: junit-examples + - name: Prepare Maven Central user token + uses: ./junit-framework/.github/actions/maven-central-user-token + with: + username: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + password: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + - name: Inject staging repository URL + run: java src/StagingRepoInjector.java ${{ env.STAGING_REPO_URL }} + working-directory: junit-examples + - name: Build examples + run: java src/Builder.java --exclude=junit-jupiter-starter-bazel,junit-jupiter-starter-sbt + working-directory: junit-examples + env: + MAVEN_ARGS: --settings ${{ github.workspace }}/junit-examples/src/central-staging-maven-settings.xml --activate-profiles central-staging + + close_github_milestone: + name: Close GitHub milestone + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Close GitHub milestone + if: ${{ inputs.dryRun == false }} + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + result-encoding: string + script: | + const query = ` + query ($owner: String!, $repo: String!, $title: String!) { + repository(owner: $owner, name: $repo) { + milestones(first: 100, query: $title) { + nodes { + title + number + openIssueCount + } + } + } + } + `; + const {repository} = await github.graphql(query, { + owner: context.repo.owner, + repo: context.repo.repo, + title: "${{ inputs.releaseVersion }}" + }); + const [milestone] = repository.milestones.nodes.filter(it => it.title === "${{ inputs.releaseVersion }}") + if (!milestone) { + throw new Error('Milestone "${{ inputs.releaseVersion }}" not found'); + } + if (milestone.openIssueCount > 0) { + throw new Error(`Milestone "${{ inputs.releaseVersion }}" has ${milestone.openIssueCount} open issue(s)`); + } + const requestBody = { + owner: context.repo.owner, + repo: context.repo.repo, + milestone_number: milestone.number, + state: 'closed', + due_on: new Date().toISOString() + }; + console.log(requestBody); + await github.rest.issues.updateMilestone(requestBody); + + publish_deployment: + name: Publish to Maven Central + needs: [ verify_reproducibility, verify_consumability, close_github_milestone ] + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + fetch-depth: 1 + ref: "refs/tags/${{ env.RELEASE_TAG }}" + - name: Release staging repository + if: ${{ inputs.dryRun == false }} + uses: ./.github/actions/run-gradle + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + JRELEASER_MAVENCENTRAL_STAGE: PUBLISH + JRELEASER_MAVENCENTRAL_DEPLOYMENT_ID: ${{ inputs.deploymentId }} + with: + encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + arguments: jreleaserDeploy + + publish_documentation: + name: Publish documentation + needs: publish_deployment + runs-on: ubuntu-latest + permissions: + actions: write + steps: + - name: Trigger deployment + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh workflow run deploy-docs.yml --repo junit-team/junit-framework --ref docs-site + - name: Wait for deployment + if: ${{ inputs.dryRun == false }} + id: pagesDeployment + timeout-minutes: 30 + run: | + URL="https://docs.junit.org/${{ inputs.releaseVersion }}/_exports/junit-user-guide-${{ inputs.releaseVersion }}.pdf" + ./.github/scripts/waitForUrl.sh "$URL" + echo "pdfUrl=$URL" >> "$GITHUB_OUTPUT" + - name: Verify integrity of PDF version of User Guide + if: ${{ inputs.dryRun == false }} + run: | + curl --silent --fail --location --output /tmp/junit-user-guide.pdf "${{ steps.pagesDeployment.outputs.pdfUrl }}" + pdfinfo /tmp/junit-user-guide.pdf + + update_examples: + name: Update examples + needs: publish_deployment + runs-on: ubuntu-latest + steps: + - name: Check out examples repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + repository: ${{ github.repository_owner }}/junit-examples + token: ${{ secrets.JUNIT_BUILDS_GITHUB_TOKEN_EXAMPLES_REPO }} + fetch-depth: 1 + ref: releases/5.14.x + - name: Set up JDK + uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + with: + java-version: 24 + distribution: temurin + - uses: sbt/setup-sbt@3e125ece5c3e5248e18da9ed8d2cce3d335ec8dd # v1.1.14 + - name: Update JUnit dependencies in examples + run: java src/Updater.java ${{ inputs.releaseVersion }} + - name: Build examples + if: ${{ inputs.dryRun == false }} + run: java src/Builder.java + - name: Create release branch + run: | + git config user.name "JUnit Team" + git config user.email "team@junit.org" + git switch -c "${{ env.RELEASE_TAG }}" + git status + git commit -a -m "Use ${{ inputs.releaseVersion }}" + - name: Push release branch + if: ${{ inputs.dryRun == false }} + run: | + git push origin "${{ env.RELEASE_TAG }}" + + create_github_release: + name: Create GitHub release + if: ${{ inputs.dryRun == false }} + needs: [ publish_documentation, update_examples ] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Create GitHub release + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const releaseVersion = "${{ inputs.releaseVersion }}"; + const jupiterVersion = releaseVersion; + const vintageVersion = releaseVersion; + const platformVersion = "1." + releaseVersion.substring(2); + const requestBody = { + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `r${releaseVersion}`, + name: `JUnit ${releaseVersion}`, + generate_release_notes: true, + body: `JUnit ${jupiterVersion} = Platform ${platformVersion} + Jupiter ${jupiterVersion} + Vintage ${vintageVersion}\n\nSee [Release Notes](https://docs.junit.org/${releaseVersion}/release-notes/).`, + prerelease: releaseVersion.includes("-"), + make_latest: false, + }; + console.log(requestBody); + await github.rest.repos.createRelease(requestBody); diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/reproducible-build.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/reproducible-build.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/reproducible-build.yml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/reproducible-build.yml 2026-06-21 20:26:05.000000000 +0000 @@ -7,7 +7,9 @@ - 'releases/**' pull_request: branches: - - '*' + - '**' + +permissions: {} env: DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} @@ -18,7 +20,7 @@ runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 - name: Restore Gradle cache and display toolchains @@ -27,8 +29,7 @@ encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | --quiet \ - --configuration-cache + --no-configuration-cache # Disable configuration cache due to https://github.com/diffplug/spotless/issues/2318 - name: Build and compare checksums shell: bash - run: | - ./gradle/scripts/checkBuildReproducibility.sh + run: ./.github/scripts/checkBuildReproducibility.sh diff -Nru jtreg8-8.1+1+ds1/junit5/.github/workflows/sanitize-closed-issues.yml jtreg8-8.3+1+ds1/junit5/.github/workflows/sanitize-closed-issues.yml --- jtreg8-8.1+1+ds1/junit5/.github/workflows/sanitize-closed-issues.yml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.github/workflows/sanitize-closed-issues.yml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,80 @@ +name: Sanitizes assigned labels and milestone on closed issues +on: + issues: + types: + - closed +permissions: {} +jobs: + label_issues: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const issue = await github.rest.issues.get({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }); + const originalLabels = issue.data.labels.map(l => l.name); + const newLabels = originalLabels.filter(l => l !== "status: in progress" && l !== "status: new"); + if (newLabels.length !== originalLabels.length) { + await github.rest.issues.update({ + issue_number: issue.data.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: newLabels, + }); + } + if (issue.data.state_reason === "not_planned" || issue.data.state_reason === "duplicate") { + if (issue.data.milestone) { + await github.rest.issues.update({ + issue_number: issue.data.number, + owner: context.repo.owner, + repo: context.repo.repo, + milestone: null, + }); + } + const statusLabels = newLabels.filter(l => l.startsWith("status: ")); + if (statusLabels.length === 0) { + if (issue.data.state_reason === "not_planned") { + await github.rest.issues.createComment({ + issue_number: issue.data.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: "Please assign a status label to this issue.", + }); + await github.rest.issues.update({ + issue_number: issue.data.number, + owner: context.repo.owner, + repo: context.repo.repo, + state: "open", + }); + } else { + newLabels.push("status: duplicate"); + await github.rest.issues.update({ + issue_number: issue.data.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: newLabels, + }); + } + } + } else { + if (!(newLabels.includes("type: task") || newLabels.includes("type: question")) && !issue.data.milestone) { + await github.rest.issues.createComment({ + issue_number: issue.data.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: "Please assign a milestone to this issue or label it with `type: task` or `type: question`.", + }); + await github.rest.issues.update({ + issue_number: issue.data.number, + owner: context.repo.owner, + repo: context.repo.repo, + state: "open", + }); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/.gitignore jtreg8-8.3+1+ds1/junit5/.gitignore --- jtreg8-8.1+1+ds1/junit5/.gitignore 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.gitignore 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,6 @@ # Gradle .gradle +.kotlin build # Ignore Gradle GUI config @@ -30,5 +31,13 @@ coverage.db* .metadata /.sdkmanrc +/.tool-versions checksums* + +# snapshot-tests +*.snapshot_actual +*.snapshot_raw + +# Antora +/documentation/node_modules/ diff -Nru jtreg8-8.1+1+ds1/junit5/.idea/codeStyles/Project.xml jtreg8-8.3+1+ds1/junit5/.idea/codeStyles/Project.xml --- jtreg8-8.1+1+ds1/junit5/.idea/codeStyles/Project.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/.idea/codeStyles/Project.xml 2026-06-21 20:26:05.000000000 +0000 @@ -7,6 +7,7 @@

In contrast to {@link AfterEach @AfterEach} methods, {@code @AfterAll} - * methods are only executed once for a given test class. + * methods are only executed once per execution of a given test class. If the + * test class is annotated with {@link ClassTemplate @ClassTemplate}, the + * {@code @AfterAll} methods are executed once after the last invocation of the + * class template. If a {@link Nested @Nested} test class is declared in a + * {@link ClassTemplate @ClassTemplate}, its {@code @AfterAll} methods are + * called once per execution of the nested test class, namely, once per + * invocation of the outer class template. * *

Method Signatures

* diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertAll.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertAll.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertAll.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertAll.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertArrayEquals.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertArrayEquals.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertArrayEquals.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertArrayEquals.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertDoesNotThrow.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertDoesNotThrow.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertDoesNotThrow.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertDoesNotThrow.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertEquals.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertEquals.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertEquals.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertEquals.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertFalse.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertFalse.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertFalse.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertFalse.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertInstanceOf.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertInstanceOf.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertInstanceOf.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertInstanceOf.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertIterableEquals.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertIterableEquals.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertIterableEquals.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertIterableEquals.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertLinesMatch.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertLinesMatch.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertLinesMatch.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertLinesMatch.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotEquals.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotEquals.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotEquals.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotEquals.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotNull.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotNull.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotNull.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotNull.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotSame.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotSame.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotSame.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNotSame.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNull.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNull.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNull.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertNull.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertSame.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertSame.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertSame.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertSame.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrowsExactly.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrowsExactly.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrowsExactly.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrowsExactly.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeout.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeout.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeout.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeout.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeoutPreemptively.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeoutPreemptively.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeoutPreemptively.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTimeoutPreemptively.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -113,7 +113,7 @@ cause = new ExecutionTimeoutException("Execution timed out in thread " + thread.getName()); cause.setStackTrace(thread.getStackTrace()); } - throw failureFactory.createTimeoutFailure(timeout, messageSupplier, cause); + throw failureFactory.createTimeoutFailure(timeout, messageSupplier, cause, thread); } catch (ExecutionException ex) { throw throwAsUncheckedException(ex.getCause()); @@ -124,7 +124,7 @@ } private static AssertionFailedError createAssertionFailure(Duration timeout, Supplier messageSupplier, - Throwable cause) { + Throwable cause, Thread thread) { return assertionFailure() // .message(messageSupplier) // .reason("execution timed out after " + timeout.toMillis() + " ms") // @@ -143,14 +143,17 @@ /** * The thread factory used for preemptive timeout. - *

- * The factory creates threads with meaningful names, helpful for debugging purposes. + * + *

The factory creates threads with meaningful names, helpful for debugging + * purposes. */ private static class TimeoutThreadFactory implements ThreadFactory { private static final AtomicInteger threadNumber = new AtomicInteger(1); + @Override public Thread newThread(Runnable r) { return new Thread(r, "junit-timeout-thread-" + threadNumber.getAndIncrement()); } } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTrue.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTrue.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTrue.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertTrue.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionFailureBuilder.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionFailureBuilder.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionFailureBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionFailureBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,8 +21,8 @@ /** * Builder for {@link AssertionFailedError AssertionFailedErrors}. - *

- * Using this builder ensures consistency in how failure message are formatted + * + *

Using this builder ensures consistency in how failure message are formatted * within JUnit Jupiter and for custom user-defined assertions. * * @since 5.9 @@ -51,8 +51,8 @@ /** * Set the user-defined message of the assertion. - *

- * The {@code message} may be passed as a {@link Supplier} or plain + * + *

The {@code message} may be passed as a {@link Supplier} or plain * {@link String}. If any other type is passed, it is converted to * {@code String} as per {@link StringUtils#nullSafeToString(Object)}. * @@ -115,7 +115,7 @@ * failure message. * * @param includeValuesInMessage whether to include the actual and expected - * values + * values * @return this builder for method chaining */ public AssertionFailureBuilder includeValuesInMessage(boolean includeValuesInMessage) { @@ -202,4 +202,5 @@ return (obj == null ? "null" : obj instanceof Class ? getCanonicalName((Class) obj) : obj.getClass().getName()); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -1493,7 +1493,7 @@ * iterators must return equal elements in the same order as each other. Note: * this means that the iterables do not need to be of the same type. Example:

{@code
 	 * import static java.util.Arrays.asList;
-	 *  . . .
+	 *  ...
 	 * Iterable i0 = new ArrayList<>(asList(1, 2, 3));
 	 * Iterable i1 = new LinkedList<>(asList(1, 2, 3));
 	 * assertIterableEquals(i0, i1); // Passes
@@ -1516,7 +1516,7 @@
 	 * elements in the same order as each other. Note: this means that the iterables
 	 * do not need to be of the same type. Example: 
{@code
 	 * import static java.util.Arrays.asList;
-	 *  . . .
+	 *  ...
 	 * Iterable i0 = new ArrayList<>(asList(1, 2, 3));
 	 * Iterable i1 = new LinkedList<>(asList(1, 2, 3));
 	 * assertIterableEquals(i0, i1); // Passes
@@ -1540,7 +1540,7 @@
 	 * elements in the same order as each other. Note: this means that the iterables
 	 * do not need to be of the same type. Example: 
{@code
 	 * import static java.util.Arrays.asList;
-	 *  . . .
+	 *  ...
 	 * Iterable i0 = new ArrayList<>(asList(1, 2, 3));
 	 * Iterable i1 = new LinkedList<>(asList(1, 2, 3));
 	 * assertIterableEquals(i0, i1); // Passes
@@ -3662,6 +3662,6 @@
 		 *
 		 * @return timeout failure; never {@code null}
 		 */
-		T createTimeoutFailure(Duration timeout, Supplier messageSupplier, Throwable cause);
+		T createTimeoutFailure(Duration timeout, Supplier messageSupplier, Throwable cause, Thread testThread);
 	}
 }
diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assumptions.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assumptions.java
--- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assumptions.java	2025-10-22 19:33:55.000000000 +0000
+++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assumptions.java	2026-06-21 20:26:05.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2026 the original author or authors.
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v2.0 which
@@ -27,7 +27,12 @@
  *
  * 

In direct contrast to failed {@linkplain Assertions assertions}, * failed assumptions do not result in a test failure; rather, - * a failed assumption results in a test being aborted. + * a failed assumption results in a test being aborted. However, + * failed assertions and other exceptions thrown by tests take precedence over + * failed assumptions when both are thrown during the execution of a test + * (for example, by different lifecycle methods), regardless of the order they + * are thrown in. In such cases, the test will be reported as failed + * rather than aborted. * *

Assumptions are typically used whenever it does not make sense to * continue execution of a given test method — for example, if the diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AutoClose.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AutoClose.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AutoClose.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AutoClose.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -78,7 +78,7 @@ @Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Documented -@API(status = EXPERIMENTAL, since = "5.11") +@API(status = MAINTAINED, since = "5.13.3") public @interface AutoClose { /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -25,7 +25,13 @@ * executed before all tests in the current test class. * *

In contrast to {@link BeforeEach @BeforeEach} methods, {@code @BeforeAll} - * methods are only executed once for a given test class. + * methods are only executed once per execution of a given test class. If the + * test class is annotated with {@link ClassTemplate @ClassTemplate}, the + * {@code @BeforeAll} methods are executed once before the first invocation of + * the class template. If a {@link Nested @Nested} test class is declared in a + * {@link ClassTemplate @ClassTemplate}, its {@code @BeforeAll} methods are + * called once per execution of the nested test class, namely, once per + * invocation of the outer class template. * *

Method Signatures

* diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrderer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrderer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrderer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrderer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -90,8 +90,7 @@ *
 	 * public void orderClasses(ClassOrdererContext context) {
 	 *     Collections.shuffle(context.getClassDescriptors());
-	 * }
-	 * 
+ * }
* * @param context the {@code ClassOrdererContext} containing the * {@linkplain ClassDescriptor class descriptors} to order; never {@code null} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrdererContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrdererContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrdererContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassOrdererContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassTemplate.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassTemplate.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassTemplate.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/ClassTemplate.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContextProvider; +import org.junit.platform.commons.annotation.Testable; + +/** + * {@code @ClassTemplate} is used to signal that the annotated class is a + * class template. + * + *

In contrast to regular test classes, a class template is not directly + * a test class but rather a template for a set of test cases. As such, it is + * designed to be invoked multiple times depending on the number of {@linkplain + * ClassTemplateInvocationContext invocation + * contexts} returned by the registered {@linkplain + * ClassTemplateInvocationContextProvider + * providers}. Must be used together with at least one provider. Otherwise, + * execution will fail. + * + *

Each invocation of a class template method behaves like the execution + * of a regular test class with full support for the same lifecycle callbacks + * and extensions. + * + *

{@code @ClassTemplate} may be combined with {@link Nested @Nested} and + * a class template may contain regular nested test classes or nested + * class templates. + * + *

{@code @ClassTemplate} may also be used as a meta-annotation in order + * to create a custom composed annotation that inherits the semantics + * of {@code @ClassTemplate}. + * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * + * @since 5.13 + * @see TestTemplate + * @see ClassTemplateInvocationContext + * @see ClassTemplateInvocationContextProvider + * @see BeforeClassTemplateInvocationCallback + * @see AfterClassTemplateInvocationCallback + */ +@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@API(status = MAINTAINED, since = "5.13.3") +@Testable +public @interface ClassTemplate { +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayName.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayName.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayName.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayName.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGeneration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGeneration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGeneration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGeneration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,18 +10,28 @@ package org.junit.jupiter.api; +import static java.util.Collections.emptyList; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import static org.junit.platform.commons.support.ModifierSupport.isStatic; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; import java.util.function.Predicate; import org.apiguardian.api.API; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; /** * {@code DisplayNameGenerator} defines the SPI for generating display names @@ -73,7 +83,8 @@ /** * Generate a display name for the given top-level or {@code static} nested test class. * - *

If it returns {@code null}, the default display name generator will be used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @param testClass the class to generate a name for; never {@code null} * @return the display name for the class; never blank @@ -81,19 +92,52 @@ String generateDisplayNameForClass(Class testClass); /** - * Generate a display name for the given {@link Nested @Nested} inner test class. + * Generate a display name for the given {@link Nested @Nested} inner test + * class. * - *

If it returns {@code null}, the default display name generator will be used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @param nestedClass the class to generate a name for; never {@code null} * @return the display name for the nested class; never blank + * @deprecated in favor of {@link #generateDisplayNameForNestedClass(List, Class)} */ - String generateDisplayNameForNestedClass(Class nestedClass); + @API(status = DEPRECATED, since = "5.12") + @Deprecated + default String generateDisplayNameForNestedClass(Class nestedClass) { + throw new UnsupportedOperationException( + "Implement generateDisplayNameForNestedClass(List>, Class) instead"); + } + + /** + * Generate a display name for the given {@link Nested @Nested} inner test + * class. + * + *

If this method returns {@code null}, the default display name + * generator will be used instead. + * + * @implNote The classes supplied as {@code enclosingInstanceTypes} may + * differ from the classes returned from invocations of + * {@link Class#getEnclosingClass()} — for example, when a nested test + * class is inherited from a superclass. + * + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances for the test class, ordered from outermost to innermost, + * excluding {@code nestedClass}; never {@code null} + * @param nestedClass the class to generate a name for; never {@code null} + * @return the display name for the nested class; never blank + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + default String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { + return generateDisplayNameForNestedClass(nestedClass); + } /** * Generate a display name for the given method. * - *

If it returns {@code null}, the default display name generator will be used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @implNote The class instance supplied as {@code testClass} may differ from * the class returned by {@code testMethod.getDeclaringClass()} — for @@ -102,8 +146,42 @@ * @param testClass the class the test method is invoked on; never {@code null} * @param testMethod method to generate a display name for; never {@code null} * @return the display name for the test; never blank + * @deprecated in favor of {@link #generateDisplayNameForMethod(List, Class, Method)} */ - String generateDisplayNameForMethod(Class testClass, Method testMethod); + @API(status = DEPRECATED, since = "5.12") + @Deprecated + default String generateDisplayNameForMethod(Class testClass, Method testMethod) { + throw new UnsupportedOperationException( + "Implement generateDisplayNameForMethod(List>, Class, Method) instead"); + } + + /** + * Generate a display name for the given method. + * + *

If this method returns {@code null}, the default display name + * generator will be used instead. + * + * @implNote The classes supplied as {@code enclosingInstanceTypes} may + * differ from the classes returned from invocations of + * {@link Class#getEnclosingClass()} — for example, when a nested test + * class is inherited from a superclass. Similarly, the class instance + * supplied as {@code testClass} may differ from the class returned by + * {@code testMethod.getDeclaringClass()} — for example, when a test + * method is inherited from a superclass. + * + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances for the test class, ordered from outermost to innermost, + * excluding {@code testClass}; never {@code null} + * @param testClass the class the test method is invoked on; never {@code null} + * @param testMethod method to generate a display name for; never {@code null} + * @return the display name for the test; never blank + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + default String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return generateDisplayNameForMethod(testClass, testMethod); + } /** * Generate a string representation of the formal parameters of the supplied @@ -141,12 +219,13 @@ } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return nestedClass.getSimpleName(); } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return testMethod.getName() + parameterTypesAsString(testMethod); } } @@ -158,7 +237,10 @@ *

This generator extends the functionality of {@link Standard} by * removing parentheses ({@code '()'}) found at the end of method names * with no parameters. + * + * @since 5.7 */ + @API(status = STABLE, since = "5.7") class Simple extends Standard { static final DisplayNameGenerator INSTANCE = new Simple(); @@ -167,7 +249,8 @@ } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { String displayName = testMethod.getName(); if (hasParameters(testMethod)) { displayName += ' ' + parameterTypesAsString(testMethod); @@ -201,13 +284,15 @@ } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { - return replaceUnderscores(super.generateDisplayNameForNestedClass(nestedClass)); + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { + return replaceUnderscores(super.generateDisplayNameForNestedClass(enclosingInstanceTypes, nestedClass)); } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { - return replaceUnderscores(super.generateDisplayNameForMethod(testClass, testMethod)); + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return replaceUnderscores( + super.generateDisplayNameForMethod(enclosingInstanceTypes, testClass, testMethod)); } private static String replaceUnderscores(String name) { @@ -226,63 +311,116 @@ * via the {@link IndicativeSentencesGeneration @IndicativeSentencesGeneration} * annotation. * + *

If you do not want to rely on a display name generator for individual + * sentence fragments, you can supply custom text for individual fragments + * via the {@link SentenceFragment @SentenceFragment} annotation. + * * @since 5.7 */ @API(status = STABLE, since = "5.10") class IndicativeSentences implements DisplayNameGenerator { + /** + * {@code @SentenceFragment} is used to configure a custom sentence fragment + * for a sentence generated by the {@link IndicativeSentences IndicativeSentences} + * {@code DisplayNameGenerator}. + * + *

Note that {@link DisplayName @DisplayName} always takes precedence + * over {@code @SentenceFragment}. + * + * @since 5.13 + */ + @Target({ ElementType.TYPE, ElementType.METHOD }) + @Retention(RetentionPolicy.RUNTIME) + @API(status = MAINTAINED, since = "5.13.3") + public @interface SentenceFragment { + + /** + * Custom sentence fragment for the annotated class or method. + * + * @return a custom sentence fragment; never blank or consisting solely + * of whitespace + */ + String value(); + + } + static final DisplayNameGenerator INSTANCE = new IndicativeSentences(); + private static final Predicate> notIndicativeSentences = clazz -> clazz != IndicativeSentences.class; + public IndicativeSentences() { } @Override public String generateDisplayNameForClass(Class testClass) { - return getGeneratorFor(testClass).generateDisplayNameForClass(testClass); + String sentenceFragment = getSentenceFragment(testClass); + return (sentenceFragment != null ? sentenceFragment + : getGeneratorFor(testClass, emptyList()).generateDisplayNameForClass(testClass)); } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { - return getSentenceBeginning(nestedClass); + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { + return getSentenceBeginning(nestedClass, enclosingInstanceTypes); } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { - return getSentenceBeginning(testClass) + getFragmentSeparator(testClass) - + getGeneratorFor(testClass).generateDisplayNameForMethod(testClass, testMethod); + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + + String displayName = getSentenceBeginning(testClass, enclosingInstanceTypes) + + getFragmentSeparator(testClass, enclosingInstanceTypes); + + String sentenceFragment = getSentenceFragment(testMethod); + displayName += (sentenceFragment != null ? sentenceFragment + : getGeneratorFor(testClass, enclosingInstanceTypes).generateDisplayNameForMethod( + enclosingInstanceTypes, testClass, testMethod)); + return displayName; } - private String getSentenceBeginning(Class testClass) { - Class enclosingClass = testClass.getEnclosingClass(); + private String getSentenceBeginning(Class testClass, List> enclosingInstanceTypes) { + Class enclosingClass = enclosingInstanceTypes.isEmpty() ? null + : enclosingInstanceTypes.get(enclosingInstanceTypes.size() - 1); boolean topLevelTestClass = (enclosingClass == null || isStatic(testClass)); - Optional displayName = findAnnotation(testClass, DisplayName.class)// - .map(DisplayName::value).map(String::trim); + + String sentenceFragment = findAnnotation(testClass, DisplayName.class)// + .map(DisplayName::value)// + .map(String::trim)// + .orElseGet(() -> getSentenceFragment(testClass)); if (topLevelTestClass) { - if (displayName.isPresent()) { - return displayName.get(); + if (sentenceFragment != null) { + return sentenceFragment; } - Class generatorClass = findDisplayNameGeneration(testClass)// - .map(DisplayNameGeneration::value)// - .filter(not(IndicativeSentences.class))// - .orElse(null); + Class generatorClass = findDisplayNameGeneration(testClass, + enclosingInstanceTypes)// + .map(DisplayNameGeneration::value)// + .filter(notIndicativeSentences)// + .orElse(null); if (generatorClass != null) { return getDisplayNameGenerator(generatorClass).generateDisplayNameForClass(testClass); } return generateDisplayNameForClass(testClass); } + List> remainingEnclosingInstanceTypes = enclosingInstanceTypes.isEmpty() ? emptyList() + : enclosingInstanceTypes.subList(0, enclosingInstanceTypes.size() - 1); + // Only build prefix based on the enclosing class if the enclosing // class is also configured to use the IndicativeSentences generator. - boolean buildPrefix = findDisplayNameGeneration(enclosingClass)// + boolean buildPrefix = findDisplayNameGeneration(enclosingClass, remainingEnclosingInstanceTypes)// .map(DisplayNameGeneration::value)// .filter(IndicativeSentences.class::equals)// .isPresent(); - String prefix = (buildPrefix ? getSentenceBeginning(enclosingClass) + getFragmentSeparator(testClass) : ""); - - return prefix + displayName.orElseGet( - () -> getGeneratorFor(testClass).generateDisplayNameForNestedClass(testClass)); + String prefix = (buildPrefix + ? getSentenceBeginning(enclosingClass, remainingEnclosingInstanceTypes) + + getFragmentSeparator(testClass, enclosingInstanceTypes) + : ""); + + return prefix + (sentenceFragment != null ? sentenceFragment + : getGeneratorFor(testClass, enclosingInstanceTypes).generateDisplayNameForNestedClass( + remainingEnclosingInstanceTypes, testClass)); } /** @@ -295,10 +433,12 @@ * will be used. * * @param testClass the test class to search on for {@code @IndicativeSentencesGeneration} + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances; never {@code null} * @return the sentence fragment separator */ - private static String getFragmentSeparator(Class testClass) { - return findIndicativeSentencesGeneration(testClass)// + private static String getFragmentSeparator(Class testClass, List> enclosingInstanceTypes) { + return findIndicativeSentencesGeneration(testClass, enclosingInstanceTypes)// .map(IndicativeSentencesGeneration::separator)// .orElse(IndicativeSentencesGeneration.DEFAULT_SEPARATOR); } @@ -313,12 +453,14 @@ * will be used. * * @param testClass the test class to search on for {@code @IndicativeSentencesGeneration} + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances; never {@code null} * @return the {@code DisplayNameGenerator} instance to use */ - private static DisplayNameGenerator getGeneratorFor(Class testClass) { - return findIndicativeSentencesGeneration(testClass)// + private static DisplayNameGenerator getGeneratorFor(Class testClass, List> enclosingInstanceTypes) { + return findIndicativeSentencesGeneration(testClass, enclosingInstanceTypes)// .map(IndicativeSentencesGeneration::generator)// - .filter(not(IndicativeSentences.class))// + .filter(notIndicativeSentences)// .map(DisplayNameGenerator::getDisplayNameGenerator)// .orElseGet(() -> getDisplayNameGenerator(IndicativeSentencesGeneration.DEFAULT_GENERATOR)); } @@ -326,29 +468,43 @@ /** * Find the first {@code DisplayNameGeneration} annotation that is either * directly present, meta-present, or indirectly present - * on the supplied {@code testClass} or on an enclosing class. + * on the supplied {@code testClass} or on an enclosing instance type. * * @param testClass the test class on which to find the annotation; never {@code null} + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances; never {@code null} * @return an {@code Optional} containing the annotation, potentially empty if not found */ - private static Optional findDisplayNameGeneration(Class testClass) { - return findAnnotation(testClass, DisplayNameGeneration.class, true); + @API(status = INTERNAL, since = "5.12") + private static Optional findDisplayNameGeneration(Class testClass, + List> enclosingInstanceTypes) { + return findAnnotation(testClass, DisplayNameGeneration.class, enclosingInstanceTypes); } /** * Find the first {@code IndicativeSentencesGeneration} annotation that is either * directly present, meta-present, or indirectly present - * on the supplied {@code testClass} or on an enclosing class. + * on the supplied {@code testClass} or on an enclosing instance type. * * @param testClass the test class on which to find the annotation; never {@code null} + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances; never {@code null} * @return an {@code Optional} containing the annotation, potentially empty if not found */ - private static Optional findIndicativeSentencesGeneration(Class testClass) { - return findAnnotation(testClass, IndicativeSentencesGeneration.class, true); + private static Optional findIndicativeSentencesGeneration(Class testClass, + List> enclosingInstanceTypes) { + return findAnnotation(testClass, IndicativeSentencesGeneration.class, enclosingInstanceTypes); } - private static Predicate> not(Class clazz) { - return ((Predicate>) clazz::equals).negate(); + private static String getSentenceFragment(AnnotatedElement element) { + return findAnnotation(element, SentenceFragment.class) // + .map(SentenceFragment::value) // + .map(sentenceFragment -> { + Preconditions.notBlank(sentenceFragment, String.format( + "@SentenceFragment on [%s] must be declared with a non-blank value.", element)); + return sentenceFragment.trim(); + }) // + .orElse(null); } } @@ -377,7 +533,7 @@ if (generatorClass == IndicativeSentences.class) { return IndicativeSentences.INSTANCE; } - return (DisplayNameGenerator) ReflectionUtils.newInstance(generatorClass); + return (DisplayNameGenerator) ReflectionSupport.newInstance(generatorClass); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicContainer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicContainer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicContainer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicContainer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicNode.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicNode.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicNode.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicNode.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,7 +12,6 @@ import static java.util.Spliterator.ORDERED; import static java.util.Spliterators.spliteratorUnknownSize; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.MAINTAINED; import java.net.URI; @@ -249,7 +248,7 @@ * @see #stream(Stream) * @see NamedExecutable */ - @API(status = EXPERIMENTAL, since = "5.11") + @API(status = MAINTAINED, since = "5.13.3") public static , E extends Executable> Stream stream( Iterator iterator) { Preconditions.notNull(iterator, "iterator must not be null"); @@ -279,7 +278,7 @@ * @see #stream(Iterator) * @see NamedExecutable */ - @API(status = EXPERIMENTAL, since = "5.11") + @API(status = MAINTAINED, since = "5.13.3") public static , E extends Executable> Stream stream( Stream inputStream) { Preconditions.notNull(inputStream, "inputStream must not be null"); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/IndicativeSentencesGeneration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/IndicativeSentencesGeneration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/IndicativeSentencesGeneration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/IndicativeSentencesGeneration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MediaType.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MediaType.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MediaType.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MediaType.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,165 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; + +/** + * Represents a media type as defined by + * RFC 2045. + * + *

WARNING: This type should not be extended by third parties. + * + * @since 5.14 + * @see TestReporter#publishFile(Path, MediaType) + * @see TestReporter#publishFile(String, MediaType, org.junit.jupiter.api.function.ThrowingConsumer) + * @see org.junit.jupiter.api.extension.ExtensionContext#publishFile(String, MediaType, org.junit.jupiter.api.function.ThrowingConsumer) + */ +@API(status = MAINTAINED, since = "5.14") +public class MediaType { + + private static final Pattern PATTERN; + + static { + // https://datatracker.ietf.org/doc/html/rfc2045#section-5.1 + String whitespace = "[ \t]*"; + String token = "[0-9A-Za-z!#$%&'*+.^_`|~-]+"; + String quotedString = "\"(?:[^\"\\\\]|\\.)*\""; + String parameter = ";" + whitespace + token + "=" + "(?:" + token + "|" + quotedString + ")"; + PATTERN = Pattern.compile(token + "/" + token + "(?:" + whitespace + parameter + ")*"); + } + + /** + * The {@code text/plain} media type. + */ + public static final MediaType TEXT_PLAIN = create("text", "plain"); + + /** + * The {@code text/plain; charset=UTF-8} media type. + */ + public static final MediaType TEXT_PLAIN_UTF_8 = create("text", "plain", UTF_8); + + /** + * The {@code application/json} media type. + */ + public static final MediaType APPLICATION_JSON = create("application", "json"); + + /** + * The {@code application/octet-stream} media type. + */ + public static final MediaType APPLICATION_OCTET_STREAM = create("application", "octet-stream"); + + /** + * The {@code image/jpeg} media type. + */ + public static final MediaType IMAGE_JPEG = create("image", "jpeg"); + + /** + * The {@code image/png} media type. + */ + public static final MediaType IMAGE_PNG = create("image", "png"); + + private final String value; + + /** + * Parse the given media type value. + * + *

Must be valid according to + * RFC 2045. + * + * @param value the media type value to parse; never {@code null} or blank + * @return the parsed media type + */ + public static MediaType parse(String value) { + return new MediaType(value); + } + + /** + * Create a media type with the given type and subtype. + * + * @param type the type; never {@code null} or blank + * @param subtype the subtype; never {@code null} or blank + * @return the media type + */ + public static MediaType create(String type, String subtype) { + return new MediaType(type, subtype, null); + } + + /** + * Create a media type with the given type, subtype, and charset. + * + * @param type the type; never {@code null} or blank + * @param subtype the subtype; never {@code null} or blank + * @param charset the charset; never {@code null} + * @return the media type + */ + public static MediaType create(String type, String subtype, Charset charset) { + Preconditions.notNull(charset, "charset must not be null"); + return new MediaType(type, subtype, charset); + } + + protected MediaType(String type, String subtype, Charset charset) { + this(String.format("%s/%s%s", // + Preconditions.notBlank(type, "type must not be null or blank").trim(), + Preconditions.notBlank(subtype, "subtype must not be null or blank").trim(), + (charset != null ? ("; charset=" + charset.name()) : ""))); + } + + protected MediaType(String value) { + // Mimic sealed types, permitting only this class and api.extension.MediaType. + if (getClass() != MediaType.class + && !getClass().getName().equals("org.junit.jupiter.api.extension.MediaType")) { + throw new IllegalStateException( + String.format("Type '%s' is not permitted to extend MediaType", getClass().getName())); + } + + String trimmedValue = Preconditions.notBlank(value, "value must not be null or blank").trim(); + Matcher matcher = PATTERN.matcher(trimmedValue); + Preconditions.condition(matcher.matches(), () -> "Invalid media type: '" + trimmedValue + "'"); + this.value = trimmedValue; + } + + /** + * {@return a string representation of this media type} + */ + @Override + public final String toString() { + return this.value; + } + + @Override + public final boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MediaType) { + MediaType that = (MediaType) obj; + return this.value.equals(that.value); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hashCode(this.value); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrderer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrderer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrderer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrderer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -88,8 +88,7 @@ *

 	 * public void orderMethods(MethodOrdererContext context) {
 	 *     Collections.shuffle(context.getMethodDescriptors());
-	 * }
-	 * 
+ * }
* * @param context the {@code MethodOrdererContext} containing the * {@linkplain MethodDescriptor method descriptors} to order; never {@code null} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrdererContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrdererContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrdererContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/MethodOrdererContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Named.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Named.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Named.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Named.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/NamedExecutable.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/NamedExecutable.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/NamedExecutable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/NamedExecutable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.util.Iterator; import java.util.stream.Stream; @@ -34,7 +34,7 @@ * @see DynamicTest#stream(Iterator) */ @FunctionalInterface -@API(status = EXPERIMENTAL, since = "5.11") +@API(status = MAINTAINED, since = "5.13.3") public interface NamedExecutable extends Named, Executable { @Override default String getName() { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Nested.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Nested.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Nested.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Nested.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -31,6 +31,8 @@ *

{@code @Nested} test classes may be ordered via * {@link TestClassOrder @TestClassOrder} or a global {@link ClassOrderer}. * + *

{@code @Nested} may be combined with {@link ClassTemplate @ClassTemplate}. + * *

Test Instance Lifecycle

* *
    @@ -42,6 +44,7 @@ *
* * @since 5.0 + * @see ClassTemplate * @see Test * @see TestInstance * @see TestClassOrder diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Order.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Order.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Order.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Order.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepeatedTest.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepeatedTest.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepeatedTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepeatedTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -191,7 +191,7 @@ * @return the failure threshold; must be greater than zero and less than the * total number of repetitions */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") int failureThreshold() default Integer.MAX_VALUE; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepetitionInfo.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepetitionInfo.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepetitionInfo.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RepetitionInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; @@ -58,7 +58,7 @@ * @since 5.10 * @see #getFailureThreshold() */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") int getFailureCount(); /** @@ -68,7 +68,7 @@ * @since 5.10 * @see RepeatedTest#failureThreshold() */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") int getFailureThreshold(); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tag.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tag.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tag.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tag.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tags.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tags.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tags.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Tags.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Test.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Test.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Test.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Test.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestClassOrder.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestClassOrder.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestClassOrder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestClassOrder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -57,8 +57,7 @@ * class SecondaryTests { * // {@literal @}Test methods ... * } - * } - *
+ * } * * @since 5.8 * @see ClassOrderer diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -30,7 +30,9 @@ * *

{@code @TestFactory} methods must not be {@code private} or {@code static} * and must return a {@code Stream}, {@code Collection}, {@code Iterable}, - * {@code Iterator}, or array of {@link DynamicNode} instances. Supported + * {@code Iterator}, array of {@link DynamicNode} instances, or any type that + * provides an {@link java.util.Iterator Iterator}-returning {@code iterator()} + * method (such as, for example, a {@code kotlin.sequences.Sequence}). Supported * subclasses of {@code DynamicNode} include {@link DynamicContainer} and * {@link DynamicTest}. Dynamic tests will be executed lazily, * enabling dynamic and even non-deterministic generation of test cases. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInfo.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInfo.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInfo.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -68,8 +68,7 @@ * class NestedTests {} * * static class StaticTests {} - * } - * + * } * *

If the context in which {@code TestInfo} is used is at the test level, * the default display name is the name of the test method concatenated with @@ -79,8 +78,7 @@ * *

 	 *   {@literal @}Test
-	 *   void testUser(TestInfo testInfo, {@literal @}Mock User user) {}
-	 * 
+ * void testUser(TestInfo testInfo, {@literal @}Mock User user) {} * *

Note that display names are typically used for test reporting in IDEs * and build tools and may contain spaces, special characters, and even emoji. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestInstance.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -86,7 +86,12 @@ /** * When using this mode, a new test instance will be created once per - * test class. + * test class or class template. + * + *

For {@link Nested @Nested}

test classes declared inside an + * enclosing {@link ClassTemplate @ClassTemplate}, an instance of the + * {@code @Nested} class will be created for each invocation of the + * {@code @ClassTemplate}. * * @see #PER_METHOD */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestMethodOrder.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestMethodOrder.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestMethodOrder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestMethodOrder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -62,8 +62,7 @@ * {@literal @}Test * {@literal @}Order(3) * void validValues() {} - * } - * + * } * *

Parallel Execution

*

Using a {@link MethodOrderer} disables parallel execution unless the test diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,12 +10,22 @@ package org.junit.jupiter.api; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.Map; +import java.util.stream.Stream; import org.apiguardian.api.API; +import org.junit.jupiter.api.function.ThrowingConsumer; +import org.junit.platform.commons.util.Preconditions; /** * Parameters of type {@code TestReporter} can be injected into @@ -74,7 +84,145 @@ */ @API(status = STABLE, since = "5.3") default void publishEntry(String value) { - this.publishEntry("value", value); + publishEntry("value", value); + } + + /** + * Publish the supplied file and attach it to the current test or container. + * + *

The file will be copied to the report output directory replacing any + * potentially existing file with the same name. + * + * @param file the file to be published; never {@code null} + * @param mediaType the media type of the file; never {@code null}; use + * {@link org.junit.jupiter.api.extension.MediaType#APPLICATION_OCTET_STREAM} + * if unknown + * @since 5.12 + * @deprecated Use {@link #publishFile(Path, MediaType)} instead. + */ + @Deprecated + @API(status = DEPRECATED, since = "5.14") + default void publishFile(Path file, org.junit.jupiter.api.extension.MediaType mediaType) { + Preconditions.notNull(mediaType, "mediaType must not be null"); + publishFile(file, MediaType.parse(mediaType.toString())); + } + + /** + * Publish the supplied file and attach it to the current test or container. + * + *

The file will be copied to the report output directory replacing any + * potentially existing file with the same name. + * + * @param file the file to be published; never {@code null} + * @param mediaType the media type of the file; never {@code null}; use + * {@link MediaType#APPLICATION_OCTET_STREAM} if unknown + * @since 5.14 + */ + @API(status = MAINTAINED, since = "5.14") + default void publishFile(Path file, MediaType mediaType) { + Preconditions.notNull(file, "file must not be null"); + Preconditions.notNull(mediaType, "mediaType must not be null"); + Preconditions.condition(Files.exists(file), () -> "file must exist: " + file); + Preconditions.condition(Files.isRegularFile(file), () -> "file must be a regular file: " + file); + publishFile(file.getFileName().toString(), mediaType, path -> Files.copy(file, path, REPLACE_EXISTING)); + } + + /** + * Publish the supplied directory and attach it to the current test or + * container. + * + *

The entire directory will be copied to the report output directory + * replacing any potentially existing files with the same name. + * + * @param directory the directory to be published; never {@code null} + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + default void publishDirectory(Path directory) { + Preconditions.notNull(directory, "directory must not be null"); + Preconditions.condition(Files.exists(directory), () -> "directory must exist: " + directory); + Preconditions.condition(Files.isDirectory(directory), () -> "path must represent a directory: " + directory); + publishDirectory(directory.getFileName().toString(), path -> { + try (Stream stream = Files.walk(directory)) { + stream.forEach(source -> { + Path destination = path.resolve(directory.relativize(source)); + try { + if (Files.isDirectory(source)) { + Files.createDirectories(destination); + } + else { + Files.copy(source, destination, REPLACE_EXISTING); + } + } + catch (IOException e) { + throw new UncheckedIOException("Failed to copy files to the output directory", e); + } + }); + } + }); + } + + /** + * Publish a file with the supplied name and media type written by the supplied + * action and attach it to the current test or container. + * + *

The {@link Path} passed to the supplied action will be relative to the + * report output directory, but it is up to the action to write the file. + * + * @param name the name of the file to be published; never {@code null} or + * blank and must not contain any path separators + * @param mediaType the media type of the file; never {@code null}; use + * {@link org.junit.jupiter.api.extension.MediaType#APPLICATION_OCTET_STREAM} + * if unknown + * @param action the action to be executed to write the file; never {@code null} + * @since 5.12 + * @deprecated Use {@link #publishFile(String, MediaType, ThrowingConsumer)} instead. + */ + @Deprecated + @API(status = DEPRECATED, since = "5.14") + default void publishFile(String name, org.junit.jupiter.api.extension.MediaType mediaType, + ThrowingConsumer action) { + + Preconditions.notNull(mediaType, "mediaType must not be null"); + publishFile(name, MediaType.parse(mediaType.toString()), action); + } + + /** + * Publish a file with the supplied name and media type written by the supplied + * action and attach it to the current test or container. + * + *

The {@link Path} passed to the supplied action will be relative to the + * report output directory, but it is up to the action to write the file. + * + * @param name the name of the file to be published; never {@code null} or + * blank and must not contain any path separators + * @param mediaType the media type of the file; never {@code null}; use + * {@link MediaType#APPLICATION_OCTET_STREAM} if unknown + * @param action the action to be executed to write the file; never {@code null} + * @since 5.14 + */ + @API(status = MAINTAINED, since = "5.14") + default void publishFile(String name, MediaType mediaType, ThrowingConsumer action) { + throw new UnsupportedOperationException(); + } + + /** + * Publish a directory with the supplied name written by the supplied action + * and attach it to the current test or container. + * + *

The {@link Path} passed to the supplied action will be relative to the + * report output directory and will point to an existing directory, but it is + * up to the action to write files to the directory. + * + * @param name the name of the directory to be published; never {@code null} + * or blank and must not contain any path separators + * @param action the action to be executed to write to the directory; never + * {@code null} + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + default void publishDirectory(String name, ThrowingConsumer action) { + throw new UnsupportedOperationException(); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestTemplate.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestTemplate.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestTemplate.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestTemplate.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -79,6 +79,7 @@ * * @since 5.0 * @see Test + * @see ClassTemplate * @see org.junit.jupiter.api.extension.TestTemplateInvocationContext * @see org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Timeout.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Timeout.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Timeout.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Timeout.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -329,7 +329,7 @@ * * @since 5.9 */ - @API(status = EXPERIMENTAL, since = "5.9") + @API(status = MAINTAINED, since = "5.13.3") String DEFAULT_TIMEOUT_THREAD_MODE_PROPERTY_NAME = "junit.jupiter.execution.timeout.thread.mode.default"; /** @@ -358,8 +358,8 @@ ThreadMode threadMode() default ThreadMode.INFERRED; /** - * {@code ThreadMode} is use to define whether the test code should be executed in the thread - * of the calling code or in a separated thread. + * {@code ThreadMode} is used to define whether test code should be executed + * in the thread of the calling code or in a separate thread. * * @since 5.9 */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreCondition.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.condition; + +import static java.util.function.Predicate.isEqual; + +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.function.Function; +import java.util.stream.IntStream; + +import org.junit.platform.commons.util.Preconditions; + +/** + * Abstract base class for {@link EnabledOnJreCondition} and + * {@link DisabledOnJreCondition}. + * + * @since 5.12 + */ +abstract class AbstractJreCondition extends BooleanExecutionCondition { + + static final String ENABLED_ON_CURRENT_JRE = // + "Enabled on JRE version: " + System.getProperty("java.version"); + + static final String DISABLED_ON_CURRENT_JRE = // + "Disabled on JRE version: " + System.getProperty("java.version"); + + private final String annotationName; + + AbstractJreCondition(Class annotationType, Function customDisabledReason) { + super(annotationType, ENABLED_ON_CURRENT_JRE, DISABLED_ON_CURRENT_JRE, customDisabledReason); + this.annotationName = annotationType.getSimpleName(); + } + + protected final IntStream validatedVersions(JRE[] jres, int[] versions) { + Preconditions.condition(jres.length > 0 || versions.length > 0, + () -> "You must declare at least one JRE or version in @" + this.annotationName); + + Preconditions.condition(Arrays.stream(jres).noneMatch(isEqual(JRE.UNDEFINED)), + () -> "JRE.UNDEFINED is not supported in @" + this.annotationName); + Arrays.stream(versions).min().ifPresent(version -> Preconditions.condition(version >= JRE.MINIMUM_VERSION, + () -> String.format("Version [%d] in @%s must be greater than or equal to %d", version, this.annotationName, + JRE.MINIMUM_VERSION))); + + return IntStream.concat(// + Arrays.stream(jres).mapToInt(JRE::version), // + Arrays.stream(versions) // + ).distinct(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreRangeCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreRangeCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreRangeCondition.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractJreRangeCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.condition; + +import static org.junit.jupiter.api.condition.AbstractJreCondition.DISABLED_ON_CURRENT_JRE; +import static org.junit.jupiter.api.condition.AbstractJreCondition.ENABLED_ON_CURRENT_JRE; + +import java.lang.annotation.Annotation; +import java.util.function.Function; + +import org.junit.platform.commons.util.Preconditions; + +/** + * Abstract base class for {@link EnabledForJreRangeCondition} and + * {@link DisabledForJreRangeCondition}. + * + * @since 5.12 + */ +abstract class AbstractJreRangeCondition extends BooleanExecutionCondition { + + private final String annotationName; + + AbstractJreRangeCondition(Class annotationType, Function customDisabledReason) { + super(annotationType, ENABLED_ON_CURRENT_JRE, DISABLED_ON_CURRENT_JRE, customDisabledReason); + this.annotationName = annotationType.getSimpleName(); + } + + protected final boolean isCurrentVersionWithinRange(JRE minJre, JRE maxJre, int minVersion, int maxVersion) { + boolean minJreSet = minJre != JRE.UNDEFINED; + boolean maxJreSet = maxJre != JRE.UNDEFINED; + boolean minVersionSet = minVersion != JRE.UNDEFINED_VERSION; + boolean maxVersionSet = maxVersion != JRE.UNDEFINED_VERSION; + + // Users must choose between JRE enum constants and version numbers. + Preconditions.condition(!minJreSet || !minVersionSet, () -> String.format( + "@%s's minimum value must be configured with either a JRE enum constant or numeric version, but not both", + this.annotationName)); + Preconditions.condition(!maxJreSet || !maxVersionSet, () -> String.format( + "@%s's maximum value must be configured with either a JRE enum constant or numeric version, but not both", + this.annotationName)); + + // Users must supply valid values for minVersion and maxVersion. + Preconditions.condition(!minVersionSet || (minVersion >= JRE.MINIMUM_VERSION), + () -> String.format("@%s's minVersion [%d] must be greater than or equal to %d", this.annotationName, + minVersion, JRE.MINIMUM_VERSION)); + Preconditions.condition(!maxVersionSet || (maxVersion >= JRE.MINIMUM_VERSION), + () -> String.format("@%s's maxVersion [%d] must be greater than or equal to %d", this.annotationName, + maxVersion, JRE.MINIMUM_VERSION)); + + // Now that we have checked the basic preconditions, we need to ensure that we are + // using valid JRE enum constants. + if (!minJreSet) { + minJre = JRE.JAVA_8; + } + if (!maxJreSet) { + maxJre = JRE.OTHER; + } + + int min = (minVersionSet ? minVersion : minJre.version()); + int max = (maxVersionSet ? maxVersion : maxJre.version()); + + // Finally, we need to validate the effective minimum and maximum values. + Preconditions.condition((min != JRE.MINIMUM_VERSION || max != Integer.MAX_VALUE), + () -> "You must declare a non-default value for the minimum or maximum value in @" + this.annotationName); + Preconditions.condition(min <= max, + () -> String.format("@%s's minimum value [%d] must be less than or equal to its maximum value [%d]", + this.annotationName, min, max)); + + return JRE.isCurrentVersionWithinRange(min, max); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractOsBasedExecutionCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractOsBasedExecutionCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractOsBasedExecutionCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractOsBasedExecutionCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.jupiter.api.condition; import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.annotation.Annotation; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractRepeatableAnnotationCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractRepeatableAnnotationCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractRepeatableAnnotationCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/AbstractRepeatableAnnotationCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.jupiter.api.condition; import static java.lang.String.format; -import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/BooleanExecutionCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/BooleanExecutionCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/BooleanExecutionCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/BooleanExecutionCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,7 +12,7 @@ import static org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled; import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.annotation.Annotation; import java.util.function.Function; @@ -23,31 +23,32 @@ abstract class BooleanExecutionCondition implements ExecutionCondition { - private final Class annotationType; + protected final Class annotationType; private final String enabledReason; private final String disabledReason; private final Function customDisabledReason; BooleanExecutionCondition(Class annotationType, String enabledReason, String disabledReason, Function customDisabledReason) { + this.annotationType = annotationType; this.enabledReason = enabledReason; this.disabledReason = disabledReason; this.customDisabledReason = customDisabledReason; } - abstract boolean isEnabled(A annotation); - @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { - return findAnnotation(context.getElement(), annotationType) // - .map(annotation -> isEnabled(annotation) ? enabled(enabledReason) - : disabled(disabledReason, customDisabledReason.apply(annotation))) // + return findAnnotation(context.getElement(), this.annotationType) // + .map(annotation -> isEnabled(annotation) ? enabled(this.enabledReason) + : disabled(this.disabledReason, this.customDisabledReason.apply(annotation))) // .orElseGet(this::enabledByDefault); } + abstract boolean isEnabled(A annotation); + private ConditionEvaluationResult enabledByDefault() { - String reason = String.format("@%s is not present", annotationType.getSimpleName()); + String reason = String.format("@%s is not present", this.annotationType.getSimpleName()); return enabled(reason); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -24,7 +25,11 @@ /** * {@code @DisabledForJreRange} is used to signal that the annotated test class * or test method is disabled for a specific range of Java Runtime - * Environment (JRE) versions from {@link #min} to {@link #max}. + * Environment (JRE) versions. + * + *

Version ranges can be specified as {@link JRE} enum constants via + * {@link #min min} and {@link #max max} or as integers via + * {@link #minVersion minVersion} and {@link #maxVersion maxVersion}. * *

When applied at the class level, all test methods within that class will * be disabled on the same specified JRE versions. @@ -82,28 +87,78 @@ public @interface DisabledForJreRange { /** - * Java Runtime Environment version which is used as the lower boundary - * for the version range that determines if the annotated class or method - * should be disabled. + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as a {@link JRE} enum constant. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the minimum version via + * {@link #minVersion() minVersion} instead. * - *

Defaults to {@link JRE#JAVA_8 JAVA_8}, as this is the lowest - * supported JRE version. + *

Defaults to {@link JRE#UNDEFINED UNDEFINED}, which will be interpreted + * as {@link JRE#JAVA_8 JAVA_8} if the {@link #minVersion() minVersion} is + * not set. * * @see JRE + * @see #minVersion() */ - JRE min() default JRE.JAVA_8; + JRE min() default JRE.UNDEFINED; /** - * Java Runtime Environment version which is used as the upper boundary - * for the version range that determines if the annotated class or method - * should be disabled. + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as a {@link JRE} enum constant. * - *

Defaults to {@link JRE#OTHER OTHER}, as this will always be the highest - * possible version. + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the maximum version via + * {@link #maxVersion() maxVersion} instead. + * + *

Defaults to {@link JRE#UNDEFINED UNDEFINED}, which will be interpreted + * as {@link JRE#OTHER OTHER} if the {@link #maxVersion() maxVersion} is not + * set. * * @see JRE + * @see #maxVersion() + */ + JRE max() default JRE.UNDEFINED; + + /** + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the minimum version via {@link #min() min} instead. + * + *

Defaults to {@code -1} to signal that {@link #min() min} should be used + * instead. + * + * @since 5.12 + * @see #min() + * @see JRE#version() + * @see Runtime.Version#feature() + */ + @API(status = MAINTAINED, since = "5.13.3") + int minVersion() default -1; + + /** + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the maximum version via {@link #max() max} instead. + * + *

Defaults to {@code -1} to signal that {@link #max() max} should be used + * instead. + * + * @since 5.12 + * @see #max() + * @see JRE#version() + * @see Runtime.Version#feature() */ - JRE max() default JRE.OTHER; + @API(status = MAINTAINED, since = "5.13.3") + int maxVersion() default -1; /** * Custom reason to provide if the test or container is disabled. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,11 +10,7 @@ package org.junit.jupiter.api.condition; -import static org.junit.jupiter.api.condition.EnabledOnJreCondition.DISABLED_ON_CURRENT_JRE; -import static org.junit.jupiter.api.condition.EnabledOnJreCondition.ENABLED_ON_CURRENT_JRE; - import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.util.Preconditions; /** * {@link ExecutionCondition} for {@link DisabledForJreRange @DisabledForJreRange}. @@ -22,24 +18,15 @@ * @since 5.6 * @see DisabledForJreRange */ -class DisabledForJreRangeCondition extends BooleanExecutionCondition { +class DisabledForJreRangeCondition extends AbstractJreRangeCondition { DisabledForJreRangeCondition() { - super(DisabledForJreRange.class, ENABLED_ON_CURRENT_JRE, DISABLED_ON_CURRENT_JRE, - DisabledForJreRange::disabledReason); + super(DisabledForJreRange.class, DisabledForJreRange::disabledReason); } @Override - boolean isEnabled(DisabledForJreRange annotation) { - JRE min = annotation.min(); - JRE max = annotation.max(); - - Preconditions.condition((min != JRE.JAVA_8 || max != JRE.OTHER), - "You must declare a non-default value for min or max in @DisabledForJreRange"); - Preconditions.condition(max.compareTo(min) >= 0, - "@DisabledForJreRange.min must be less than or equal to @DisabledForJreRange.max"); - - return !JRE.isCurrentVersionWithinRange(min, max); + boolean isEnabled(DisabledForJreRange range) { + return !isCurrentVersionWithinRange(range.min(), range.max(), range.minVersion(), range.maxVersion()); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -24,7 +25,10 @@ /** * {@code @DisabledOnJre} is used to signal that the annotated test class or * test method is disabled on one or more specified Java Runtime - * Environment (JRE) {@linkplain #value versions}. + * Environment (JRE) versions. + * + *

Versions can be specified as {@link JRE} enum constants via + * {@link #value() value} or as integers via {@link #versions() versions}. * *

When applied at the class level, all test methods within that class * will be disabled on the same specified JRE versions. @@ -82,12 +86,32 @@ public @interface DisabledOnJre { /** - * Java Runtime Environment versions on which the annotated class or - * method should be disabled. + * Java Runtime Environment versions on which the annotated class or method + * should be disabled, specified as {@link JRE} enum constants. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the version via {@link #versions() versions} + * instead. * * @see JRE + * @see #versions() + */ + JRE[] value() default {}; + + /** + * Java Runtime Environment versions on which the annotated class or method + * should be disabled, specified as integers. + * + *

If a {@code JRE} enum constant exists for a particular JRE version, you + * can specify the version via {@link #value() value} instead. + * + * @since 5.12 + * @see #value() + * @see JRE#version() + * @see Runtime.Version#feature() */ - JRE[] value(); + @API(status = MAINTAINED, since = "5.13.3") + int[] versions() default {}; /** * Custom reason to provide if the test or container is disabled. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,13 +10,7 @@ package org.junit.jupiter.api.condition; -import static org.junit.jupiter.api.condition.EnabledOnJreCondition.DISABLED_ON_CURRENT_JRE; -import static org.junit.jupiter.api.condition.EnabledOnJreCondition.ENABLED_ON_CURRENT_JRE; - -import java.util.Arrays; - import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.util.Preconditions; /** * {@link ExecutionCondition} for {@link DisabledOnJre @DisabledOnJre}. @@ -24,17 +18,15 @@ * @since 5.1 * @see DisabledOnJre */ -class DisabledOnJreCondition extends BooleanExecutionCondition { +class DisabledOnJreCondition extends AbstractJreCondition { DisabledOnJreCondition() { - super(DisabledOnJre.class, ENABLED_ON_CURRENT_JRE, DISABLED_ON_CURRENT_JRE, DisabledOnJre::disabledReason); + super(DisabledOnJre.class, DisabledOnJre::disabledReason); } @Override boolean isEnabled(DisabledOnJre annotation) { - JRE[] versions = annotation.value(); - Preconditions.condition(versions.length > 0, "You must declare at least one JRE in @DisabledOnJre"); - return Arrays.stream(versions).noneMatch(JRE::isCurrentVersion); + return validatedVersions(annotation.value(), annotation.versions()).noneMatch(JRE::isCurrentVersion); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOsCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOsCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOsCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOsCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -24,7 +25,11 @@ /** * {@code @EnabledForJreRange} is used to signal that the annotated test class or * test method is only enabled for a specific range of Java Runtime - * Environment (JRE) versions from {@link #min} to {@link #max}. + * Environment (JRE) versions. + * + *

Version ranges can be specified as {@link JRE} enum constants via + * {@link #min min} and {@link #max max} or as integers via + * {@link #minVersion minVersion} and {@link #maxVersion maxVersion}. * *

When applied at the class level, all test methods within that class will * be enabled on the same specified JRE versions. @@ -82,28 +87,78 @@ public @interface EnabledForJreRange { /** - * Java Runtime Environment version which should be used as the lower boundary - * for the version range that determines if the annotated class or method - * should be enabled. + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as a {@link JRE} enum constant. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the minimum version via + * {@link #minVersion() minVersion} instead. * - *

Defaults to {@link JRE#JAVA_8 JAVA_8}, as this is the lowest - * supported JRE version. + *

Defaults to {@link JRE#UNDEFINED UNDEFINED}, which will be interpreted + * as {@link JRE#JAVA_8 JAVA_8} if the {@link #minVersion() minVersion} is + * not set. * * @see JRE + * @see #minVersion() */ - JRE min() default JRE.JAVA_8; + JRE min() default JRE.UNDEFINED; /** - * Java Runtime Environment version which should be used as the upper boundary - * for the version range that determines if the annotated class or method - * should be enabled. + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as a {@link JRE} enum constant. * - *

Defaults to {@link JRE#OTHER OTHER}, as this will always be the highest - * possible version. + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the maximum version via + * {@link #maxVersion() maxVersion} instead. + * + *

Defaults to {@link JRE#UNDEFINED UNDEFINED}, which will be interpreted + * as {@link JRE#OTHER OTHER} if the {@link #maxVersion() maxVersion} is not + * set. * * @see JRE + * @see #maxVersion() + */ + JRE max() default JRE.UNDEFINED; + + /** + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the minimum version via {@link #min() min} instead. + * + *

Defaults to {@code -1} to signal that {@link #min() min} should be used + * instead. + * + * @since 5.12 + * @see #min() + * @see JRE#version() + * @see Runtime.Version#feature() + */ + @API(status = MAINTAINED, since = "5.13.3") + int minVersion() default -1; + + /** + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the maximum version via {@link #max() max} instead. + * + *

Defaults to {@code -1} to signal that {@link #max() max} should be used + * instead. + * + * @since 5.12 + * @see #max() + * @see JRE#version() + * @see Runtime.Version#feature() */ - JRE max() default JRE.OTHER; + @API(status = MAINTAINED, since = "5.13.3") + int maxVersion() default -1; /** * Custom reason to provide if the test or container is disabled. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,11 +10,7 @@ package org.junit.jupiter.api.condition; -import static org.junit.jupiter.api.condition.EnabledOnJreCondition.DISABLED_ON_CURRENT_JRE; -import static org.junit.jupiter.api.condition.EnabledOnJreCondition.ENABLED_ON_CURRENT_JRE; - import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.util.Preconditions; /** * {@link ExecutionCondition} for {@link EnabledForJreRange @EnabledForJreRange}. @@ -22,24 +18,15 @@ * @since 5.6 * @see EnabledForJreRange */ -class EnabledForJreRangeCondition extends BooleanExecutionCondition { +class EnabledForJreRangeCondition extends AbstractJreRangeCondition { EnabledForJreRangeCondition() { - super(EnabledForJreRange.class, ENABLED_ON_CURRENT_JRE, DISABLED_ON_CURRENT_JRE, - EnabledForJreRange::disabledReason); + super(EnabledForJreRange.class, EnabledForJreRange::disabledReason); } @Override - boolean isEnabled(EnabledForJreRange annotation) { - JRE min = annotation.min(); - JRE max = annotation.max(); - - Preconditions.condition((min != JRE.JAVA_8 || max != JRE.OTHER), - "You must declare a non-default value for min or max in @EnabledForJreRange"); - Preconditions.condition(max.compareTo(min) >= 0, - "@EnabledForJreRange.min must be less than or equal to @EnabledForJreRange.max"); - - return JRE.isCurrentVersionWithinRange(min, max); + boolean isEnabled(EnabledForJreRange range) { + return isCurrentVersionWithinRange(range.min(), range.max(), range.minVersion(), range.maxVersion()); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -23,8 +24,11 @@ /** * {@code @EnabledOnJre} is used to signal that the annotated test class or - * test method is only enabled on one or more specified Java - * Runtime Environment (JRE) {@linkplain #value versions}. + * test method is only enabled on one or more specified Java Runtime + * Environment (JRE) versions. + * + *

Versions can be specified as {@link JRE} enum constants via + * {@link #value() value} or as integers via {@link #versions() versions}. * *

When applied at the class level, all test methods within that class * will be enabled on the same specified JRE versions. @@ -82,12 +86,32 @@ public @interface EnabledOnJre { /** - * Java Runtime Environment versions on which the annotated class or - * method should be enabled. + * Java Runtime Environment versions on which the annotated class or method + * should be enabled, specified as {@link JRE} enum constants. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the version via {@link #versions() versions} + * instead. * * @see JRE + * @see #versions() + */ + JRE[] value() default {}; + + /** + * Java Runtime Environment versions on which the annotated class or method + * should be enabled, specified as integers. + * + *

If a {@code JRE} enum constant exists for a particular JRE version, you + * can specify the version via {@link #value() value} instead. + * + * @since 5.12 + * @see #value() + * @see JRE#version() + * @see Runtime.Version#feature() */ - JRE[] value(); + @API(status = MAINTAINED, since = "5.13.3") + int[] versions() default {}; /** * Custom reason to provide if the test or container is disabled. @@ -100,4 +124,5 @@ */ @API(status = STABLE, since = "5.7") String disabledReason() default ""; + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,7 @@ package org.junit.jupiter.api.condition; -import java.util.Arrays; - import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.util.Preconditions; /** * {@link ExecutionCondition} for {@link EnabledOnJre @EnabledOnJre}. @@ -21,23 +18,15 @@ * @since 5.1 * @see EnabledOnJre */ -class EnabledOnJreCondition extends BooleanExecutionCondition { - - static final String ENABLED_ON_CURRENT_JRE = // - "Enabled on JRE version: " + System.getProperty("java.version"); - - static final String DISABLED_ON_CURRENT_JRE = // - "Disabled on JRE version: " + System.getProperty("java.version"); +class EnabledOnJreCondition extends AbstractJreCondition { EnabledOnJreCondition() { - super(EnabledOnJre.class, ENABLED_ON_CURRENT_JRE, DISABLED_ON_CURRENT_JRE, EnabledOnJre::disabledReason); + super(EnabledOnJre.class, EnabledOnJre::disabledReason); } @Override boolean isEnabled(EnabledOnJre annotation) { - JRE[] versions = annotation.value(); - Preconditions.condition(versions.length > 0, "You must declare at least one JRE in @EnabledOnJre"); - return Arrays.stream(versions).anyMatch(JRE::isCurrentVersion); + return validatedVersions(annotation.value(), annotation.versions()).anyMatch(JRE::isCurrentVersion); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOsCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOsCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOsCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOsCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/MethodBasedCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/MethodBasedCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/MethodBasedCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/MethodBasedCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import static java.lang.String.format; import static org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled; import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -25,6 +25,7 @@ import org.junit.jupiter.api.extension.ExecutionCondition; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ClassLoaderUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; @@ -67,13 +68,13 @@ String className = methodParts[0]; String methodName = methodParts[1]; ClassLoader classLoader = ClassLoaderUtils.getClassLoader(testClass); - Class clazz = ReflectionUtils.tryToLoadClass(className, classLoader).getOrThrow( + Class clazz = ReflectionSupport.tryToLoadClass(className, classLoader).getOrThrow( cause -> new JUnitException(format("Could not load class [%s]", className), cause)); return findMethod(clazz, methodName); } private Method findMethod(Class clazz, String methodName) { - return ReflectionUtils.findMethod(clazz, methodName) // + return ReflectionSupport.findMethod(clazz, methodName) // .orElseGet(() -> ReflectionUtils.getRequiredMethod(clazz, methodName, ExtensionContext.class)); } @@ -85,9 +86,9 @@ Object testInstance = context.getTestInstance().orElse(null); if (method.getParameterCount() == 0) { - return (boolean) ReflectionUtils.invokeMethod(method, testInstance); + return (boolean) ReflectionSupport.invokeMethod(method, testInstance); } - return (boolean) ReflectionUtils.invokeMethod(method, testInstance, context); + return (boolean) ReflectionSupport.invokeMethod(method, testInstance, context); } private boolean acceptsExtensionContextOrNoArguments(Method method) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/OS.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/OS.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/OS.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/OS.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterAllCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterAllCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterAllCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterAllCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -34,8 +34,10 @@ *

JUnit Jupiter guarantees wrapping behavior for multiple * registered extensions that implement lifecycle callbacks such as * {@link BeforeAllCallback}, {@link AfterAllCallback}, - * {@link BeforeEachCallback}, {@link AfterEachCallback}, - * {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}. + * {@link BeforeClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. * *

That means that, given two extensions {@code Extension1} and * {@code Extension2} with {@code Extension1} registered before @@ -54,6 +56,8 @@ * @see AfterEachCallback * @see BeforeTestExecutionCallback * @see AfterTestExecutionCallback + * @see BeforeClassTemplateInvocationCallback + * @see AfterClassTemplateInvocationCallback */ @FunctionalInterface @API(status = STABLE, since = "5.0") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterClassTemplateInvocationCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterClassTemplateInvocationCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterClassTemplateInvocationCallback.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterClassTemplateInvocationCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.ClassTemplate; + +/** + * {@code AfterClassTemplateInvocationCallback} defines the API for + * {@link Extension Extensions} that wish to provide additional behavior + * once before each invocation of a + * {@link ClassTemplate @ClassTemplate}. + * + *

Concrete implementations often implement + * {@link BeforeClassTemplateInvocationCallback} as well. + * + *

Constructor Requirements

+ * + *

Consult the documentation in {@link Extension} for details on + * constructor requirements. + * + *

Wrapping Behavior

+ * + *

JUnit Jupiter guarantees wrapping behavior for multiple + * registered extensions that implement lifecycle callbacks such as + * {@link BeforeAllCallback}, {@link AfterAllCallback}, + * {@link AfterClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. + * + *

That means that, given two extensions {@code Extension1} and + * {@code Extension2} with {@code Extension1} registered before + * {@code Extension2}, any "before" callbacks implemented by {@code Extension1} + * are guaranteed to execute before any "before" callbacks implemented by + * {@code Extension2}. Similarly, given the two same two extensions registered + * in the same order, any "after" callbacks implemented by {@code Extension1} + * are guaranteed to execute after any "after" callbacks implemented by + * {@code Extension2}. {@code Extension1} is therefore said to wrap + * {@code Extension2}. + * + * @since 5.13 + * @see ClassTemplate + * @see BeforeClassTemplateInvocationCallback + * @see BeforeAllCallback + * @see AfterAllCallback + * @see BeforeEachCallback + * @see AfterEachCallback + * @see BeforeTestExecutionCallback + * @see AfterTestExecutionCallback + */ +@FunctionalInterface +@API(status = MAINTAINED, since = "5.13.3") +public interface AfterClassTemplateInvocationCallback extends Extension { + + /** + * Callback that is invoked after each invocation of a container + * template. + * + * @param context the current extension context; never {@code null} + */ + void afterClassTemplateInvocation(ExtensionContext context) throws Exception; + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterEachCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterEachCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterEachCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterEachCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -37,8 +37,10 @@ *

JUnit Jupiter guarantees wrapping behavior for multiple * registered extensions that implement lifecycle callbacks such as * {@link BeforeAllCallback}, {@link AfterAllCallback}, - * {@link BeforeEachCallback}, {@link AfterEachCallback}, - * {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}. + * {@link BeforeClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. * *

That means that, given two extensions {@code Extension1} and * {@code Extension2} with {@code Extension1} registered before @@ -57,6 +59,8 @@ * @see AfterTestExecutionCallback * @see BeforeAllCallback * @see AfterAllCallback + * @see BeforeClassTemplateInvocationCallback + * @see AfterClassTemplateInvocationCallback */ @FunctionalInterface @API(status = STABLE, since = "5.0") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterTestExecutionCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterTestExecutionCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterTestExecutionCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AfterTestExecutionCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -38,8 +38,10 @@ *

JUnit Jupiter guarantees wrapping behavior for multiple * registered extensions that implement lifecycle callbacks such as * {@link BeforeAllCallback}, {@link AfterAllCallback}, - * {@link BeforeEachCallback}, {@link AfterEachCallback}, - * {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}. + * {@link BeforeClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. * *

That means that, given two extensions {@code Extension1} and * {@code Extension2} with {@code Extension1} registered before @@ -58,6 +60,8 @@ * @see AfterEachCallback * @see BeforeAllCallback * @see AfterAllCallback + * @see BeforeClassTemplateInvocationCallback + * @see AfterClassTemplateInvocationCallback */ @FunctionalInterface @API(status = STABLE, since = "5.0") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AnnotatedElementContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AnnotatedElementContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AnnotatedElementContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/AnnotatedElementContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api.extension; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; @@ -33,7 +33,7 @@ * * @since 5.10 */ -@API(status = EXPERIMENTAL, since = "5.10") +@API(status = MAINTAINED, since = "5.13.3") public interface AnnotatedElementContext { /** @@ -55,6 +55,10 @@ * present or meta-present on the {@link AnnotatedElement} for * this context. * + *

Note: This method does not find repeatable annotations. + * To check for repeatable annotations, use {@link #findRepeatableAnnotations(Class)} + * and verify that the returned list is not empty. + * *

WARNING

*

Favor the use of this method over directly invoking * {@link AnnotatedElement#isAnnotationPresent(Class)} due to a bug in {@code javac} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeAllCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeAllCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeAllCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeAllCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -34,8 +34,10 @@ *

JUnit Jupiter guarantees wrapping behavior for multiple * registered extensions that implement lifecycle callbacks such as * {@link BeforeAllCallback}, {@link AfterAllCallback}, - * {@link BeforeEachCallback}, {@link AfterEachCallback}, - * {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}. + * {@link BeforeClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. * *

That means that, given two extensions {@code Extension1} and * {@code Extension2} with {@code Extension1} registered before @@ -54,6 +56,8 @@ * @see AfterEachCallback * @see BeforeTestExecutionCallback * @see AfterTestExecutionCallback + * @see BeforeClassTemplateInvocationCallback + * @see AfterClassTemplateInvocationCallback */ @FunctionalInterface @API(status = STABLE, since = "5.0") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeClassTemplateInvocationCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeClassTemplateInvocationCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeClassTemplateInvocationCallback.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeClassTemplateInvocationCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.ClassTemplate; + +/** + * {@code BeforeClassTemplateInvocationCallback} defines the API for + * {@link Extension Extensions} that wish to provide additional behavior + * once before each invocation of a + * {@link ClassTemplate @ClassTemplate}. + * + *

Concrete implementations often implement + * {@link AfterClassTemplateInvocationCallback} as well. + * + *

Constructor Requirements

+ * + *

Consult the documentation in {@link Extension} for details on + * constructor requirements. + * + *

Wrapping Behavior

+ * + *

JUnit Jupiter guarantees wrapping behavior for multiple + * registered extensions that implement lifecycle callbacks such as + * {@link BeforeAllCallback}, {@link AfterAllCallback}, + * {@link BeforeClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. + * + *

That means that, given two extensions {@code Extension1} and + * {@code Extension2} with {@code Extension1} registered before + * {@code Extension2}, any "before" callbacks implemented by {@code Extension1} + * are guaranteed to execute before any "before" callbacks implemented by + * {@code Extension2}. Similarly, given the two same two extensions registered + * in the same order, any "after" callbacks implemented by {@code Extension1} + * are guaranteed to execute after any "after" callbacks implemented by + * {@code Extension2}. {@code Extension1} is therefore said to wrap + * {@code Extension2}. + * + * @since 5.13 + * @see ClassTemplate + * @see AfterClassTemplateInvocationCallback + * @see BeforeAllCallback + * @see AfterAllCallback + * @see BeforeEachCallback + * @see AfterEachCallback + * @see BeforeTestExecutionCallback + * @see AfterTestExecutionCallback + */ +@FunctionalInterface +@API(status = MAINTAINED, since = "5.13.3") +public interface BeforeClassTemplateInvocationCallback extends Extension { + + /** + * Callback that is invoked before each invocation of a container + * template. + * + * @param context the current extension context; never {@code null} + */ + void beforeClassTemplateInvocation(ExtensionContext context) throws Exception; + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeEachCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeEachCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeEachCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeEachCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -37,8 +37,10 @@ *

JUnit Jupiter guarantees wrapping behavior for multiple * registered extensions that implement lifecycle callbacks such as * {@link BeforeAllCallback}, {@link AfterAllCallback}, - * {@link BeforeEachCallback}, {@link AfterEachCallback}, - * {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}. + * {@link BeforeClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. * *

That means that, given two extensions {@code Extension1} and * {@code Extension2} with {@code Extension1} registered before @@ -57,6 +59,8 @@ * @see AfterTestExecutionCallback * @see BeforeAllCallback * @see AfterAllCallback + * @see BeforeClassTemplateInvocationCallback + * @see AfterClassTemplateInvocationCallback */ @FunctionalInterface @API(status = STABLE, since = "5.0") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -38,8 +38,10 @@ *

JUnit Jupiter guarantees wrapping behavior for multiple * registered extensions that implement lifecycle callbacks such as * {@link BeforeAllCallback}, {@link AfterAllCallback}, - * {@link BeforeEachCallback}, {@link AfterEachCallback}, - * {@link BeforeTestExecutionCallback}, and {@link AfterTestExecutionCallback}. + * {@link BeforeClassTemplateInvocationCallback}, + * {@link AfterClassTemplateInvocationCallback}, {@link BeforeEachCallback}, + * {@link AfterEachCallback}, {@link BeforeTestExecutionCallback}, and + * {@link AfterTestExecutionCallback}. * *

That means that, given two extensions {@code Extension1} and * {@code Extension2} with {@code Extension1} registered before @@ -58,6 +60,8 @@ * @see AfterEachCallback * @see BeforeAllCallback * @see AfterAllCallback + * @see BeforeClassTemplateInvocationCallback + * @see AfterClassTemplateInvocationCallback */ @FunctionalInterface @API(status = STABLE, since = "5.0") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static java.util.Collections.emptyList; +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.List; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.ClassTemplate; + +/** + * {@code ClassTemplateInvocationContext} represents the context of + * a single invocation of a {@link ClassTemplate @ClassTemplate}. + * + *

Each context is provided by a + * {@link ClassTemplateInvocationContextProvider}. + * + * @since 5.13 + * @see ClassTemplate + * @see ClassTemplateInvocationContextProvider + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface ClassTemplateInvocationContext { + + /** + * Get the display name for this invocation. + * + *

The supplied {@code invocationIndex} is incremented by the framework + * with each container invocation. Thus, in the case of multiple active + * {@linkplain ClassTemplateInvocationContextProvider providers}, only the + * first active provider receives indices starting with {@code 1}. + * + *

The default implementation returns the supplied {@code invocationIndex} + * wrapped in brackets — for example, {@code [1]}, {@code [42]}, etc. + * + * @param invocationIndex the index of this invocation (1-based). + * @return the display name for this invocation; never {@code null} or blank + */ + default String getDisplayName(int invocationIndex) { + return "[" + invocationIndex + "]"; + } + + /** + * Get the additional {@linkplain Extension extensions} for this invocation. + * + *

The extensions provided by this method will only be used for this + * invocation of the class template. Thus, it does not make sense to return + * an extension that acts solely on the container level (e.g. + * {@link BeforeAllCallback}). + * + *

The default implementation returns an empty list. + * + * @return the additional extensions for this invocation; never {@code null} + * or containing {@code null} elements, but potentially empty + */ + default List getAdditionalExtensions() { + return emptyList(); + } + + /** + * Prepare the imminent invocation of the class template. + * + *

This may be used, for example, to store entries in the + * {@link ExtensionContext.Store Store} to benefit from its cleanup support + * or for retrieval by other extensions. + * + * @param context The invocation-level extension context. + */ + default void prepareInvocation(ExtensionContext context) { + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContextProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContextProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContextProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationContextProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,120 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.stream.Stream; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.ClassTemplate; + +/** + * {@code ClassTemplateInvocationContextProvider} defines the API for + * {@link Extension Extensions} that wish to provide one or multiple contexts + * for the invocation of a {@link ClassTemplate @ClassTemplate}. + * + *

This extension point makes it possible to execute a class template in + * different contexts — for example, with different parameters, by + * preparing the test class instance differently, or multiple times without + * modifying the context. + * + *

This interface defines two main methods: + * {@link #supportsClassTemplate} and + * {@link #provideClassTemplateInvocationContexts}. The former is called by the + * framework to determine whether this extension wants to act on a container + * template that is about to be executed. If so, the latter is called and must + * return a {@link Stream} of {@link ClassTemplateInvocationContext} instances. + * Otherwise, this provider is ignored for the execution of the current class + * template. + * + *

A provider that has returned {@code true} from its + * {@link #supportsClassTemplate} method is called active. When + * multiple providers are active for a class template, the + * {@code Streams} returned by their + * {@link #provideClassTemplateInvocationContexts} methods will be chained, and + * the class template method will be invoked using the contexts of all active + * providers. + * + *

An active provider may return zero invocation contexts from its + * {@link #provideClassTemplateInvocationContexts} method if it overrides + * {@link #mayReturnZeroClassTemplateInvocationContexts} to return + * {@code true}. + * + *

Constructor Requirements

+ * + *

Consult the documentation in {@link Extension} for details on + * constructor requirements. + * + * @since 5.13 + * @see ClassTemplate + * @see ClassTemplateInvocationContext + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface ClassTemplateInvocationContextProvider extends Extension { + + /** + * Determine if this provider supports providing invocation contexts for the + * class template represented by the supplied {@code context}. + * + * @param context the extension context for the class template + * about to be invoked; never {@code null} + * @return {@code true} if this provider can provide invocation contexts + * @see #provideClassTemplateInvocationContexts + * @see ExtensionContext + */ + boolean supportsClassTemplate(ExtensionContext context); + + /** + * Provide {@linkplain ClassTemplateInvocationContext invocation contexts} + * for the class template represented by the supplied {@code context}. + * + *

This method is only called by the framework if + * {@link #supportsClassTemplate} previously returned {@code true} for the + * same {@link ExtensionContext}; this method is allowed to return an empty + * {@code Stream} but not {@code null}. + * + *

The returned {@code Stream} will be properly closed by calling + * {@link Stream#close()}, making it safe to use a resource such as + * {@link java.nio.file.Files#lines(java.nio.file.Path) Files.lines()}. + * + * @param context the extension context for the class template about to be + * invoked; never {@code null} + * @return a {@code Stream} of {@code ClassTemplateInvocationContext} + * instances for the invocation of the class template; never {@code null} + * @throws TemplateInvocationValidationException if a validation fails when + * while providing or closing the {@link java.util.stream.Stream}. + * @see #supportsClassTemplate + * @see ExtensionContext + */ + Stream provideClassTemplateInvocationContexts(ExtensionContext context); + + /** + * Signal that this provider may provide zero + * {@linkplain ClassTemplateInvocationContext invocation contexts} for + * the class template represented by the supplied {@code context}. + * + *

If this method returns {@code false} (which is the default) and the + * provider returns an empty stream from + * {@link #provideClassTemplateInvocationContexts}, this will be considered + * an execution error. Override this method to return {@code true} to ignore + * the absence of invocation contexts for this provider. + * + * @param context the extension context for the class template + * about to be invoked; never {@code null} + * @return {@code true} to allow zero contexts, {@code false} to fail + * execution in case of zero contexts + */ + default boolean mayReturnZeroClassTemplateInvocationContexts(ExtensionContext context) { + return false; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationLifecycleMethod.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationLifecycleMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationLifecycleMethod.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ClassTemplateInvocationLifecycleMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; + +/** + * Internal marker annotation for lifecycle methods specific to implementations + * of {@link ClassTemplateInvocationContextProvider}. + * + * @since 5.13 + */ +@API(status = INTERNAL, since = "5.13") +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface ClassTemplateInvocationLifecycleMethod { + + /** + * The corresponding {@link org.junit.jupiter.api.ClassTemplate}-derived + * annotation class. + */ + Class classTemplateAnnotation(); + + /** + * The actual lifecycle method annotation class. + */ + Class lifecycleMethodAnnotation(); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ConditionEvaluationResult.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ConditionEvaluationResult.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ConditionEvaluationResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ConditionEvaluationResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -29,8 +29,11 @@ /** * Factory for creating enabled results. * - * @param reason the reason why the container or test should be enabled + * @param reason the reason why the container or test should be enabled; may + * be {@code null} or blank if the reason is unknown * @return an enabled {@code ConditionEvaluationResult} with the given reason + * or an empty reason if the reason is unknown + * @see StringUtils#isBlank(String) */ public static ConditionEvaluationResult enabled(String reason) { return new ConditionEvaluationResult(true, reason); @@ -39,8 +42,11 @@ /** * Factory for creating disabled results. * - * @param reason the reason why the container or test should be disabled + * @param reason the reason why the container or test should be disabled; may + * be {@code null} or blank if the reason is unknown * @return a disabled {@code ConditionEvaluationResult} with the given reason + * or an empty reason if the reason is unknown + * @see StringUtils#isBlank(String) */ public static ConditionEvaluationResult disabled(String reason) { return new ConditionEvaluationResult(false, reason); @@ -50,17 +56,27 @@ * Factory for creating disabled results with custom reasons * added by the user. * - * @param reason the default reason why the container or test should be disabled - * @param customReason the custom reason why the container or test should be disabled - * @return a disabled {@code ConditionEvaluationResult} with the given reasons + *

If non-blank default and custom reasons are provided, they will be + * concatenated using the format: "reason ==> customReason". + * + * @param reason the default reason why the container or test should be disabled; + * may be {@code null} or blank if the default reason is unknown + * @param customReason the custom reason why the container or test should be + * disabled; may be {@code null} or blank if the custom reason is unknown + * @return a disabled {@code ConditionEvaluationResult} with the given reason(s) + * or an empty reason if the reasons are unknown * @since 5.7 + * @see StringUtils#isBlank(String) */ @API(status = STABLE, since = "5.7") public static ConditionEvaluationResult disabled(String reason, String customReason) { + if (StringUtils.isBlank(reason)) { + return disabled(customReason); + } if (StringUtils.isBlank(customReason)) { return disabled(reason); } - return disabled(String.format("%s ==> %s", reason, customReason)); + return disabled(String.format("%s ==> %s", reason.trim(), customReason.trim())); } private final boolean enabled; @@ -69,7 +85,7 @@ private ConditionEvaluationResult(boolean enabled, String reason) { this.enabled = enabled; - this.reason = Optional.ofNullable(reason); + this.reason = StringUtils.isNotBlank(reason) ? Optional.of(reason.trim()) : Optional.empty(); } /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/DynamicTestInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/DynamicTestInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/DynamicTestInvocationContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/DynamicTestInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutableInvoker.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutableInvoker.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutableInvoker.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutableInvoker.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutionCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutionCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutionCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExecutionCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtendWith.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtendWith.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtendWith.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtendWith.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionConfigurationException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionConfigurationException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionConfigurationException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionConfigurationException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,15 @@ package org.junit.jupiter.api.extension; +import static java.util.Collections.unmodifiableList; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -24,7 +29,9 @@ import java.util.function.Function; import org.apiguardian.api.API; +import org.junit.jupiter.api.MediaType; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.function.ThrowingConsumer; import org.junit.jupiter.api.parallel.ExecutionMode; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.support.ReflectionSupport; @@ -37,6 +44,8 @@ *

{@link Extension Extensions} are provided an instance of * {@code ExtensionContext} to perform their work. * + *

This interface is not intended to be implemented by clients. + * * @since 5.0 * @see Store * @see Namespace @@ -127,6 +136,31 @@ Optional> getTestClass(); /** + * Get the enclosing test classes of the current test or container. + * + *

This method is useful to look up annotations on nested test classes + * and their enclosing runtime types: + * + *

{@code
+	 * AnnotationSupport.findAnnotation(
+	 *     extensionContext.getRequiredTestClass(),
+	 *     MyAnnotation.class,
+	 *     extensionContext.getEnclosingTestClasses()
+	 * );
+	 * }
+ * + * @return an empty list if there is no class associated with the current + * test or container or when it is not nested; otherwise, a list containing + * the enclosing test classes in order from outermost to innermost; never + * {@code null} + * + * @since 5.12.1 + * @see org.junit.platform.commons.support.AnnotationSupport#findAnnotation(Class, Class, List) + */ + @API(status = MAINTAINED, since = "5.13.3") + List> getEnclosingTestClasses(); + + /** * Get the required {@link Class} associated with the current test * or container. * @@ -365,6 +399,69 @@ } /** + * Publish a file with the supplied name written by the supplied action and + * attach it to the current test or container. + * + *

The file will be resolved in the report output directory prior to + * invoking the supplied action. + * + * @param name the name of the file to be published; never {@code null} or + * blank and must not contain any path separators + * @param mediaType the media type of the file; never {@code null}; use + * {@link org.junit.jupiter.api.extension.MediaType#APPLICATION_OCTET_STREAM} + * if unknown + * @param action the action to be executed to write the file; never {@code null} + * @since 5.12 + * @see org.junit.platform.engine.EngineExecutionListener#fileEntryPublished + * @deprecated Use + * {@link #publishFile(String, MediaType, ThrowingConsumer)} + * instead. + */ + @Deprecated + @API(status = DEPRECATED, since = "5.14") + default void publishFile(String name, org.junit.jupiter.api.extension.MediaType mediaType, + ThrowingConsumer action) { + + Preconditions.notNull(mediaType, "mediaType must not be null"); + publishFile(name, MediaType.parse(mediaType.toString()), action); + } + + /** + * Publish a file with the supplied name written by the supplied action and + * attach it to the current test or container. + * + *

The file will be resolved in the report output directory prior to + * invoking the supplied action. + * + * @param name the name of the file to be attached; never {@code null} or + * blank and must not contain any path separators + * @param mediaType the media type of the file; never {@code null}; use + * {@link MediaType#APPLICATION_OCTET_STREAM} if unknown + * @param action the action to be executed to write the file; never {@code null} + * @since 5.14 + * @see org.junit.platform.engine.EngineExecutionListener#fileEntryPublished + */ + @API(status = MAINTAINED, since = "5.14") + void publishFile(String name, MediaType mediaType, ThrowingConsumer action); + + /** + * Publish a directory with the supplied name written by the supplied action + * and attach it to the current test or container. + * + *

The directory will be resolved and created in the report output directory + * prior to invoking the supplied action, if it does not already exist. + * + * @param name the name of the directory to be published; never {@code null} + * or blank and must not contain any path separators + * @param action the action to be executed to write to the directory; never + * {@code null} + * @since 5.12 + * @see org.junit.platform.engine.EngineExecutionListener#fileEntryPublished + */ + @API(status = MAINTAINED, since = "5.13.3") + void publishDirectory(String name, ThrowingConsumer action); + + /** * Get the {@link Store} for the supplied {@link Namespace}. * *

Use {@code getStore(Namespace.GLOBAL)} to get the default, global {@link Namespace}. @@ -378,10 +475,29 @@ * @return the store in which to put and get objects for other invocations * working in the same namespace; never {@code null} * @see Namespace#GLOBAL + * @see #getStore(StoreScope, Namespace) */ Store getStore(Namespace namespace); /** + * Returns the store for supplied scope and namespace. + * + *

If {@code scope} is + * {@link StoreScope#EXTENSION_CONTEXT EXTENSION_CONTEXT}, the store behaves + * exactly like the one returned by {@link #getStore(Namespace)}. If the + * {@code scope} is {@link StoreScope#LAUNCHER_SESSION LAUNCHER_SESSION} or + * {@link StoreScope#EXECUTION_REQUEST EXECUTION_REQUEST}, all stored values + * that are instances of {@link AutoCloseable} are notified by invoking + * their {@code close()} methods when the scope is closed. + * + * @since 5.13 + * @see StoreScope + * @see #getStore(Namespace) + */ + @API(status = MAINTAINED, since = "5.13.3") + Store getStore(StoreScope scope, Namespace namespace); + + /** * Get the {@link ExecutionMode} associated with the current test or container. * * @return the {@code ExecutionMode} of the test; never {@code null} @@ -418,8 +534,10 @@ * inverse order they were added in. * * @since 5.1 + * @deprecated Please extend {@code AutoCloseable} directly. */ - @API(status = STABLE, since = "5.1") + @Deprecated + @API(status = DEPRECATED, since = "5.13") interface CloseableResource { /** @@ -510,9 +628,11 @@ *

See {@link #getOrComputeIfAbsent(Object, Function, Class)} for * further details. * - *

If {@code type} implements {@link ExtensionContext.Store.CloseableResource} - * the {@code close()} method will be invoked on the stored object when - * the store is closed. + *

If {@code type} implements {@link CloseableResource} or + * {@link AutoCloseable} (unless the + * {@code junit.jupiter.extensions.store.close.autocloseable.enabled} + * configuration parameter is set to {@code false}), then the {@code close()} + * method will be invoked on the stored object when the store is closed. * * @param type the type of object to retrieve; never {@code null} * @param the key and value type @@ -521,6 +641,7 @@ * @see #getOrComputeIfAbsent(Object, Function) * @see #getOrComputeIfAbsent(Object, Function, Class) * @see CloseableResource + * @see AutoCloseable */ @API(status = STABLE, since = "5.1") default V getOrComputeIfAbsent(Class type) { @@ -540,9 +661,11 @@ *

For greater type safety, consider using * {@link #getOrComputeIfAbsent(Object, Function, Class)} instead. * - *

If the created value is an instance of {@link ExtensionContext.Store.CloseableResource} - * the {@code close()} method will be invoked on the stored object when - * the store is closed. + *

If the created value is an instance of {@link CloseableResource} or + * {@link AutoCloseable} (unless the + * {@code junit.jupiter.extensions.store.close.autocloseable.enabled} + * configuration parameter is set to {@code false}), then the {@code close()} + * method will be invoked on the stored object when the store is closed. * * @param key the key; never {@code null} * @param defaultCreator the function called with the supplied {@code key} @@ -553,6 +676,7 @@ * @see #getOrComputeIfAbsent(Class) * @see #getOrComputeIfAbsent(Object, Function, Class) * @see CloseableResource + * @see AutoCloseable */ Object getOrComputeIfAbsent(K key, Function defaultCreator); @@ -567,9 +691,11 @@ * a new value will be computed by the {@code defaultCreator} (given * the {@code key} as input), stored, and returned. * - *

If {@code requiredType} implements {@link ExtensionContext.Store.CloseableResource} - * the {@code close()} method will be invoked on the stored object when - * the store is closed. + *

If {@code requiredType} implements {@link CloseableResource} or + * {@link AutoCloseable} (unless the + * {@code junit.jupiter.extensions.store.close.autocloseable.enabled} + * configuration parameter is set to {@code false}), then the {@code close()} + * method will be invoked on the stored object when the store is closed. * * @param key the key; never {@code null} * @param defaultCreator the function called with the supplied {@code key} @@ -581,6 +707,7 @@ * @see #getOrComputeIfAbsent(Class) * @see #getOrComputeIfAbsent(Object, Function) * @see CloseableResource + * @see AutoCloseable */ V getOrComputeIfAbsent(K key, Function defaultCreator, Class requiredType); @@ -591,14 +718,17 @@ * ExtensionContexts} for the store's {@code Namespace} unless they * overwrite it. * - *

If the {@code value} is an instance of {@link ExtensionContext.Store.CloseableResource} - * the {@code close()} method will be invoked on the stored object when - * the store is closed. + *

If the {@code value} is an instance of {@link CloseableResource} or + * {@link AutoCloseable} (unless the + * {@code junit.jupiter.extensions.store.close.autocloseable.enabled} + * configuration parameter is set to {@code false}), then the {@code close()} + * method will be invoked on the stored object when the store is closed. * * @param key the key under which the value should be stored; never * {@code null} * @param value the value to store; may be {@code null} * @see CloseableResource + * @see AutoCloseable */ void put(Object key, Object value); @@ -606,8 +736,8 @@ * Remove the value that was previously stored under the supplied {@code key}. * *

The value will only be removed in the current {@link ExtensionContext}, - * not in ancestors. In addition, the {@link CloseableResource} API will not - * be honored for values that are manually removed via this method. + * not in ancestors. In addition, the {@link CloseableResource} and {@link AutoCloseable} + * API will not be honored for values that are manually removed via this method. * *

For greater type safety, consider using {@link #remove(Object, Class)} * instead. @@ -624,8 +754,8 @@ * under the supplied {@code key}. * *

The value will only be removed in the current {@link ExtensionContext}, - * not in ancestors. In addition, the {@link CloseableResource} API will not - * be honored for values that are manually removed via this method. + * not in ancestors. In addition, the {@link CloseableResource} and {@link AutoCloseable} + * API will not be honored for values that are manually removed via this method. * * @param key the key; never {@code null} * @param requiredType the required type of the value; never {@code null} @@ -707,6 +837,57 @@ Collections.addAll(newParts, parts); return new Namespace(newParts); } + + @API(status = INTERNAL, since = "5.13") + public List getParts() { + return unmodifiableList(parts); + } + } + + /** + * {@code StoreScope} is an enumeration of the different scopes for + * {@link Store} instances. + * + * @since 5.13 + * @see #getStore(StoreScope, Namespace) + */ + @API(status = MAINTAINED, since = "5.13.3") + enum StoreScope { + + /** + * The store is scoped to the current {@code LauncherSession}. + * + *

Any data that is stored in a {@code Store} with this scope will be + * available throughout the entire launcher session. Therefore, it may + * be used to inject values from registered + * {@code LauncherSessionListener} implementations, to share data across + * multiple executions of the Jupiter engine within the same session, or + * even to share data across multiple engines. + * + * @see org.junit.platform.launcher.LauncherSession#getStore() + * @see org.junit.platform.launcher.LauncherSessionListener + */ + LAUNCHER_SESSION, + + /** + * The store is scoped to the current {@code ExecutionRequest} of the + * JUnit Platform {@code Launcher}. + * + *

Any data that is stored in a {@code Store} with this scope will be + * available for the duration of the current execution request. + * Therefore, it may be used to share data across multiple engines. + * + * @see org.junit.platform.engine.ExecutionRequest#getStore() + */ + EXECUTION_REQUEST, + + /** + * The store is scoped to the current {@code ExtensionContext}. + * + *

Any data that is stored in a {@code Store} with this scope will be + * bound to the current extension context lifecycle. + */ + EXTENSION_CONTEXT } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContextException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContextException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContextException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ExtensionContextException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api.extension; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; @@ -33,7 +33,7 @@ super(message); } - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") public ExtensionContextException(String message, Throwable cause) { super(message, cause); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/InvocationInterceptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/InvocationInterceptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/InvocationInterceptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/InvocationInterceptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -24,6 +24,7 @@ import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestTemplate; /** @@ -44,13 +45,23 @@ *

Consult the documentation in {@link Extension} for details on * constructor requirements. * + *

{@code ExtensionContext} Scope

+ * + *

As of JUnit Jupiter 5.12, this API participates in the + * {@link TestInstantiationAwareExtension} contract. Implementations of this API + * may therefore choose to override + * {@link TestInstantiationAwareExtension#getTestInstantiationExtensionContextScope(ExtensionContext) + * getTestInstantiationExtensionContextScope(ExtensionContext)}. See + * {@link #interceptTestClassConstructor(Invocation, ReflectiveInvocationContext, ExtensionContext)} + * for details. + * * @since 5.5 * @see Invocation * @see ReflectiveInvocationContext * @see ExtensionContext */ @API(status = STABLE, since = "5.10") -public interface InvocationInterceptor extends Extension { +public interface InvocationInterceptor extends TestInstantiationAwareExtension { /** * Intercept the invocation of a test class constructor. @@ -58,6 +69,16 @@ *

Note that the test class may not have been initialized * (static initialization) when this method is invoked. * + *

By default, the supplied {@link ExtensionContext} represents the test + * class that's about to be constructed. Extensions may override + * {@link #getTestInstantiationExtensionContextScope} to return + * {@link ExtensionContextScope#TEST_METHOD TEST_METHOD} in order to change + * the scope of the {@code ExtensionContext} to the test method, unless the + * {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used. + * Changing the scope makes test-specific data available to the + * implementation of this method and allows keeping state on the test level + * by using the provided {@link ExtensionContext.Store Store} instance. + * * @param invocation the invocation that is being intercepted; never * {@code null} * @param invocationContext the context of the invocation that is being diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/MediaType.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/MediaType.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/MediaType.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/MediaType.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,121 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apiguardian.api.API.Status.DEPRECATED; + +import java.nio.charset.Charset; +import java.nio.file.Path; + +import org.apiguardian.api.API; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.Preconditions; + +/** + * Represents a media type as defined by + * RFC 2045. + * + * @since 5.12 + * @see org.junit.jupiter.api.TestReporter#publishFile(Path, MediaType) + * @see org.junit.jupiter.api.TestReporter#publishFile(String, MediaType, org.junit.jupiter.api.function.ThrowingConsumer) + * @see ExtensionContext#publishFile(String, MediaType, org.junit.jupiter.api.function.ThrowingConsumer) + * @deprecated Use {@link org.junit.jupiter.api.MediaType} instead. + */ +@Deprecated +@API(status = DEPRECATED, since = "5.14") +public class MediaType extends org.junit.jupiter.api.MediaType { + + /** + * The {@code text/plain} media type. + */ + public static final MediaType TEXT_PLAIN = create("text", "plain"); + + /** + * The {@code text/plain; charset=UTF-8} media type. + */ + public static final MediaType TEXT_PLAIN_UTF_8 = create("text", "plain", UTF_8); + + /** + * The {@code application/json} media type. + */ + public static final MediaType APPLICATION_JSON = create("application", "json"); + + /** + * The {@code application/json; charset=UTF-8} media type. + * @deprecated Use {@link #APPLICATION_JSON} instead. + */ + @Deprecated + @API(status = DEPRECATED, since = "5.14") + public static final MediaType APPLICATION_JSON_UTF_8 = create("application", "json", UTF_8); + + /** + * The {@code application/octet-stream} media type. + */ + public static final MediaType APPLICATION_OCTET_STREAM = create("application", "octet-stream"); + + /** + * The {@code image/jpeg} media type. + */ + public static final MediaType IMAGE_JPEG = create("image", "jpeg"); + + /** + * The {@code image/png} media type. + */ + public static final MediaType IMAGE_PNG = create("image", "png"); + + /** + * Parse the given media type value. + * + *

Must be valid according to + * RFC 2045. + * + * @param value the media type value to parse; never {@code null} or blank + * @return the parsed media type + * @throws PreconditionViolationException if the value is not a valid media type + */ + public static MediaType parse(String value) { + return new MediaType(value); + } + + /** + * Create a media type with the given type and subtype. + * + * @param type the type; never {@code null} or blank + * @param subtype the subtype; never {@code null} or blank + * @return the media type + */ + public static MediaType create(String type, String subtype) { + return new MediaType(type, subtype, null); + } + + /** + * Create a media type with the given type, subtype, and charset. + * + * @param type the type; never {@code null} or blank + * @param subtype the subtype; never {@code null} or blank + * @param charset the charset; never {@code null} + * @return the media type + */ + public static MediaType create(String type, String subtype, Charset charset) { + Preconditions.notNull(charset, "charset must not be null"); + return new MediaType(type, subtype, charset); + } + + private MediaType(String type, String subtype, Charset charset) { + super(type, subtype, charset); + } + + private MediaType(String value) { + super(value); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api.extension; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Annotation; @@ -94,7 +94,7 @@ * {@inheritDoc} * @since 5.10 */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") @Override default AnnotatedElement getAnnotatedElement() { return getParameter(); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolutionException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolutionException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolutionException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolutionException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,6 +15,7 @@ import java.lang.reflect.Parameter; import org.apiguardian.api.API; +import org.junit.jupiter.api.TestInstance; /** * {@code ParameterResolver} defines the API for {@link Extension Extensions} @@ -30,11 +31,31 @@ * an argument for the parameter must be resolved at runtime by a * {@code ParameterResolver}. * + *

By default, when the methods in this interface are called for a test class + * constructor, the supplied {@link ExtensionContext} represents the test + * class that's about to be instantiated. Extensions may override + * {@link #getTestInstantiationExtensionContextScope} to return + * {@link ExtensionContextScope#TEST_METHOD TEST_METHOD} in order to change + * the scope of the {@code ExtensionContext} to the test method, unless the + * {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used. + * Changing the scope makes test-specific data available to the + * implementation of this method and allows keeping state on the test level + * by using the provided {@link ExtensionContext.Store Store} instance. + * *

Constructor Requirements

* *

Consult the documentation in {@link Extension} for details on * constructor requirements. * + *

{@code ExtensionContext} Scope

+ * + *

As of JUnit Jupiter 5.12, this API participates in the + * {@link TestInstantiationAwareExtension} contract. Implementations of this API + * may therefore choose to override + * {@link TestInstantiationAwareExtension#getTestInstantiationExtensionContextScope(ExtensionContext) + * getTestInstantiationExtensionContextScope(ExtensionContext)} to require a + * test-method scoped {@code ExtensionContext}. + * * @since 5.0 * @see #supportsParameter(ParameterContext, ExtensionContext) * @see #resolveParameter(ParameterContext, ExtensionContext) @@ -44,7 +65,7 @@ * @see TestInstancePreDestroyCallback */ @API(status = STABLE, since = "5.0") -public interface ParameterResolver extends Extension { +public interface ParameterResolver extends TestInstantiationAwareExtension { /** * Determine if this resolver supports resolution of an argument for the diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptCallback.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; + +/** + * {@code PreInterruptCallback} defines the API for {@link Extension + * Extensions} that wish to be called prior to invocations of + * {@link Thread#interrupt()} by the {@link org.junit.jupiter.api.Timeout} + * extension. + * + *

JUnit registers a default implementation that dumps the stacks of all + * {@linkplain Thread threads} to {@code System.out} if the + * {@value #THREAD_DUMP_ENABLED_PROPERTY_NAME} configuration parameter is set to + * {@code true}. + * + * @since 5.12 + * @see org.junit.jupiter.api.Timeout + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface PreInterruptCallback extends Extension { + + /** + * Property name used to enable dumping the stack of all + * {@linkplain Thread threads} to {@code System.out} when a timeout has occurred. + * + *

This behavior is disabled by default. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + String THREAD_DUMP_ENABLED_PROPERTY_NAME = "junit.jupiter.execution.timeout.threaddump.enabled"; + + /** + * Callback that is invoked before a {@link Thread} is interrupted with + * {@link Thread#interrupt()}. + * + *

Note: There is no guarantee on which {@link Thread} this callback will be + * executed. + * + * @param preInterruptContext the context with the target {@link Thread}, which will get interrupted. + * @param extensionContext the extension context for the callback; never {@code null} + * @since 5.12 + * @see PreInterruptContext + */ + @API(status = MAINTAINED, since = "5.13.3") + void beforeThreadInterrupt(PreInterruptContext preInterruptContext, ExtensionContext extensionContext) + throws Exception; +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/PreInterruptContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; + +/** + * {@code PreInterruptContext} encapsulates the context in which an + * {@link PreInterruptCallback#beforeThreadInterrupt(PreInterruptContext, ExtensionContext) beforeThreadInterrupt} method is called. + * + * @since 5.12 + * @see PreInterruptCallback + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface PreInterruptContext { + + /** + * Get the {@link Thread} which will be interrupted. + * + * @return the Thread; never {@code null} + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + Thread getThreadToInterrupt(); +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ReflectiveInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ReflectiveInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ReflectiveInvocationContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ReflectiveInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/RegisterExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/RegisterExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/RegisterExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/RegisterExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TemplateInvocationValidationException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TemplateInvocationValidationException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TemplateInvocationValidationException.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TemplateInvocationValidationException.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; +import org.junit.platform.commons.JUnitException; + +/** + * {@code TemplateInvocationValidationException} is an exception thrown by a + * {@link TestTemplateInvocationContextProvider} or + * {@link ClassTemplateInvocationContextProvider} if a validation fails when + * while providing or closing {@link java.util.stream.Stream} of invocation + * contexts. + * + * @since 5.13 + */ +@API(status = MAINTAINED, since = "5.13.3") +public class TemplateInvocationValidationException extends JUnitException { + + private static final long serialVersionUID = 1L; + + public TemplateInvocationValidationException(String message) { + super(message); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; +import org.junit.jupiter.api.TestInstance; /** * {@code TestInstanceFactory} defines the API for {@link Extension @@ -42,6 +43,17 @@ *

Consult the documentation in {@link Extension} for details on * constructor requirements. * + *

{@code ExtensionContext} Scope

+ * + *

As of JUnit Jupiter 5.12, this API participates in the + * {@link TestInstantiationAwareExtension} contract. Implementations of this API + * may therefore choose to override + * {@link TestInstantiationAwareExtension#getTestInstantiationExtensionContextScope(ExtensionContext) + * getTestInstantiationExtensionContextScope(ExtensionContext)} to require a + * test-method scoped {@code ExtensionContext}. See + * {@link #createTestInstance(TestInstanceFactoryContext, ExtensionContext)} for + * further details. + * * @since 5.3 * @see #createTestInstance(TestInstanceFactoryContext, ExtensionContext) * @see TestInstanceFactoryContext @@ -51,11 +63,21 @@ */ @FunctionalInterface @API(status = STABLE, since = "5.7") -public interface TestInstanceFactory extends Extension { +public interface TestInstanceFactory extends TestInstantiationAwareExtension { /** * Callback for creating a test instance for the supplied context. * + *

By default, the supplied {@link ExtensionContext} represents the test + * class that's about to be instantiated. Extensions may override + * {@link #getTestInstantiationExtensionContextScope} to return + * {@link ExtensionContextScope#TEST_METHOD TEST_METHOD} in order to change + * the scope of the {@code ExtensionContext} to the test method, unless the + * {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used. + * Changing the scope makes test-specific data available to the + * implementation of this method and allows keeping state on the test level + * by using the provided {@link ExtensionContext.Store Store} instance. + * *

Note: the {@code ExtensionContext} supplied to a * {@code TestInstanceFactory} will always return an empty * {@link java.util.Optional} value from diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactoryContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactoryContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactoryContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactoryContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePostProcessor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePostProcessor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePostProcessor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePostProcessor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; +import org.junit.jupiter.api.TestInstance; /** * {@code TestInstancePostProcessor} defines the API for {@link Extension @@ -32,6 +33,16 @@ *

Consult the documentation in {@link Extension} for details on * constructor requirements. * + *

{@code ExtensionContext} Scope

+ * + *

As of JUnit Jupiter 5.12, this API participates in the + * {@link TestInstantiationAwareExtension} contract. Implementations of this API + * may therefore choose to override + * {@link TestInstantiationAwareExtension#getTestInstantiationExtensionContextScope(ExtensionContext) + * getTestInstantiationExtensionContextScope(ExtensionContext)} to require a + * test-method scoped {@code ExtensionContext}. See + * {@link #postProcessTestInstance(Object, ExtensionContext)} for further details. + * * @since 5.0 * @see #postProcessTestInstance(Object, ExtensionContext) * @see TestInstancePreDestroyCallback @@ -40,11 +51,21 @@ */ @FunctionalInterface @API(status = STABLE, since = "5.0") -public interface TestInstancePostProcessor extends Extension { +public interface TestInstancePostProcessor extends TestInstantiationAwareExtension { /** * Callback for post-processing the supplied test instance. * + *

By default, the supplied {@link ExtensionContext} represents the test + * class that's being post-processed. Extensions may override + * {@link #getTestInstantiationExtensionContextScope} to return + * {@link ExtensionContextScope#TEST_METHOD TEST_METHOD} in order to change + * the scope of the {@code ExtensionContext} to the test method, unless the + * {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used. + * Changing the scope makes test-specific data available to the + * implementation of this method and allows keeping state on the test level + * by using the provided {@link ExtensionContext.Store Store} instance. + * *

Note: the {@code ExtensionContext} supplied to a * {@code TestInstancePostProcessor} will always return an empty * {@link java.util.Optional} value from {@link ExtensionContext#getTestInstance() diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreConstructCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreConstructCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreConstructCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreConstructCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; /** @@ -37,6 +38,17 @@ *

Consult the documentation in {@link Extension} for details on constructor * requirements. * + *

{@code ExtensionContext} Scope

+ * + *

As of JUnit Jupiter 5.12, this API participates in the + * {@link TestInstantiationAwareExtension} contract. Implementations of this API + * may therefore choose to override + * {@link TestInstantiationAwareExtension#getTestInstantiationExtensionContextScope(ExtensionContext) + * getTestInstantiationExtensionContextScope(ExtensionContext)} to require a + * test-method scoped {@code ExtensionContext}. See + * {@link #preConstructTestInstance(TestInstanceFactoryContext, ExtensionContext)} + * for further details. + * * @since 5.9 * @see TestInstancePreDestroyCallback * @see TestInstanceFactory @@ -44,11 +56,21 @@ */ @FunctionalInterface @API(status = STABLE, since = "5.11") -public interface TestInstancePreConstructCallback extends Extension { +public interface TestInstancePreConstructCallback extends TestInstantiationAwareExtension { /** * Callback invoked prior to test instances being constructed. * + *

By default, the supplied {@link ExtensionContext} represents the test + * class that's about to be constructed. Extensions may override + * {@link #getTestInstantiationExtensionContextScope} to return + * {@link ExtensionContextScope#TEST_METHOD TEST_METHOD} in order to change + * the scope of the {@code ExtensionContext} to the test method, unless the + * {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used. + * Changing the scope makes test-specific data available to the + * implementation of this method and allows keeping state on the test level + * by using the provided {@link ExtensionContext.Store Store} instance. + * * @param factoryContext the context for the test instance about to be instantiated; * never {@code null} * @param context the current extension context; never {@code null} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreDestroyCallback.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreDestroyCallback.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreDestroyCallback.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePreDestroyCallback.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstances.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstances.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstances.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstances.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationAwareExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,190 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; + +/** + * {@code TestInstantiationAwareExtension} defines the API for {@link Extension + * Extensions} that are aware of or influence the instantiation of test classes. + * + *

This interface is not intended to be implemented directly. Instead, extensions + * should implement one of the sub-interfaces listed below. + * + *

    + *
  • {@link InvocationInterceptor}
  • + *
  • {@link ParameterResolver}
  • + *
  • {@link TestInstancePreConstructCallback}
  • + *
  • {@link TestInstancePostProcessor}
  • + *
  • {@link TestInstanceFactory}
  • + *
+ * + *

See {@link #getTestInstantiationExtensionContextScope(ExtensionContext)} for + * further details. + * + * @since 5.12 + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface TestInstantiationAwareExtension extends Extension { + + /** + * Determine whether this extension should receive a test-method scoped + * {@link ExtensionContext} during the instantiation of test classes or + * processing of test instances. + * + *

If an extension returns {@link ExtensionContextScope#TEST_METHOD TEST_METHOD} + * from this method, methods defined in the following extension APIs will be + * called with a test-method scoped {@code ExtensionContext} instead of a + * test-class scoped context. Note, however, that a test-class scoped context + * will always be supplied if the + * {@link org.junit.jupiter.api.TestInstance.Lifecycle#PER_CLASS PER_CLASS} + * test instance lifecycle is used. + * + *

    + *
  • {@link InvocationInterceptor}: only the + * {@link InvocationInterceptor#interceptTestClassConstructor + * interceptTestClassConstructor(...)} method
  • + *
  • {@link ParameterResolver}: only when resolving constructor parameters
  • + *
  • {@link TestInstancePreConstructCallback}
  • + *
  • {@link TestInstancePostProcessor}
  • + *
  • {@link TestInstanceFactory}
  • + *
+ * + *

When a test-method scoped {@code ExtensionContext} is supplied, implementations + * of the above extension APIs will observe the following differences. + * + *

    + *
  • + * {@link ExtensionContext#getElement() getElement()} may refer to the + * test method. + *
  • + *
  • + * {@link ExtensionContext#getTestClass() getTestClass()} may refer to a + * nested test class. + *
      + *
    • + * For {@link TestInstancePostProcessor}, use {@code testInstance.getClass()} + * to get the test class associated with the supplied instance. + *
    • + *
    • + * For {@link TestInstanceFactory} and {@link TestInstancePreConstructCallback}, + * use {@link TestInstanceFactoryContext#getTestClass()} to get the + * class under construction. + *
    • + *
    • + * For {@link ParameterResolver}, when resolving a parameter for a + * constructor, ensure that the + * {@link ParameterContext#getDeclaringExecutable() Executable} is a + * {@link java.lang.reflect.Constructor Constructor}, and then use + * {@code constructor.getDeclaringClass()} to get the test class + * associated with the constructor. + *
    • + *
    + *
  • + *
  • + * {@link ExtensionContext#getTestMethod() getTestMethod()} is no longer + * empty, unless the + * {@link org.junit.jupiter.api.TestInstance.Lifecycle#PER_CLASS PER_CLASS} + * test instance lifecycle is used. + *
  • + *
  • + * If the extension adds a {@link ExtensionContext.Store.CloseableResource + * CloseableResource} or {@link AutoCloseable} to the + * {@link ExtensionContext.Store Store} (unless the + * {@code junit.jupiter.extensions.store.close.autocloseable.enabled} + * configuration parameter is set to {@code false}), then the resource will + * be closed just after the instance is destroyed. + *
  • + *
  • + * Extensions can now access data previously stored by a + * {@link TestTemplateInvocationContext}, unless the + * {@link org.junit.jupiter.api.TestInstance.Lifecycle#PER_CLASS PER_CLASS} + * test instance lifecycle is used. + *
  • + *
+ * + *

Note: The behavior which is enabled by returning + * {@link ExtensionContextScope#TEST_METHOD TEST_METHOD} from this method + * will become the default in future versions of JUnit. To ensure forward + * compatibility, extension authors are therefore advised to opt into this + * feature, even if they do not require the new functionality. + * + * @implNote There are no guarantees about how often this method will be called. + * Therefore, implementations should be idempotent and avoid side effects. + * If computation of the return value is costly, implementations may wish to + * cache the result in the {@link ExtensionContext.Store Store} of the supplied + * {@code ExtensionContext}. + * @param rootContext the root extension context to allow inspection of + * configuration parameters; never {@code null} + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + default ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.DEFAULT; + } + + /** + * {@code ExtensionContextScope} is used to define the scope of the + * {@link ExtensionContext} supplied to an extension during the instantiation + * of test classes or processing of test instances. + * + * @since 5.12 + * @see TestInstantiationAwareExtension#getTestInstantiationExtensionContextScope(ExtensionContext) + */ + @API(status = MAINTAINED, since = "5.13.3") + enum ExtensionContextScope { + + /** + * The extension should receive an {@link ExtensionContext} for the + * the default scope. + * + *

The default scope is determined by the configuration parameter + * {@link #DEFAULT_SCOPE_PROPERTY_NAME}. If not specified, extensions + * will receive an {@link ExtensionContext} scoped to the test class. + * + * @deprecated This behavior will be removed from future versions of + * JUnit, and {@link #TEST_METHOD} will become the default. + * + * @see #DEFAULT_SCOPE_PROPERTY_NAME + */ + @API(status = DEPRECATED, since = "5.12") // + @Deprecated + DEFAULT, + + /** + * The extension should receive an {@link ExtensionContext} scoped to + * the test method. + * + *

Note, however, that a test-class scoped context will always be + * supplied if the + * {@link org.junit.jupiter.api.TestInstance.Lifecycle#PER_CLASS PER_CLASS} + * test instance lifecycle is used. + */ + TEST_METHOD; + + /** + * Property name used to set the default extension context scope: {@value} + * + *

Supported Values

+ * + *

Supported values include names of enum constants defined in this + * class, ignoring case. + * + * @see #DEFAULT + */ + public static final String DEFAULT_SCOPE_PROPERTY_NAME = "junit.jupiter.extensions.testinstantiation.extensioncontextscope.default"; + + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstantiationException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.jupiter.api.extension; import static java.util.Collections.emptyList; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.List; @@ -66,4 +67,18 @@ return emptyList(); } + /** + * Prepare the imminent invocation of the test template. + * + *

This may be used, for example, to store entries in the + * {@link ExtensionContext.Store Store} to benefit from its cleanup support + * or for retrieval by other extensions. + * + * @param context The invocation-level extension context. + * @since 5.13 + */ + @API(status = MAINTAINED, since = "5.13.3") + default void prepareInvocation(ExtensionContext context) { + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.api.extension; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.stream.Stream; @@ -27,7 +28,7 @@ * preparing the test class instance differently, or multiple times without * modifying the context. * - *

This interface defines two methods: {@link #supportsTestTemplate} and + *

This interface defines two main methods: {@link #supportsTestTemplate} and * {@link #provideTestTemplateInvocationContexts}. The former is called by the * framework to determine whether this extension wants to act on a test template * that is about to be executed. If so, the latter is called and must return a @@ -41,6 +42,10 @@ * the test template method will be invoked using the contexts of all active * providers. * + *

An active provider may return zero invocation contexts from its + * {@link #provideTestTemplateInvocationContexts} method if it overrides + * {@link #mayReturnZeroTestTemplateInvocationContexts} to return {@code true}. + * *

Constructor Requirements

* *

Consult the documentation in {@link Extension} for details on @@ -81,9 +86,34 @@ * to be invoked; never {@code null} * @return a {@code Stream} of {@code TestTemplateInvocationContext} * instances for the invocation of the test template method; never {@code null} + * @throws TemplateInvocationValidationException if a validation fails when + * while providing or closing the {@link java.util.stream.Stream}. * @see #supportsTestTemplate * @see ExtensionContext */ Stream provideTestTemplateInvocationContexts(ExtensionContext context); + /** + * Signal that this provider may provide zero + * {@linkplain TestTemplateInvocationContext invocation contexts} for the test + * template method represented by the supplied {@code context}. + * + *

If this method returns {@code false} (which is the default) and the + * provider returns an empty stream from + * {@link #provideTestTemplateInvocationContexts}, this will be considered + * an execution error. Override this method to return {@code true} to ignore + * the absence of invocation contexts for this provider. + * + * @param context the extension context for the test template method about + * to be invoked; never {@code null} + * @return {@code true} to allow zero contexts, {@code false} to fail + * execution in case of zero contexts + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + default boolean mayReturnZeroTestTemplateInvocationContexts(ExtensionContext context) { + return false; + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestWatcher.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestWatcher.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestWatcher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestWatcher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/Executable.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/Executable.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/Executable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/Executable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingConsumer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingConsumer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingConsumer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingConsumer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingSupplier.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingSupplier.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingSupplier.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/function/ThrowingSupplier.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/CleanupMode.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/CleanupMode.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/CleanupMode.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/CleanupMode.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDir.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDir.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDir.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDir.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.jupiter.api.io; import static org.apiguardian.api.API.Status.DEPRECATED; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.io.File; @@ -28,44 +28,39 @@ import org.junit.jupiter.api.extension.ParameterResolutionException; /** - * {@code @TempDir} can be used to annotate a field in a test class or a - * parameter in a lifecycle method or test method of type {@link Path} or - * {@link File} that should be resolved into a temporary directory. - * - *

Please note that {@code @TempDir} is not supported on constructor - * parameters. Please use field injection instead by annotating an instance - * field with {@code @TempDir}. + * {@code @TempDir} can be used to annotate a field in a test class or a parameter + * in a test class constructor, lifecycle method, or test method of type + * {@link Path} or {@link File} that should be resolved into a temporary directory. * *

Creation

* *

The temporary directory is only created if a field in a test class or a - * parameter in a lifecycle method or test method is annotated with - * {@code @TempDir}. - * An {@link ExtensionConfigurationException} or a - * {@link ParameterResolutionException} will be thrown in one of the following + * parameter in a test class constructor, lifecycle method, or test method is + * annotated with {@code @TempDir}. An {@link ExtensionConfigurationException} or + * a {@link ParameterResolutionException} will be thrown in one of the following * cases: * *

    - *
  • If the field type or parameter type is neither {@link Path} nor - {@link File}.
  • + *
  • If the field type or parameter type is neither {@code Path} nor {@code File}.
  • *
  • If a field is declared as {@code final}.
  • *
  • If the temporary directory cannot be created.
  • *
  • If the field type or parameter type is {@code File} and a custom - * {@linkplain TempDir#factory() factory} is used, which creates a temporary + * {@link TempDir#factory() factory} is used, which creates a temporary * directory that does not belong to the * {@linkplain java.nio.file.FileSystems#getDefault() default file system}. *
  • *
* - * In addition, a {@code ParameterResolutionException} will be thrown for a - * constructor parameter annotated with {@code @TempDir}. - * *

Scope

* - *

By default, a separate temporary directory is created for every - * declaration of the {@code @TempDir} annotation. If you want to share a - * temporary directory across all tests in a test class, you should declare the - * annotation on a {@code static} field or on a parameter of a + *

By default, a separate temporary directory is created for every declaration + * of the {@code @TempDir} annotation. For better isolation when using + * {@link org.junit.jupiter.api.TestInstance.Lifecycle#PER_METHOD @TestInstance(Lifecycle.PER_METHOD)} + * semantics, you can annotate an instance field or a parameter in the test class + * constructor with {@code @TempDir} so that each test method uses a separate + * temporary directory. Alternatively, if you want to share a temporary directory + * across all tests in a test class, you should declare the annotation on a + * {@code static} field or on a parameter of a * {@link org.junit.jupiter.api.BeforeAll @BeforeAll} method. * *

Old behavior

@@ -89,8 +84,11 @@ * — when the test method or class has finished execution — JUnit will * attempt to clean up the temporary directory by recursively deleting all files * and directories in the temporary directory and, finally, the temporary directory - * itself. In case deletion of a file or directory fails, an {@link IOException} - * will be thrown that will cause the test or test class to fail. + * itself. Symbolic and other types of links, such as junctions on Windows, are + * not followed. A warning is logged when deleting a link that targets a + * location outside the temporary directory. In case deletion of a file or + * directory fails, an {@link IOException} will be thrown that will cause the + * test or test class to fail. * *

The {@link #cleanup} attribute allows you to configure the {@link CleanupMode}. * If the cleanup mode is set to {@link CleanupMode#NEVER NEVER}, the temporary @@ -122,7 +120,7 @@ * * @since 5.10 */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") String DEFAULT_FACTORY_PROPERTY_NAME = "junit.jupiter.tempdir.factory.default"; /** @@ -144,7 +142,7 @@ * @since 5.10 * @see TempDirFactory */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") Class factory() default TempDirFactory.class; /** @@ -154,9 +152,10 @@ *

Supported Values

*
    *
  • {@code per_context}: creates a single temporary directory for the - * entire test class or method, depending on where it's first declared + * entire test class or method, depending on where {@code @TempDir} is first + * declared
  • *
  • {@code per_declaration}: creates separate temporary directories for - * each declaration site of the {@code @TempDir} annotation. + * each declaration site of the {@code @TempDir} annotation
  • *
* *

If not specified, the default is {@code per_declaration}. @@ -177,7 +176,7 @@ * * @since 5.9 */ - @API(status = EXPERIMENTAL, since = "5.9") + @API(status = MAINTAINED, since = "5.13.3") String DEFAULT_CLEANUP_MODE_PROPERTY_NAME = "junit.jupiter.tempdir.cleanup.mode.default"; /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDirFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDirFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDirFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/io/TempDirFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api.io; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.io.Closeable; import java.io.IOException; @@ -45,7 +45,7 @@ * @see TempDir @TempDir */ @FunctionalInterface -@API(status = EXPERIMENTAL, since = "5.10") +@API(status = MAINTAINED, since = "5.13.3") public interface TempDirFactory extends Closeable { /** @@ -73,7 +73,7 @@ /** * Standard {@link TempDirFactory} implementation which delegates to - * {@link Files#createTempDirectory} using {@code "junit-,"} as prefix. + * {@link Files#createTempDirectory} using {@code "junit-"} as prefix. * *

The created temporary directory is always created in the default * file system with the system's default temporary directory as its parent. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Execution.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Execution.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Execution.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Execution.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.api.parallel; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.ElementType; @@ -77,7 +77,7 @@ * * @since 5.4 */ - @API(status = EXPERIMENTAL, since = "5.9") + @API(status = MAINTAINED, since = "5.13.3") String DEFAULT_EXECUTION_MODE_PROPERTY_NAME = "junit.jupiter.execution.parallel.mode.default"; /** @@ -96,7 +96,7 @@ * * @since 5.4 */ - @API(status = EXPERIMENTAL, since = "5.9") + @API(status = MAINTAINED, since = "5.13.3") String DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME = "junit.jupiter.execution.parallel.mode.classes.default"; /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ExecutionMode.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ExecutionMode.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ExecutionMode.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ExecutionMode.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Isolated.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Isolated.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Isolated.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Isolated.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceAccessMode.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceAccessMode.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceAccessMode.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceAccessMode.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,6 +19,7 @@ * * @since 5.3 * @see ResourceLock + * @see ResourceLocksProvider.Lock */ @API(status = STABLE, since = "5.10") public enum ResourceAccessMode { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLock.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLock.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLock.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLock.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.api.parallel; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.ElementType; @@ -20,16 +21,15 @@ import java.lang.annotation.Target; import org.apiguardian.api.API; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.ClassTemplate; /** * {@code @ResourceLock} is used to declare that the annotated test class or test * method requires access to a shared resource identified by a key. * - *

The resource key is specified via {@link #value}. In addition, - * {@link #mode} allows you to specify whether the annotated test class or test - * method requires {@link ResourceAccessMode#READ_WRITE READ_WRITE} or only + *

The resource key is specified via {@link #value}. In addition, {@link #mode} + * allows one to specify whether the annotated test class or test method requires + * {@link ResourceAccessMode#READ_WRITE READ_WRITE} or * {@link ResourceAccessMode#READ READ} access to the resource. In the former case, * execution of the annotated element will occur while no other test class or * test method that uses the shared resource is being executed. In the latter case, @@ -38,20 +38,49 @@ * other test that requires {@code READ_WRITE} access. * *

This guarantee extends to lifecycle methods of a test class or method. For - * example, if a test method is annotated with a {@code @ResourceLock} - * annotation the "lock" will be acquired before any - * {@link BeforeEach @BeforeEach} methods are executed and released after all - * {@link AfterEach @AfterEach} methods have been executed. + * example, if a test method is annotated with {@code @ResourceLock} the lock + * will be acquired before any {@link org.junit.jupiter.api.BeforeEach @BeforeEach} + * methods are executed and released after all + * {@link org.junit.jupiter.api.AfterEach @AfterEach} methods have been executed. * *

This annotation can be repeated to declare the use of multiple shared resources. * + *

Uniqueness of a shared resource is determined by both the {@link #value()} + * and the {@link #mode()}. Duplicated shared resources do not cause errors. + * *

Since JUnit Jupiter 5.4, this annotation is {@linkplain Inherited inherited} * within class hierarchies. * + *

Since JUnit Jupiter 5.12, this annotation supports adding shared resources + * dynamically at runtime via {@link #providers}. Resources declared "statically" + * using {@link #value()} and {@link #mode()} are combined with "dynamic" resources + * added via {@link #providers()}. For example, declaring resource "A" via + * {@code @ResourceLock("A")} and resource "B" via a provider returning + * {@code new Lock("B")} will result in two shared resources "A" and "B". + * + *

Since JUnit Jupiter 5.12, this annotation supports declaring "static" + * shared resources for direct child nodes via the {@link #target()} + * attribute. Using {@link ResourceLockTarget#CHILDREN} in a class-level annotation + * has the same semantics as adding an annotation with the same {@link #value()} + * and {@link #mode()} to each test method and nested test class declared in the + * annotated class. This may improve parallelization when a test class declares a + * {@link ResourceAccessMode#READ READ} lock, but only a few methods hold + * {@link ResourceAccessMode#READ_WRITE READ_WRITE} lock. Note that + * {@code target = CHILDREN} means that {@link #value()} and {@link #mode()} no + * longer apply to a node declaring the annotation. However, the {@link #providers()} + * attribute remains applicable, and the target of "dynamic" shared resources added + * via implementations of {@link ResourceLocksProvider} is not changed. + * + *

Shared resources declared on or provided for methods or nested test + * classes in a {@link ClassTemplate @ClassTemplate} are propagated as if they + * were declared on the outermost enclosing {@code @ClassTemplate} class itself. + * * @see Isolated * @see Resources * @see ResourceAccessMode + * @see ResourceLockTarget * @see ResourceLocks + * @see ResourceLocksProvider * @since 5.3 */ @API(status = STABLE, since = "5.10") @@ -64,9 +93,12 @@ /** * The resource key. * + *

Defaults to an empty string. + * * @see Resources + * @see ResourceLocksProvider.Lock#getKey() */ - String value(); + String value() default ""; /** * The resource access mode. @@ -74,7 +106,33 @@ *

Defaults to {@link ResourceAccessMode#READ_WRITE READ_WRITE}. * * @see ResourceAccessMode + * @see ResourceLocksProvider.Lock#getAccessMode() */ ResourceAccessMode mode() default ResourceAccessMode.READ_WRITE; + /** + * An array of one or more classes implementing {@link ResourceLocksProvider}. + * + *

Defaults to an empty array. + * + * @see ResourceLocksProvider.Lock + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + Class[] providers() default {}; + + /** + * The target of a resource created from {@link #value()} and {@link #mode()}. + * + *

Defaults to {@link ResourceLockTarget#SELF SELF}. + * + *

Note that using {@link ResourceLockTarget#CHILDREN} in a method-level + * annotation results in an exception. + * + * @see ResourceLockTarget + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + ResourceLockTarget target() default ResourceLockTarget.SELF; + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLockTarget.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLockTarget.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLockTarget.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLockTarget.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.parallel; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; + +/** + * {@code ResourceLockTarget} is used to define the target of a shared resource. + * + * @since 5.12 + * @see ResourceLock#target() + */ +@API(status = MAINTAINED, since = "5.13.3") +public enum ResourceLockTarget { + + /** + * Add a shared resource to the current node. + */ + SELF, + + /** + * Add a shared resource to the direct children of the current node. + * + *

Examples of "parent - child" relationships in the context of + * {@code ResourceLockTarget}: + *

    + *
  • test class: test methods and nested test classes + * declared in the test class are children of the test class.
  • + *
  • nested test class: test methods and nested test + * classes declared in the nested class are children of the nested test class. + *
  • + *
  • test method: test methods are not considered to have + * children. Using {@code CHILDREN} for a test method results in an + * exception.
  • + *
+ */ + CHILDREN + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocks.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocks.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocks.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocks.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocksProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocksProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocksProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/ResourceLocksProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,223 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.parallel; + +import static java.util.Collections.emptySet; +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ToStringBuilder; + +/** + * A {@code ResourceLocksProvider} is used to programmatically add shared resources + * to a test class or its test methods dynamically at runtime. + * + *

Each shared resource is represented by an instance of {@link Lock}. + * + *

Adding shared resources via this API has the same semantics as declaring + * them declaratively via {@link ResourceLock @ResourceLock(value, mode)}, but for + * some use cases the programmatic approach may be more flexible and less verbose. + * + *

Implementations must provide a no-args constructor. + * + * @since 5.12 + * @see ResourceLock#providers() + * @see Resources + * @see ResourceAccessMode + * @see Lock + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface ResourceLocksProvider { + + /** + * Add shared resources for a test class. + * + *

Invoked in case a test class or its parent class is annotated with + * {@code @ResourceLock(providers)}. + * + * @apiNote Adding {@linkplain Lock a shared resource} via this method has + * the same semantics as annotating a test class with an analogous + * {@code @ResourceLock(value, mode)} declaration. + * + * @param testClass a test class for which to add shared resources + * @return a set of {@link Lock}; may be empty + */ + default Set provideForClass(Class testClass) { + return emptySet(); + } + + /** + * Add shared resources for a + * {@link org.junit.jupiter.api.Nested @Nested} test class. + * + *

Invoked in case: + *

    + *
  • an enclosing test class of any level or its parent class is + * annotated with {@code @ResourceLock(providers = ...)}.
  • + *
  • a nested test class or its parent class is annotated with + * {@code @ResourceLock(providers = ...)}.
  • + *
+ * + * @apiNote Adding {@linkplain Lock a shared resource} via this method has + * the same semantics as annotating a nested test class with an analogous + * {@code @ResourceLock(value, mode)} declaration. + * + * @implNote The classes supplied as {@code enclosingInstanceTypes} may + * differ from the classes returned from invocations of + * {@link Class#getEnclosingClass()} — for example, when a nested test + * class is inherited from a superclass. + * + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances for the test class, ordered from outermost to innermost, + * excluding {@code testClass}; never {@code null} + * @param testClass a nested test class for which to add shared resources + * @return a set of {@link Lock}; may be empty + * @see org.junit.jupiter.api.Nested @Nested + */ + default Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + return emptySet(); + } + + /** + * Add shared resources for a test method. + * + *

Invoked in case: + *

    + *
  • an enclosing test class of any level or its parent class is + * annotated with {@code @ResourceLock(providers)}.
  • + *
  • a test method is annotated with {@code @ResourceLock(providers)}.
  • + *
+ * + * @apiNote Adding {@linkplain Lock a shared resource} with this method + * has the same semantics as annotating a test method + * with analogous {@code @ResourceLock(value, mode)}. + * + * @implNote The classes supplied as {@code enclosingInstanceTypes} may + * differ from the classes returned from invocations of + * {@link Class#getEnclosingClass()} — for example, when a nested test + * class is inherited from a superclass. Similarly, the class instance + * supplied as {@code testClass} may differ from the class returned by + * {@code testMethod.getDeclaringClass()} — for example, when a test + * method is inherited from a superclass. + * + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances for the test class, ordered from outermost to innermost, + * excluding {@code testClass}; never {@code null} + * @param testClass the test class or {@link org.junit.jupiter.api.Nested @Nested} + * test class that contains the {@code testMethod} + * @param testMethod a test method for which to add shared resources + * @return a set of {@link Lock}; may be empty + * @see org.junit.jupiter.api.Nested @Nested + */ + default Set provideForMethod(List> enclosingInstanceTypes, Class testClass, Method testMethod) { + return emptySet(); + } + + /** + * {@code Lock} represents a shared resource. + * + *

Each resource is identified by a {@linkplain #getKey() key}. In addition, + * the {@linkplain #getAccessMode() access mode} allows one to specify whether + * a test class or test method requires {@link ResourceAccessMode#READ_WRITE + * READ_WRITE} or {@link ResourceAccessMode#READ READ} access to the resource. + * + * @apiNote {@link #getKey()} and {@link #getAccessMode()} have the same + * semantics as {@link ResourceLock#value()} and {@link ResourceLock#mode()} + * respectively. + * + * @since 5.12 + * @see Isolated + * @see Resources + * @see ResourceAccessMode + * @see ResourceLock + * @see ResourceLocksProvider + */ + final class Lock { + + private final String key; + + private final ResourceAccessMode accessMode; + + /** + * Create a new {@code Lock} with {@link ResourceAccessMode#READ_WRITE}. + * + * @param key the identifier of the resource; never {@code null} or blank + * @see ResourceLock#value() + */ + public Lock(String key) { + this(key, ResourceAccessMode.READ_WRITE); + } + + /** + * Create a new {@code Lock}. + * + * @param key the identifier of the resource; never {@code null} or blank + * @param accessMode the lock mode to use to synchronize access to the + * resource; never {@code null} + * @see ResourceLock#value() + * @see ResourceLock#mode() + */ + public Lock(String key, ResourceAccessMode accessMode) { + this.key = Preconditions.notBlank(key, "key must not be null or blank"); + this.accessMode = Preconditions.notNull(accessMode, "accessMode must not be null"); + } + + /** + * Get the key for this lock. + * + * @see ResourceLock#value() + */ + public String getKey() { + return this.key; + } + + /** + * Get the access mode for this lock. + * + * @see ResourceLock#mode() + */ + public ResourceAccessMode getAccessMode() { + return this.accessMode; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Lock that = (Lock) o; + return this.key.equals(that.key) && this.accessMode == that.accessMode; + } + + @Override + public int hashCode() { + return Objects.hash(this.key, this.accessMode); + } + + @Override + public String toString() { + return new ToStringBuilder(this) // + .append("key", this.key) // + .append("accessMode", this.accessMode) // + .toString(); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Resources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Resources.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Resources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/java/org/junit/jupiter/api/parallel/Resources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,6 +19,7 @@ * * @since 5.3 * @see ResourceLock + * @see ResourceLocksProvider.Lock */ @API(status = STABLE, since = "5.10") public class Resources { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,12 +7,14 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + @file:API(status = STABLE, since = "5.7") package org.junit.jupiter.api import org.apiguardian.api.API -import org.apiguardian.api.API.Status.EXPERIMENTAL +import org.apiguardian.api.API.Status.MAINTAINED import org.apiguardian.api.API.Status.STABLE import org.junit.jupiter.api.function.Executable import org.junit.jupiter.api.function.ThrowingSupplier @@ -20,6 +22,8 @@ import java.util.function.Supplier import java.util.stream.Stream import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind.AT_MOST_ONCE +import kotlin.contracts.InvocationKind.EXACTLY_ONCE import kotlin.contracts.contract /** @@ -33,6 +37,20 @@ /** * @see Assertions.fail */ +@OptIn(ExperimentalContracts::class) +@API(status = MAINTAINED, since = "5.13.3") +@JvmName("fail_nonNullableLambda") +fun fail(message: () -> String): Nothing { + contract { + callsInPlace(message, EXACTLY_ONCE) + } + + return Assertions.fail(message) +} + +/** + * @see Assertions.fail + */ fun fail(message: (() -> String)?): Nothing = Assertions.fail(message) /** @@ -96,6 +114,154 @@ /** * Example usage: * ```kotlin + * val nullableString: String? = ... + * + * assertNull(nullableString) + * + * // The compiler won't allow even safe calls, since nullableString is always null. + * // nullableString?.isNotEmpty() + * ``` + * @see Assertions.assertNull + */ +@OptIn(ExperimentalContracts::class) +@API(status = MAINTAINED, since = "5.13.3") +fun assertNull(actual: Any?) { + contract { + returns() implies (actual == null) + } + + Assertions.assertNull(actual) +} + +/** + * Example usage: + * ```kotlin + * val nullableString: String? = ... + * + * assertNull(nullableString, "Should be nullable") + * + * // The compiler won't allow even safe calls, since nullableString is always null. + * // nullableString?.isNotEmpty() + * ``` + * @see Assertions.assertNull + */ +@OptIn(ExperimentalContracts::class) +@API(status = MAINTAINED, since = "5.13.3") +fun assertNull( + actual: Any?, + message: String +) { + contract { + returns() implies (actual == null) + } + + Assertions.assertNull(actual, message) +} + +/** + * Example usage: + * ```kotlin + * val nullableString: String? = ... + * + * assertNull(nullableString) { "Should be nullable" } + * + * // The compiler won't allow even safe calls, since nullableString is always null. + * // nullableString?.isNotEmpty() + * ``` + * @see Assertions.assertNull + */ +@OptIn(ExperimentalContracts::class) +@API(status = MAINTAINED, since = "5.13.3") +fun assertNull( + actual: Any?, + messageSupplier: () -> String +) { + contract { + returns() implies (actual == null) + + callsInPlace(messageSupplier, AT_MOST_ONCE) + } + + Assertions.assertNull(actual, messageSupplier) +} + +/** + * Example usage: + * ```kotlin + * val nullableString: String? = ... + * + * assertNotNull(nullableString) + * + * // The compiler smart casts nullableString to a non-nullable object. + * assertTrue(nullableString.isNotEmpty()) + * ``` + * @see Assertions.assertNotNull + */ +@OptIn(ExperimentalContracts::class) +@API(status = MAINTAINED, since = "5.13.3") +fun assertNotNull(actual: Any?) { + contract { + returns() implies (actual != null) + } + + Assertions.assertNotNull(actual) +} + +/** + * Example usage: + * ```kotlin + * val nullableString: String? = ... + * + * assertNotNull(nullableString, "Should be non-nullable") + * + * // The compiler smart casts nullableString to a non-nullable object. + * assertTrue(nullableString.isNotEmpty()) + * ``` + * @see Assertions.assertNotNull + */ +@OptIn(ExperimentalContracts::class) +@API(status = MAINTAINED, since = "5.13.3") +fun assertNotNull( + actual: Any?, + message: String +) { + contract { + returns() implies (actual != null) + } + + Assertions.assertNotNull(actual, message) +} + +/** + * Example usage: + * ```kotlin + * val nullableString: String? = ... + * + * assertNotNull(nullableString) { "Should be non-nullable" } + * + * // The compiler smart casts nullableString to a non-nullable object. + * assertTrue(nullableString.isNotEmpty()) + * ``` + * @see Assertions.assertNotNull + */ +@OptIn(ExperimentalContracts::class) +@API(status = MAINTAINED, since = "5.13.3") +fun assertNotNull( + actual: Any?, + messageSupplier: () -> String +) { + contract { + returns() implies (actual != null) + + callsInPlace(messageSupplier, AT_MOST_ONCE) + } + + Assertions.assertNotNull(actual, messageSupplier) +} + +/** + * Example usage: + * ```kotlin * val exception = assertThrows { * throw IllegalArgumentException("Talk to a duck") * } @@ -104,6 +270,8 @@ * @see Assertions.assertThrows */ inline fun assertThrows(executable: () -> Unit): T { + // no contract for `executable` because it is expected to throw an exception instead + // of being executed completely (see https://youtrack.jetbrains.com/issue/KT-27748) val throwable: Throwable? = try { executable() @@ -143,10 +311,17 @@ * ``` * @see Assertions.assertThrows */ +@OptIn(ExperimentalContracts::class) inline fun assertThrows( noinline message: () -> String, executable: () -> Unit ): T { + contract { + callsInPlace(message, AT_MOST_ONCE) + // no contract for `executable` because it is expected to throw an exception instead + // of being executed completely (see https://youtrack.jetbrains.com/issue/KT-27748) + } + val throwable: Throwable? = try { executable() @@ -175,8 +350,15 @@ * @see Assertions.assertDoesNotThrow * @param R the result type of the [executable] */ +@OptIn(ExperimentalContracts::class) @API(status = STABLE, since = "5.11") -inline fun assertDoesNotThrow(executable: () -> R): R = Assertions.assertDoesNotThrow(evaluateAndWrap(executable)) +inline fun assertDoesNotThrow(executable: () -> R): R { + contract { + callsInPlace(executable, EXACTLY_ONCE) + } + + return Assertions.assertDoesNotThrow(evaluateAndWrap(executable)) +} /** * Example usage: @@ -188,11 +370,18 @@ * @see Assertions.assertDoesNotThrow * @param R the result type of the [executable] */ +@OptIn(ExperimentalContracts::class) @API(status = STABLE, since = "5.11") inline fun assertDoesNotThrow( message: String, executable: () -> R -): R = assertDoesNotThrow({ message }, executable) +): R { + contract { + callsInPlace(executable, EXACTLY_ONCE) + } + + return assertDoesNotThrow({ message }, executable) +} /** * Example usage: @@ -204,15 +393,22 @@ * @see Assertions.assertDoesNotThrow * @param R the result type of the [executable] */ +@OptIn(ExperimentalContracts::class) @API(status = STABLE, since = "5.11") inline fun assertDoesNotThrow( noinline message: () -> String, executable: () -> R -): R = - Assertions.assertDoesNotThrow( +): R { + contract { + callsInPlace(executable, EXACTLY_ONCE) + callsInPlace(message, AT_MOST_ONCE) + } + + return Assertions.assertDoesNotThrow( evaluateAndWrap(executable), Supplier(message) ) +} @PublishedApi internal inline fun evaluateAndWrap(executable: () -> R): ThrowingSupplier = @@ -231,13 +427,20 @@ * } * ``` * @see Assertions.assertTimeout - * @paramR the result of the [executable]. + * @param R the result of the [executable]. */ +@OptIn(ExperimentalContracts::class) @API(status = STABLE, since = "5.11") fun assertTimeout( timeout: Duration, executable: () -> R -): R = Assertions.assertTimeout(timeout, executable) +): R { + contract { + callsInPlace(executable, EXACTLY_ONCE) + } + + return Assertions.assertTimeout(timeout, executable) +} /** * Example usage: @@ -247,14 +450,21 @@ * } * ``` * @see Assertions.assertTimeout - * @paramR the result of the [executable]. + * @param R the result of the [executable]. */ +@OptIn(ExperimentalContracts::class) @API(status = STABLE, since = "5.11") fun assertTimeout( timeout: Duration, message: String, executable: () -> R -): R = Assertions.assertTimeout(timeout, executable, message) +): R { + contract { + callsInPlace(executable, EXACTLY_ONCE) + } + + return Assertions.assertTimeout(timeout, executable, message) +} /** * Example usage: @@ -264,14 +474,22 @@ * } * ``` * @see Assertions.assertTimeout - * @paramR the result of the [executable]. + * @param R the result of the [executable]. */ +@OptIn(ExperimentalContracts::class) @API(status = STABLE, since = "5.11") fun assertTimeout( timeout: Duration, message: () -> String, executable: () -> R -): R = Assertions.assertTimeout(timeout, executable, message) +): R { + contract { + callsInPlace(executable, EXACTLY_ONCE) + callsInPlace(message, AT_MOST_ONCE) + } + + return Assertions.assertTimeout(timeout, executable, message) +} /** * Example usage: @@ -281,13 +499,16 @@ * } * ``` * @see Assertions.assertTimeoutPreemptively - * @paramR the result of the [executable]. + * @param R the result of the [executable]. */ @API(status = STABLE, since = "5.11") fun assertTimeoutPreemptively( timeout: Duration, executable: () -> R -): R = Assertions.assertTimeoutPreemptively(timeout, executable) +): R = + // no contract for `executable` because it might be interrupted and throw an exception + // (see https://youtrack.jetbrains.com/issue/KT-27748) + Assertions.assertTimeoutPreemptively(timeout, executable) /** * Example usage: @@ -297,14 +518,17 @@ * } * ``` * @see Assertions.assertTimeoutPreemptively - * @paramR the result of the [executable]. + * @param R the result of the [executable]. */ @API(status = STABLE, since = "5.11") fun assertTimeoutPreemptively( timeout: Duration, message: String, executable: () -> R -): R = Assertions.assertTimeoutPreemptively(timeout, executable, message) +): R = + // no contract for `executable` because it might be interrupted and throw an exception + // (see https://youtrack.jetbrains.com/issue/KT-27748) + Assertions.assertTimeoutPreemptively(timeout, executable, message) /** * Example usage: @@ -314,25 +538,39 @@ * } * ``` * @see Assertions.assertTimeoutPreemptively - * @paramR the result of the [executable]. + * @param R the result of the [executable]. */ +@OptIn(ExperimentalContracts::class) @API(status = STABLE, since = "5.11") fun assertTimeoutPreemptively( timeout: Duration, message: () -> String, executable: () -> R -): R = Assertions.assertTimeoutPreemptively(timeout, executable, message) +): R { + contract { + callsInPlace(message, AT_MOST_ONCE) + // no contract for `executable` because it might be interrupted and throw an exception + // (see https://youtrack.jetbrains.com/issue/KT-27748) + } + + return Assertions.assertTimeoutPreemptively(timeout, executable, message) +} /** * Example usage: * ```kotlin - * assertInstanceOf(list, "List should support fast random access") + * val maybeString: Any = ... + * + * assertInstanceOf(maybeString) + * + * // The compiler smart casts maybeString to a String object. + * assertTrue(maybeString.isNotEmpty()) * ``` * @see Assertions.assertInstanceOf * @since 5.11 */ @OptIn(ExperimentalContracts::class) -@API(status = EXPERIMENTAL, since = "5.11") +@API(status = MAINTAINED, since = "5.13.3") inline fun assertInstanceOf( actualValue: Any?, message: String? = null @@ -343,18 +581,29 @@ return Assertions.assertInstanceOf(T::class.java, actualValue, message) } -/* +/** + * Example usage: + * ```kotlin + * val maybeString: Any = ... + * + * assertInstanceOf(maybeString) { "Should be a string" } + * + * // The compiler smart casts maybeString to a String object. + * assertTrue(maybeString.isNotEmpty()) + * ``` * @see Assertions.assertInstanceOf * @since 5.11 */ @OptIn(ExperimentalContracts::class) -@API(status = EXPERIMENTAL, since = "5.11") +@API(status = MAINTAINED, since = "5.13.3") inline fun assertInstanceOf( actualValue: Any?, noinline message: () -> String ): T { contract { returns() implies (actualValue is T) + + callsInPlace(message, AT_MOST_ONCE) } return Assertions.assertInstanceOf(T::class.java, actualValue, message) } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/module/org.junit.jupiter.api/module-info.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/module/org.junit.jupiter.api/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/module/org.junit.jupiter.api/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/module/org.junit.jupiter.api/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,8 +8,11 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** - * Defines JUnit Jupiter API for writing tests. + * Defines the JUnit Jupiter API for writing tests. + * + * @since 5.0 */ module org.junit.jupiter.api { requires static transitive org.apiguardian.api; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte 2026-06-21 20:26:05.000000000 +0000 @@ -7,24 +7,27 @@ ${licenseHeader} package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.reflect.Method; -import java.util.EnumSet; import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.StringUtils; /** * Enumeration of Java Runtime Environment (JRE) versions. * - *

If the current JRE version cannot be detected — for example, if the - * {@code java.version} JVM system property is undefined — then none of - * the constants defined in this enum will be considered to be the - * {@linkplain #isCurrentVersion current JRE version}. + *

If the current JRE version can be detected but is not one of the predefined + * constants in this enum, {@link #OTHER} will be considered to be the + * {@linkplain #isCurrentVersion current JRE version}. If the current JRE version + * cannot be detected — for example, if the {@code java.version} JVM system + * property is undefined — {@link #UNDEFINED} will be considered to be the + * current JRE version. * * @since 5.1 @for(JRE jre : jres)<%-- @@ -38,6 +41,19 @@ */ @API(status = STABLE, since = "5.1") public enum JRE { + + /** + * An undefined JRE version. + * + *

This constant is used by JUnit as a default configuration value but is + * not intended to be used by users. + * + *

This constant returns {@code -1} for its {@linkplain #version() version}. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + UNDEFINED(-1), @for(var jre : jres) /** * Java ${jre.getVersion()}. @@ -49,7 +65,7 @@ @if(jre.getSince() != null)<%-- --%>@API(status = STABLE, since = "${jre.getSince()}") @endif<%-- ---%>JAVA_${jre.getVersion()}, +--%>JAVA_${jre.getVersion()}(${jre.getVersion()}), @endfor /** * A JRE version other than <%-- @@ -60,14 +76,24 @@ --%>@if(jre.getIndex() % 3 == 1 && !jre.isLast()) * @elseif(!jre.isLast()) @endif<%-- --%>@endfor + * + *

This constant returns {@link Integer#MAX_VALUE} for its + * {@linkplain #version() version}. To retrieve the actual version number, + * use {@link #currentVersionNumber()}. */ - OTHER; + OTHER(Integer.MAX_VALUE); + + static final int UNDEFINED_VERSION = -1; + + static final int MINIMUM_VERSION = 8; private static final Logger logger = LoggerFactory.getLogger(JRE.class); - private static final JRE CURRENT_VERSION = determineCurrentVersion(); + private static final int CURRENT_VERSION = determineCurrentVersion(); + + private static final JRE CURRENT_JRE = determineCurrentJre(CURRENT_VERSION); - private static JRE determineCurrentVersion() { + private static int determineCurrentVersion() { String javaVersion = System.getProperty("java.version"); boolean javaVersionIsBlank = StringUtils.isBlank(javaVersion); @@ -77,7 +103,7 @@ } if (!javaVersionIsBlank && javaVersion.startsWith("1.8")) { - return JAVA_8; + return 8; } try { @@ -85,50 +111,120 @@ // that returns an instance of java.lang.Runtime.Version which has the // following method: public int major() Method versionMethod = Runtime.class.getMethod("version"); - Object version = ReflectionUtils.invokeMethod(versionMethod, null); + Object version = ReflectionSupport.invokeMethod(versionMethod, null); Method majorMethod = version.getClass().getMethod("major"); - int major = (int) ReflectionUtils.invokeMethod(majorMethod, version); - switch (major) {<%-- - --%>@for(var jre : jres)<%-- - --%>@if(jre.getVersion() != 8) - case ${jre.getVersion()}: - return JAVA_${jre.getVersion()};<%-- - --%>@endif<%-- - --%>@endfor - default: - return OTHER; - } + return (int) ReflectionSupport.invokeMethod(majorMethod, version); } catch (Exception ex) { logger.debug(ex, () -> "Failed to determine the current JRE version via java.lang.Runtime.Version."); } - // null signals that the current JRE version is "unknown" - return null; + return UNDEFINED_VERSION; + } + + private static JRE determineCurrentJre(int currentVersion) { + switch (currentVersion) { + case UNDEFINED_VERSION: + return UNDEFINED;<%-- + --%>@for(var jre : jres) + case ${jre.getVersion()}: + return JAVA_${jre.getVersion()};<%-- + --%>@endfor + default: + return OTHER; + } + } + + private final int version; + + private JRE(int version) { + this.version = version; + } + + /** + * Get the version of this {@code JRE}. + * + *

If this {@code JRE} is {@link #UNDEFINED}, this method returns + * {@code -1}. If this {@code JRE} is {@link #OTHER}, this method returns + * {@link Integer#MAX_VALUE}. + * + * @return the version of this {@code JRE} + * @since 5.12 + * @see Runtime.Version#feature() + * @see #currentVersionNumber() + */ + @API(status = MAINTAINED, since = "5.13.3") + public int version() { + return this.version; } /** * @return {@code true} if this {@code JRE} is known to be the * Java Runtime Environment version for the currently executing JVM or if - * the version is {@link #OTHER} + * the version is {@link #OTHER} or {@link #UNDEFINED} + * + * @see #currentJre() + * @see #currentVersionNumber() */ public boolean isCurrentVersion() { - return this == CURRENT_VERSION; + return this == CURRENT_JRE; } /** * @return the {@link JRE} for the currently executing JVM, potentially - * {@link #OTHER} + * {@link #OTHER} or {@link #UNDEFINED} * * @since 5.7 + * @see #currentVersionNumber() + * @deprecated in favor of {@link #currentJre()} */ - @API(status = STABLE, since = "5.7") + @API(status = DEPRECATED, since = "5.12") + @Deprecated public static JRE currentVersion() { + return currentJre(); + } + + /** + * @return the {@link JRE} for the currently executing JVM, potentially + * {@link #OTHER} or {@link #UNDEFINED} + * + * @since 5.12 + * @see #currentVersionNumber() + */ + @API(status = STABLE, since = "5.12") + public static JRE currentJre() { + return CURRENT_JRE; + } + + /** + * @return the version number for the currently executing JVM, or {@code -1} + * if the current JVM version could not be determined + * + * @since 5.12 + * @see Runtime.Version#feature() + * @see #currentJre() + */ + @API(status = MAINTAINED, since = "5.13.3") + public static int currentVersionNumber() { return CURRENT_VERSION; } - static boolean isCurrentVersionWithinRange(JRE min, JRE max) { - return EnumSet.range(min, max).contains(CURRENT_VERSION); + /** + * @return {@code true} if the supplied version number is known to be the + * Java Runtime Environment version for the currently executing JVM or if + * the supplied version number is {@code -1} and the current JVM version + * could not be determined + * + * @since 5.12 + * @see Runtime.Version#feature() + */ + @API(status = MAINTAINED, since = "5.13.3") + public static boolean isCurrentVersion(int version) { + return version == CURRENT_VERSION; + } + + static boolean isCurrentVersionWithinRange(int min, int max) { + return CURRENT_VERSION >= min && CURRENT_VERSION <= max; } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/templates/resources/testFixtures/org/junit/jupiter/api/condition/JavaVersionPredicates.java.jte jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/templates/resources/testFixtures/org/junit/jupiter/api/condition/JavaVersionPredicates.java.jte --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/templates/resources/testFixtures/org/junit/jupiter/api/condition/JavaVersionPredicates.java.jte 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/templates/resources/testFixtures/org/junit/jupiter/api/condition/JavaVersionPredicates.java.jte 2026-06-21 20:26:05.000000000 +0000 @@ -9,10 +9,10 @@ public class JavaVersionPredicates { - private static final String JAVA_VERSION = System.getProperty("java.version"); + private static final int JAVA_VERSION = Runtime.version().feature(); @for(JRE jre : jres) static boolean onJava${jre.getVersion()}() { - return JAVA_VERSION.startsWith("@if(jre.getVersion() == 8)1.@endif${jre.getVersion()}"); + return JAVA_VERSION == ${jre.getVersion()}; } @endfor static boolean onKnownVersion() { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/EqualsAndHashCodeAssertions.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/EqualsAndHashCodeAssertions.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/EqualsAndHashCodeAssertions.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/EqualsAndHashCodeAssertions.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Assertions for unit tests that wish to test + * {@link Object#equals(Object)} and {@link Object#hashCode()}. + * + * @since 5.3 + */ +public class EqualsAndHashCodeAssertions { + + private EqualsAndHashCodeAssertions() { + } + + @SuppressWarnings("EqualsWithItself") + public static void assertEqualsAndHashCode(T equal1, T equal2, T different) { + assertThat(equal1).isNotNull(); + assertThat(equal2).isNotNull(); + assertThat(different).isNotNull(); + + assertThat(equal1).isNotSameAs(equal2); + assertThat(equal1).isNotNull(); + assertThat(equal1).isNotEqualTo(new Object()); + assertThat(equal1).isNotEqualTo(different); + assertThat(different).isNotEqualTo(equal1); + assertThat(different).isNotEqualTo(equal2); + assertThat(equal1.hashCode()).isNotEqualTo(different.hashCode()); + + assertThat(equal1).isEqualTo(equal1); + assertThat(equal1).isEqualTo(equal2); + assertThat(equal2).isEqualTo(equal1); + assertThat(equal1.hashCode()).isEqualTo(equal2.hashCode()); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/TemporaryClasspathExecutor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/TemporaryClasspathExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/TemporaryClasspathExecutor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/TemporaryClasspathExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Utility class for executing code with a temporary classpath. + * + * @since 5.13 + */ +public class TemporaryClasspathExecutor { + + private TemporaryClasspathExecutor() { + } + + /** + * Execute the {@link Runnable} within a custom classpath, temporarily modifying the + * thread's {@link Thread#getContextClassLoader() context class loader} to include + * the provided {@code classpathRoot}. + * + *

After the given {@code Runnable} completes, the original context class loader is + * restored. + * + * @param classpathRoot the root path to be added to the classpath, resolved relative + * to the current thread's context class loader. + * @param runnable the {@code Runnable} to execute with the temporary classpath. + */ + public static void withAdditionalClasspathRoot(String classpathRoot, Runnable runnable) { + var current = Thread.currentThread().getContextClassLoader(); + try (var classLoader = new URLClassLoader(new URL[] { current.getResource(classpathRoot) }, current)) { + Thread.currentThread().setContextClassLoader(classLoader); + runnable.run(); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + finally { + Thread.currentThread().setContextClassLoader(current); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledInEclipse.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledInEclipse.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledInEclipse.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledInEclipse.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.condition.DisabledIf; + +/** + * @see org.junit.platform.commons.test.IdeUtils#runningInEclipse() + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@DisabledIf("org.junit.platform.commons.test.IdeUtils#runningInEclipse()") +public @interface DisabledInEclipse { + String value() default ""; +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledOnOpenJ9.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledOnOpenJ9.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledOnOpenJ9.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/DisabledOnOpenJ9.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/ExtensionContextParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/ExtensionContextParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/ExtensionContextParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/extension/ExtensionContextParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.jupiter.engine; import static org.apiguardian.api.API.Status.DEPRECATED; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import static org.junit.platform.engine.support.hierarchical.DefaultParallelExecutionConfigurationStrategy.CONFIG_CUSTOM_CLASS_PROPERTY_NAME; import static org.junit.platform.engine.support.hierarchical.DefaultParallelExecutionConfigurationStrategy.CONFIG_DYNAMIC_FACTOR_PROPERTY_NAME; @@ -33,6 +33,7 @@ import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.engine.config.JupiterConfiguration; @@ -49,6 +50,80 @@ public final class Constants { /** + * Property name used to include patterns for auto-detecting extensions: {@value} + * + *

Pattern Matching Syntax

+ * + *

If the property value consists solely of an asterisk ({@code *}), all + * extensions will be included. Otherwise, the property value will be treated + * as a comma-separated list of patterns where each individual pattern will be + * matched against the fully qualified class name (FQCN) of each extension. + * Any dot ({@code .}) in a pattern will match against a dot ({@code .}) + * or a dollar sign ({@code $}) in a FQCN. Any asterisk ({@code *}) will match + * against one or more characters in a FQCN. All other characters in a pattern + * will be matched one-to-one against a FQCN. + * + *

Examples

+ * + *
    + *
  • {@code *}: includes all extensions. + *
  • {@code org.junit.*}: includes every extension under the {@code org.junit} + * base package and any of its subpackages. + *
  • {@code *.MyExtension}: includes every extension whose simple class name is + * exactly {@code MyExtension}. + *
  • {@code *System*}: includes every extension whose FQCN contains + * {@code System}. + *
  • {@code *System*, *Dev*}: includes every extension whose FQCN contains + * {@code System} or {@code Dev}. + *
  • {@code org.example.MyExtension, org.example.TheirExtension}: includes + * extensions whose FQCN is exactly {@code org.example.MyExtension} or + * {@code org.example.TheirExtension}. + *
+ * + *

Note: A class that matches both an inclusion and exclusion pattern will be excluded. + * + * @see JupiterConfiguration#EXTENSIONS_AUTODETECTION_INCLUDE_PROPERTY_NAME + */ + public static final String EXTENSIONS_AUTODETECTION_INCLUDE_PROPERTY_NAME = JupiterConfiguration.EXTENSIONS_AUTODETECTION_INCLUDE_PROPERTY_NAME; + + /** + * Property name used to exclude patterns for auto-detecting extensions: {@value} + * + *

Pattern Matching Syntax

+ * + *

If the property value consists solely of an asterisk ({@code *}), all + * extensions will be excluded. Otherwise, the property value will be treated + * as a comma-separated list of patterns where each individual pattern will be + * matched against the fully qualified class name (FQCN) of each extension. + * Any dot ({@code .}) in a pattern will match against a dot ({@code .}) + * or a dollar sign ({@code $}) in a FQCN. Any asterisk ({@code *}) will match + * against one or more characters in a FQCN. All other characters in a pattern + * will be matched one-to-one against a FQCN. + * + *

Examples

+ * + *
    + *
  • {@code *}: excludes all extensions. + *
  • {@code org.junit.*}: excludes every extension under the {@code org.junit} + * base package and any of its subpackages. + *
  • {@code *.MyExtension}: excludes every extension whose simple class name is + * exactly {@code MyExtension}. + *
  • {@code *System*}: excludes every extension whose FQCN contains + * {@code System}. + *
  • {@code *System*, *Dev*}: excludes every extension whose FQCN contains + * {@code System} or {@code Dev}. + *
  • {@code org.example.MyExtension, org.example.TheirExtension}: excludes + * extensions whose FQCN is exactly {@code org.example.MyExtension} or + * {@code org.example.TheirExtension}. + *
+ * + *

Note: A class that matches both an inclusion and exclusion pattern will be excluded. + * + * @see JupiterConfiguration#EXTENSIONS_AUTODETECTION_EXCLUDE_PROPERTY_NAME + */ + public static final String EXTENSIONS_AUTODETECTION_EXCLUDE_PROPERTY_NAME = JupiterConfiguration.EXTENSIONS_AUTODETECTION_EXCLUDE_PROPERTY_NAME; + + /** * Property name used to provide patterns for deactivating conditions: {@value} * *

Pattern Matching Syntax

@@ -90,7 +165,7 @@ * @see #DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME * @see org.junit.jupiter.api.extension.ExecutionCondition */ - public static final String DEACTIVATE_ALL_CONDITIONS_PATTERN = ClassNamePatternFilterUtils.DEACTIVATE_ALL_PATTERN; + public static final String DEACTIVATE_ALL_CONDITIONS_PATTERN = ClassNamePatternFilterUtils.ALL_PATTERN; /** * Property name used to set the default display name generator class name: {@value} @@ -108,6 +183,17 @@ public static final String EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME = JupiterConfiguration.EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME; /** + * Property name used to enable dumping the stack of all + * {@linkplain Thread threads} to {@code System.out} when a timeout has occurred. + * + *

This behavior is disabled by default. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME = JupiterConfiguration.EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME; + + /** * Property name used to set the default test instance lifecycle mode: {@value} * * @see TestInstance.Lifecycle#DEFAULT_LIFECYCLE_PROPERTY_NAME @@ -125,6 +211,16 @@ public static final String PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME = JupiterConfiguration.PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME; /** + * Property name used to enable auto-closing of {@link AutoCloseable} instances + * + *

By default, auto-closing is enabled. + * + * @since 5.13 + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME = JupiterConfiguration.CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME; + + /** * Property name used to set the default test execution mode: {@value} * * @see Execution#DEFAULT_EXECUTION_MODE_PROPERTY_NAME @@ -180,7 +276,7 @@ * * @since 5.10 */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") public static final String PARALLEL_CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX + CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME; @@ -191,14 +287,14 @@ *

When set to {@code false} the underlying fork-join pool will reject * additional tasks if all available workers are busy and the maximum * pool-size would be exceeded. - + * *

Value must either {@code true} or {@code false}; defaults to {@code true}. * *

Note: This property only takes affect on Java 9+. * * @since 5.10 */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") public static final String PARALLEL_CONFIG_FIXED_SATURATE_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX + CONFIG_FIXED_SATURATE_PROPERTY_NAME; @@ -356,7 +452,7 @@ * @see Timeout * @see Timeout.ThreadMode */ - @API(status = EXPERIMENTAL, since = "5.9") + @API(status = MAINTAINED, since = "5.13.3") public static final String DEFAULT_TIMEOUT_THREAD_MODE_PROPERTY_NAME = Timeout.DEFAULT_TIMEOUT_THREAD_MODE_PROPERTY_NAME; /** @@ -366,9 +462,19 @@ * @since 5.10 * @see TempDir#DEFAULT_FACTORY_PROPERTY_NAME */ - @API(status = EXPERIMENTAL, since = "5.10") + @API(status = MAINTAINED, since = "5.13.3") public static final String DEFAULT_TEMP_DIR_FACTORY_PROPERTY_NAME = TempDir.DEFAULT_FACTORY_PROPERTY_NAME; + /** + * Property name used to set the default extension context scope for + * extensions that participate in test instantiation: {@value} + * + * @since 5.12 + * @see org.junit.jupiter.api.extension.TestInstantiationAwareExtension + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextScope.DEFAULT_SCOPE_PROPERTY_NAME; + private Constants() { /* no-op */ } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/JupiterTestEngine.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/JupiterTestEngine.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/JupiterTestEngine.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/JupiterTestEngine.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,6 +21,7 @@ import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; import org.junit.jupiter.engine.discovery.DiscoverySelectorResolver; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; import org.junit.jupiter.engine.support.JupiterThrowableCollectorFactory; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.ExecutionRequest; @@ -63,8 +64,8 @@ @Override public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { - JupiterConfiguration configuration = new CachingJupiterConfiguration( - new DefaultJupiterConfiguration(discoveryRequest.getConfigurationParameters())); + JupiterConfiguration configuration = new CachingJupiterConfiguration(new DefaultJupiterConfiguration( + discoveryRequest.getConfigurationParameters(), discoveryRequest.getOutputDirectoryCreator())); JupiterEngineDescriptor engineDescriptor = new JupiterEngineDescriptor(uniqueId, configuration); new DiscoverySelectorResolver().resolveSelectors(discoveryRequest, engineDescriptor); return engineDescriptor; @@ -82,8 +83,8 @@ @Override protected JupiterEngineExecutionContext createExecutionContext(ExecutionRequest request) { - return new JupiterEngineExecutionContext(request.getEngineExecutionListener(), - getJupiterConfiguration(request)); + return new JupiterEngineExecutionContext(request.getEngineExecutionListener(), getJupiterConfiguration(request), + new LauncherStoreFacade(request.getStore())); } /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/CachingJupiterConfiguration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -26,9 +26,12 @@ import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDirFactory; import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.platform.engine.OutputDirectoryCreator; /** * Caching implementation of the {@link JupiterConfiguration} API. @@ -46,6 +49,11 @@ } @Override + public Predicate> getFilterForAutoDetectedExtensions() { + return delegate.getFilterForAutoDetectedExtensions(); + } + + @Override public Optional getRawConfigurationParameter(String key) { return delegate.getRawConfigurationParameter(key); } @@ -58,71 +66,94 @@ @Override public boolean isParallelExecutionEnabled() { return (boolean) cache.computeIfAbsent(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME, - key -> delegate.isParallelExecutionEnabled()); + __ -> delegate.isParallelExecutionEnabled()); + } + + @Override + public boolean isClosingStoredAutoCloseablesEnabled() { + return (boolean) cache.computeIfAbsent(CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME, + __ -> delegate.isClosingStoredAutoCloseablesEnabled()); } @Override public boolean isExtensionAutoDetectionEnabled() { return (boolean) cache.computeIfAbsent(EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME, - key -> delegate.isExtensionAutoDetectionEnabled()); + __ -> delegate.isExtensionAutoDetectionEnabled()); + } + + @Override + public boolean isThreadDumpOnTimeoutEnabled() { + return (boolean) cache.computeIfAbsent(EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME, + __ -> delegate.isThreadDumpOnTimeoutEnabled()); } @Override public ExecutionMode getDefaultExecutionMode() { return (ExecutionMode) cache.computeIfAbsent(DEFAULT_EXECUTION_MODE_PROPERTY_NAME, - key -> delegate.getDefaultExecutionMode()); + __ -> delegate.getDefaultExecutionMode()); } @Override public ExecutionMode getDefaultClassesExecutionMode() { return (ExecutionMode) cache.computeIfAbsent(DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME, - key -> delegate.getDefaultClassesExecutionMode()); + __ -> delegate.getDefaultClassesExecutionMode()); } @Override public TestInstance.Lifecycle getDefaultTestInstanceLifecycle() { return (TestInstance.Lifecycle) cache.computeIfAbsent(DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME, - key -> delegate.getDefaultTestInstanceLifecycle()); + __ -> delegate.getDefaultTestInstanceLifecycle()); } @SuppressWarnings("unchecked") @Override public Predicate getExecutionConditionFilter() { return (Predicate) cache.computeIfAbsent(DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME, - key -> delegate.getExecutionConditionFilter()); + __ -> delegate.getExecutionConditionFilter()); } @Override public DisplayNameGenerator getDefaultDisplayNameGenerator() { return (DisplayNameGenerator) cache.computeIfAbsent(DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME, - key -> delegate.getDefaultDisplayNameGenerator()); + __ -> delegate.getDefaultDisplayNameGenerator()); } @SuppressWarnings("unchecked") @Override public Optional getDefaultTestMethodOrderer() { return (Optional) cache.computeIfAbsent(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME, - key -> delegate.getDefaultTestMethodOrderer()); + __ -> delegate.getDefaultTestMethodOrderer()); } @SuppressWarnings("unchecked") @Override public Optional getDefaultTestClassOrderer() { return (Optional) cache.computeIfAbsent(DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME, - key -> delegate.getDefaultTestClassOrderer()); + __ -> delegate.getDefaultTestClassOrderer()); } @Override public CleanupMode getDefaultTempDirCleanupMode() { return (CleanupMode) cache.computeIfAbsent(DEFAULT_CLEANUP_MODE_PROPERTY_NAME, - key -> delegate.getDefaultTempDirCleanupMode()); + __ -> delegate.getDefaultTempDirCleanupMode()); } @SuppressWarnings("unchecked") @Override public Supplier getDefaultTempDirFactorySupplier() { return (Supplier) cache.computeIfAbsent(DEFAULT_FACTORY_PROPERTY_NAME, - key -> delegate.getDefaultTempDirFactorySupplier()); + __ -> delegate.getDefaultTempDirFactorySupplier()); } + @Override + public ExtensionContextScope getDefaultTestInstantiationExtensionContextScope() { + return (ExtensionContextScope) cache.computeIfAbsent( + DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME, + __ -> delegate.getDefaultTestInstantiationExtensionContextScope()); + } + + @Override + public OutputDirectoryCreator getOutputDirectoryCreator() { + return delegate.getOutputDirectoryCreator(); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -26,12 +26,15 @@ import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDirFactory; import org.junit.jupiter.api.parallel.ExecutionMode; import org.junit.platform.commons.util.ClassNamePatternFilterUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.OutputDirectoryCreator; /** * Default implementation of the {@link JupiterConfiguration} API. @@ -62,11 +65,36 @@ private static final InstantiatingConfigurationParameterConverter tempDirFactoryConverter = // new InstantiatingConfigurationParameterConverter<>(TempDirFactory.class, "temp dir factory"); + private static final EnumConfigurationParameterConverter extensionContextScopeConverter = // + new EnumConfigurationParameterConverter<>(ExtensionContextScope.class, "extension context scope"); + private final ConfigurationParameters configurationParameters; + private final OutputDirectoryCreator outputDirectoryCreator; - public DefaultJupiterConfiguration(ConfigurationParameters configurationParameters) { + public DefaultJupiterConfiguration(ConfigurationParameters configurationParameters, + OutputDirectoryCreator outputDirectoryCreator) { this.configurationParameters = Preconditions.notNull(configurationParameters, "ConfigurationParameters must not be null"); + this.outputDirectoryCreator = outputDirectoryCreator; + } + + @Override + public Predicate> getFilterForAutoDetectedExtensions() { + String includePattern = getExtensionAutoDetectionIncludePattern(); + String excludePattern = getExtensionAutoDetectionExcludePattern(); + Predicate predicate = ClassNamePatternFilterUtils.includeMatchingClassNames(includePattern) // + .and(ClassNamePatternFilterUtils.excludeMatchingClassNames(excludePattern)); + return clazz -> predicate.test(clazz.getName()); + } + + private String getExtensionAutoDetectionIncludePattern() { + return configurationParameters.get(EXTENSIONS_AUTODETECTION_INCLUDE_PROPERTY_NAME) // + .orElse(ClassNamePatternFilterUtils.ALL_PATTERN); + } + + private String getExtensionAutoDetectionExcludePattern() { + return configurationParameters.get(EXTENSIONS_AUTODETECTION_EXCLUDE_PROPERTY_NAME) // + .orElse(ClassNamePatternFilterUtils.BLANK); } @Override @@ -85,11 +113,21 @@ } @Override + public boolean isClosingStoredAutoCloseablesEnabled() { + return configurationParameters.getBoolean(CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME).orElse(true); + } + + @Override public boolean isExtensionAutoDetectionEnabled() { return configurationParameters.getBoolean(EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME).orElse(false); } @Override + public boolean isThreadDumpOnTimeoutEnabled() { + return configurationParameters.getBoolean(EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME).orElse(false); + } + + @Override public ExecutionMode getDefaultExecutionMode() { return executionModeConverter.get(configurationParameters, DEFAULT_EXECUTION_MODE_PROPERTY_NAME, ExecutionMode.SAME_THREAD); @@ -141,4 +179,15 @@ return () -> supplier.get().orElse(TempDirFactory.Standard.INSTANCE); } + @SuppressWarnings("deprecation") + @Override + public ExtensionContextScope getDefaultTestInstantiationExtensionContextScope() { + return extensionContextScopeConverter.get(configurationParameters, + DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME, ExtensionContextScope.DEFAULT); + } + + @Override + public OutputDirectoryCreator getOutputDirectoryCreator() { + return outputDirectoryCreator; + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/EnumConfigurationParameterConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/EnumConfigurationParameterConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/EnumConfigurationParameterConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/EnumConfigurationParameterConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,7 +16,7 @@ import org.junit.platform.commons.function.Try; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.engine.ConfigurationParameters; /** @@ -49,9 +49,9 @@ } private Supplier> newInstanceSupplier(String className, String key) { - Try> clazz = ReflectionUtils.tryToLoadClass(className); + Try> clazz = ReflectionSupport.tryToLoadClass(className); // @formatter:off - return () -> clazz.andThenTry(ReflectionUtils::newInstance) + return () -> clazz.andThenTry(ReflectionSupport::newInstance) .andThenTry(this.clazz::cast) .ifSuccess(generator -> logSuccessMessage(className, key)) .ifFailure(cause -> logFailureMessage(className, key, cause)) diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -23,10 +23,14 @@ import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.PreInterruptCallback; +import org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDirFactory; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.platform.engine.OutputDirectoryCreator; /** * @since 5.4 @@ -34,15 +38,22 @@ @API(status = INTERNAL, since = "5.4") public interface JupiterConfiguration { + String EXTENSIONS_AUTODETECTION_INCLUDE_PROPERTY_NAME = "junit.jupiter.extensions.autodetection.include"; + String EXTENSIONS_AUTODETECTION_EXCLUDE_PROPERTY_NAME = "junit.jupiter.extensions.autodetection.exclude"; String DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME = "junit.jupiter.conditions.deactivate"; String PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME = "junit.jupiter.execution.parallel.enabled"; + String CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME = "junit.jupiter.extensions.store.close.autocloseable.enabled"; String DEFAULT_EXECUTION_MODE_PROPERTY_NAME = Execution.DEFAULT_EXECUTION_MODE_PROPERTY_NAME; String DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME = Execution.DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME; String EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME = "junit.jupiter.extensions.autodetection.enabled"; + String EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME = PreInterruptCallback.THREAD_DUMP_ENABLED_PROPERTY_NAME; String DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME = TestInstance.Lifecycle.DEFAULT_LIFECYCLE_PROPERTY_NAME; String DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME = DisplayNameGenerator.DEFAULT_GENERATOR_PROPERTY_NAME; String DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME = MethodOrderer.DEFAULT_ORDER_PROPERTY_NAME; String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME; + String DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextScope.DEFAULT_SCOPE_PROPERTY_NAME; + + Predicate> getFilterForAutoDetectedExtensions(); Optional getRawConfigurationParameter(String key); @@ -50,8 +61,12 @@ boolean isParallelExecutionEnabled(); + boolean isClosingStoredAutoCloseablesEnabled(); + boolean isExtensionAutoDetectionEnabled(); + boolean isThreadDumpOnTimeoutEnabled(); + ExecutionMode getDefaultExecutionMode(); ExecutionMode getDefaultClassesExecutionMode(); @@ -70,4 +85,7 @@ Supplier getDefaultTempDirFactorySupplier(); + ExtensionContextScope getDefaultTestInstantiationExtensionContextScope(); + + OutputDirectoryCreator getOutputDirectoryCreator(); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,24 +13,37 @@ import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toCollection; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; +import org.junit.jupiter.api.MediaType; import org.junit.jupiter.api.extension.ExecutableInvoker; +import org.junit.jupiter.api.extension.Extension; import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; +import org.junit.jupiter.api.function.ThrowingConsumer; import org.junit.jupiter.api.parallel.ExecutionMode; import org.junit.jupiter.engine.config.JupiterConfiguration; -import org.junit.jupiter.engine.execution.NamespaceAwareStore; +import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionContextInternal; +import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.UnrecoverableExceptions; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestTag; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.hierarchical.Node; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; @@ -38,49 +51,74 @@ /** * @since 5.0 */ -abstract class AbstractExtensionContext implements ExtensionContext, AutoCloseable { +abstract class AbstractExtensionContext implements ExtensionContextInternal, AutoCloseable { - private static final NamespacedHierarchicalStore.CloseAction CLOSE_RESOURCES = (__, ___, value) -> { - if (value instanceof CloseableResource) { - ((CloseableResource) value).close(); - } - }; + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractExtensionContext.class); + private static final Namespace CLOSEABLE_RESOURCE_LOGGING_NAMESPACE = Namespace.create( + AbstractExtensionContext.class, "CloseableResourceLogging"); private final ExtensionContext parent; private final EngineExecutionListener engineExecutionListener; private final T testDescriptor; private final Set tags; private final JupiterConfiguration configuration; - private final NamespacedHierarchicalStore valuesStore; private final ExecutableInvoker executableInvoker; + private final ExtensionRegistry extensionRegistry; + private final LauncherStoreFacade launcherStoreFacade; + private final NamespacedHierarchicalStore valuesStore; AbstractExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, T testDescriptor, - JupiterConfiguration configuration, - Function executableInvokerFactory) { - this.executableInvoker = executableInvokerFactory.apply(this); + JupiterConfiguration configuration, ExtensionRegistry extensionRegistry, + LauncherStoreFacade launcherStoreFacade) { Preconditions.notNull(testDescriptor, "TestDescriptor must not be null"); Preconditions.notNull(configuration, "JupiterConfiguration must not be null"); - + Preconditions.notNull(extensionRegistry, "ExtensionRegistry must not be null"); + this.executableInvoker = new DefaultExecutableInvoker(this, extensionRegistry); this.parent = parent; this.engineExecutionListener = engineExecutionListener; this.testDescriptor = testDescriptor; this.configuration = configuration; - this.valuesStore = createStore(parent); + this.extensionRegistry = extensionRegistry; + this.launcherStoreFacade = launcherStoreFacade; // @formatter:off this.tags = testDescriptor.getTags().stream() .map(TestTag::getName) .collect(collectingAndThen(toCollection(LinkedHashSet::new), Collections::unmodifiableSet)); // @formatter:on + + this.valuesStore = new NamespacedHierarchicalStore<>(getParentStore(parent), createCloseAction()); } - private static NamespacedHierarchicalStore createStore(ExtensionContext parent) { - NamespacedHierarchicalStore parentStore = null; - if (parent != null) { - parentStore = ((AbstractExtensionContext) parent).valuesStore; - } - return new NamespacedHierarchicalStore<>(parentStore, CLOSE_RESOURCES); + private NamespacedHierarchicalStore getParentStore( + ExtensionContext parent) { + return parent == null // + ? this.launcherStoreFacade.getRequestLevelStore() // + : ((AbstractExtensionContext) parent).valuesStore; + } + + @SuppressWarnings("deprecation") + private NamespacedHierarchicalStore.CloseAction createCloseAction() { + Store store = this.launcherStoreFacade.getSessionLevelStore(CLOSEABLE_RESOURCE_LOGGING_NAMESPACE); + return (__, ___, value) -> { + boolean isAutoCloseEnabled = this.configuration.isClosingStoredAutoCloseablesEnabled(); + + if (isAutoCloseEnabled && value instanceof AutoCloseable) { + ((AutoCloseable) value).close(); + return; + } + + if (value instanceof Store.CloseableResource) { + if (isAutoCloseEnabled) { + store.getOrComputeIfAbsent(value.getClass(), type -> { + LOGGER.warn(() -> "Type implements CloseableResource but not AutoCloseable: " + type.getName()); + return true; + }); + } + ((Store.CloseableResource) value).close(); + } + }; } @Override @@ -104,6 +142,61 @@ } @Override + public void publishFile(String name, MediaType mediaType, ThrowingConsumer action) { + Preconditions.notBlank(name, "name must not be null or blank"); + Preconditions.notNull(mediaType, "mediaType must not be null"); + Preconditions.notNull(action, "action must not be null"); + + publishFileEntry(name, action, path -> { + Preconditions.condition(Files.isRegularFile(path), () -> "Published path must be a regular file: " + path); + return FileEntry.from(path, mediaType.toString()); + }); + } + + @Override + public void publishDirectory(String name, ThrowingConsumer action) { + Preconditions.notBlank(name, "name must not be null or blank"); + Preconditions.notNull(action, "action must not be null"); + + ThrowingConsumer enhancedAction = path -> { + if (!Files.isDirectory(path)) { + Files.createDirectory(path); + } + action.accept(path); + }; + publishFileEntry(name, enhancedAction, path -> { + Preconditions.condition(Files.isDirectory(path), () -> "Published path must be a directory: " + path); + return FileEntry.from(path, null); + }); + } + + private void publishFileEntry(String name, ThrowingConsumer action, + Function fileEntryCreator) { + Path dir = createOutputDirectory(); + Path path = dir.resolve(name); + Preconditions.condition(path.getParent().equals(dir), () -> "name must not contain path separators: " + name); + try { + action.accept(path); + } + catch (Throwable t) { + UnrecoverableExceptions.rethrowIfUnrecoverable(t); + throw new JUnitException("Failed to publish path", t); + } + Preconditions.condition(Files.exists(path), () -> "Published path must exist: " + path); + FileEntry fileEntry = fileEntryCreator.apply(path); + this.engineExecutionListener.fileEntryPublished(this.testDescriptor, fileEntry); + } + + private Path createOutputDirectory() { + try { + return configuration.getOutputDirectoryCreator().createOutputDirectory(this.testDescriptor); + } + catch (IOException e) { + throw new JUnitException("Failed to create output directory", e); + } + } + + @Override public Optional getParent() { return Optional.ofNullable(this.parent); } @@ -122,8 +215,21 @@ @Override public Store getStore(Namespace namespace) { - Preconditions.notNull(namespace, "Namespace must not be null"); - return new NamespaceAwareStore(this.valuesStore, namespace); + return launcherStoreFacade.getStoreAdapter(this.valuesStore, namespace); + } + + @Override + public Store getStore(StoreScope scope, Namespace namespace) { + // TODO [#4246] Use switch expression + switch (scope) { + case LAUNCHER_SESSION: + return launcherStoreFacade.getSessionLevelStore(namespace); + case EXECUTION_REQUEST: + return launcherStoreFacade.getRequestLevelStore(namespace); + case EXTENSION_CONTEXT: + return getStore(namespace); + } + throw new JUnitException("Unknown StoreScope: " + scope); } @Override @@ -152,6 +258,11 @@ return executableInvoker; } + @Override + public List getExtensions(Class extensionType) { + return extensionRegistry.getExtensions(extensionType); + } + protected abstract Node.ExecutionMode getPlatformExecutionMode(); private ExecutionMode toJupiterExecutionMode(Node.ExecutionMode mode) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/CallbackSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/CallbackSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/CallbackSupport.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/CallbackSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static org.junit.platform.commons.util.CollectionUtils.forEachInReverseOrder; + +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; +import org.junit.jupiter.engine.extension.ExtensionRegistry; +import org.junit.platform.engine.support.hierarchical.ThrowableCollector; + +/** + * @since 5.13 + */ +class CallbackSupport { + + static void invokeBeforeCallbacks(Class type, JupiterEngineExecutionContext context, + CallbackInvoker callbackInvoker) { + + ExtensionRegistry registry = context.getExtensionRegistry(); + ExtensionContext extensionContext = context.getExtensionContext(); + ThrowableCollector throwableCollector = context.getThrowableCollector(); + + for (T callback : registry.getExtensions(type)) { + throwableCollector.execute(() -> callbackInvoker.invoke(callback, extensionContext)); + if (throwableCollector.isNotEmpty()) { + break; + } + } + } + + static void invokeAfterCallbacks(Class type, JupiterEngineExecutionContext context, + CallbackInvoker callbackInvoker) { + + ExtensionRegistry registry = context.getExtensionRegistry(); + ExtensionContext extensionContext = context.getExtensionContext(); + ThrowableCollector throwableCollector = context.getThrowableCollector(); + + forEachInReverseOrder(registry.getExtensions(type), // + callback -> throwableCollector.execute(() -> callbackInvoker.invoke(callback, extensionContext))); + } + + @FunctionalInterface + protected interface CallbackInvoker { + + void invoke(T t, ExtensionContext context) throws Throwable; + + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,8 @@ import static java.util.stream.Collectors.joining; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.jupiter.engine.descriptor.CallbackSupport.invokeAfterCallbacks; +import static org.junit.jupiter.engine.descriptor.CallbackSupport.invokeBeforeCallbacks; import static org.junit.jupiter.engine.descriptor.ExtensionUtils.populateNewExtensionRegistryFromExtendWithAnnotation; import static org.junit.jupiter.engine.descriptor.ExtensionUtils.registerExtensionsFromConstructorParameters; import static org.junit.jupiter.engine.descriptor.ExtensionUtils.registerExtensionsFromExecutableParameters; @@ -23,7 +25,6 @@ import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findBeforeEachMethods; import static org.junit.jupiter.engine.descriptor.TestInstanceLifecycleUtils.getTestInstanceLifecycle; import static org.junit.jupiter.engine.support.JupiterThrowableCollectorFactory.createThrowableCollector; -import static org.junit.platform.commons.util.CollectionUtils.forEachInReverseOrder; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -55,8 +56,8 @@ import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.execution.AfterEachMethodAdapter; import org.junit.jupiter.engine.execution.BeforeEachMethodAdapter; -import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; import org.junit.jupiter.engine.execution.DefaultTestInstances; +import org.junit.jupiter.engine.execution.ExtensionContextSupplier; import org.junit.jupiter.engine.execution.InterceptingExecutableInvoker; import org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.ReflectiveInterceptorCall; import org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.ReflectiveInterceptorCall.VoidMethodInterceptorCall; @@ -70,11 +71,12 @@ import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.commons.util.UnrecoverableExceptions; +import org.junit.platform.engine.DiscoveryIssue; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.support.descriptor.ClassSource; -import org.junit.platform.engine.support.hierarchical.ExclusiveResource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.hierarchical.ThrowableCollector; /** @@ -83,76 +85,109 @@ * @since 5.5 */ @API(status = INTERNAL, since = "5.5") -public abstract class ClassBasedTestDescriptor extends JupiterTestDescriptor { +public abstract class ClassBasedTestDescriptor extends JupiterTestDescriptor + implements ResourceLockAware, TestClassAware, Validatable { private static final InterceptingExecutableInvoker executableInvoker = new InterceptingExecutableInvoker(); - private final Class testClass; - protected final Set tags; - protected final Lifecycle lifecycle; + protected final ClassInfo classInfo; - private ExecutionMode defaultChildExecutionMode; + private LifecycleMethods lifecycleMethods; private TestInstanceFactory testInstanceFactory; - private List beforeAllMethods; - private List afterAllMethods; ClassBasedTestDescriptor(UniqueId uniqueId, Class testClass, Supplier displayNameSupplier, JupiterConfiguration configuration) { super(uniqueId, testClass, displayNameSupplier, ClassSource.from(testClass), configuration); - this.testClass = testClass; - this.tags = getTags(testClass); - this.lifecycle = getTestInstanceLifecycle(testClass, configuration); - this.defaultChildExecutionMode = (this.lifecycle == Lifecycle.PER_CLASS ? ExecutionMode.SAME_THREAD : null); + this.classInfo = new ClassInfo(testClass, configuration); + this.lifecycleMethods = new LifecycleMethods(this.classInfo); } - // --- TestDescriptor ------------------------------------------------------ + ClassBasedTestDescriptor(UniqueId uniqueId, Class testClass, String displayName, + JupiterConfiguration configuration) { + super(uniqueId, displayName, ClassSource.from(testClass), configuration); + + this.classInfo = new ClassInfo(testClass, configuration); + this.lifecycleMethods = new LifecycleMethods(this.classInfo); + } + + // --- TestClassAware ------------------------------------------------------ + @Override public final Class getTestClass() { - return this.testClass; + return this.classInfo.testClass; } - public abstract List> getEnclosingTestClasses(); + // --- TestDescriptor ------------------------------------------------------ @Override - public Type getType() { + public final Type getType() { return Type.CONTAINER; } @Override - public String getLegacyReportingName() { - return this.testClass.getName(); + public final String getLegacyReportingName() { + return getTestClass().getName(); + } + + // --- Validatable --------------------------------------------------------- + + @Override + public final void validate(DiscoveryIssueReporter reporter) { + validateCoreLifecycleMethods(reporter); + validateClassTemplateInvocationLifecycleMethods(reporter); + validateTags(reporter); + validateDisplayNameAnnotation(reporter); + } + + private void validateDisplayNameAnnotation(DiscoveryIssueReporter reporter) { + DisplayNameUtils.validateAnnotation(getTestClass(), // + () -> String.format("class '%s'", getTestClass().getName()), // + () -> getSource().orElse(null), // + reporter); + } + + protected void validateCoreLifecycleMethods(DiscoveryIssueReporter reporter) { + Validatable.reportAndClear(this.lifecycleMethods.discoveryIssues, reporter); + } + + protected void validateClassTemplateInvocationLifecycleMethods(DiscoveryIssueReporter reporter) { + LifecycleMethodUtils.validateNoClassTemplateInvocationLifecycleMethodsAreDeclared(getTestClass(), reporter); + } + + private void validateTags(DiscoveryIssueReporter reporter) { + Validatable.reportAndClear(this.classInfo.discoveryIssues, reporter); } // --- Node ---------------------------------------------------------------- @Override - protected Optional getExplicitExecutionMode() { + protected final Optional getExplicitExecutionMode() { return getExecutionModeFromAnnotation(getTestClass()); } @Override - protected Optional getDefaultChildExecutionMode() { - return Optional.ofNullable(this.defaultChildExecutionMode); + protected final Optional getDefaultChildExecutionMode() { + return Optional.ofNullable(this.classInfo.defaultChildExecutionMode); } - public void setDefaultChildExecutionMode(ExecutionMode defaultChildExecutionMode) { - this.defaultChildExecutionMode = defaultChildExecutionMode; + public final void setDefaultChildExecutionMode(ExecutionMode defaultChildExecutionMode) { + this.classInfo.defaultChildExecutionMode = defaultChildExecutionMode; } @Override - public Set getExclusiveResources() { - return getExclusiveResourcesFromAnnotation(getTestClass()); + public final ExclusiveResourceCollector getExclusiveResourceCollector() { + return this.classInfo.exclusiveResourceCollector; } @Override - public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) { + public final JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) { MutableExtensionRegistry registry = populateNewExtensionRegistryFromExtendWithAnnotation( - context.getExtensionRegistry(), this.testClass); + context.getExtensionRegistry(), getTestClass()); // Register extensions from static fields here, at the class level but // after extensions registered via @ExtendWith. - registerExtensionsFromStaticFields(registry, this.testClass); + registerExtensionsFromStaticFields(registry, getTestClass()); // Resolve the TestInstanceFactory at the class level in order to fail // the entire class in case of configuration errors (e.g., more than @@ -160,13 +195,10 @@ this.testInstanceFactory = resolveTestInstanceFactory(registry); if (this.testInstanceFactory == null) { - registerExtensionsFromConstructorParameters(registry, this.testClass); + registerExtensionsFromConstructorParameters(registry, getTestClass()); } - this.beforeAllMethods = findBeforeAllMethods(this.testClass, this.lifecycle == Lifecycle.PER_METHOD); - this.afterAllMethods = findAfterAllMethods(this.testClass, this.lifecycle == Lifecycle.PER_METHOD); - - this.beforeAllMethods.forEach(method -> registerExtensionsFromExecutableParameters(registry, method)); + this.lifecycleMethods.beforeAll.forEach(method -> registerExtensionsFromExecutableParameters(registry, method)); // Since registerBeforeEachMethodAdapters() and registerAfterEachMethodAdapters() also // invoke registerExtensionsFromExecutableParameters(), we invoke those methods before // invoking registerExtensionsFromExecutableParameters() for @AfterAll methods, @@ -174,13 +206,13 @@ // on parameters in lifecycle methods. registerBeforeEachMethodAdapters(registry); registerAfterEachMethodAdapters(registry); - this.afterAllMethods.forEach(method -> registerExtensionsFromExecutableParameters(registry, method)); - registerExtensionsFromInstanceFields(registry, this.testClass); + this.lifecycleMethods.afterAll.forEach(method -> registerExtensionsFromExecutableParameters(registry, method)); + registerExtensionsFromInstanceFields(registry, getTestClass()); ThrowableCollector throwableCollector = createThrowableCollector(); ClassExtensionContext extensionContext = new ClassExtensionContext(context.getExtensionContext(), - context.getExecutionListener(), this, this.lifecycle, context.getConfiguration(), throwableCollector, - it -> new DefaultExecutableInvoker(it, registry)); + context.getExecutionListener(), this, this.classInfo.lifecycle, context.getConfiguration(), registry, + context.getLauncherStoreFacade(), throwableCollector); // @formatter:off return context.extend() @@ -193,7 +225,7 @@ } @Override - public JupiterEngineExecutionContext before(JupiterEngineExecutionContext context) { + public final JupiterEngineExecutionContext before(JupiterEngineExecutionContext context) { ThrowableCollector throwableCollector = context.getThrowableCollector(); if (isPerClassLifecycle(context)) { @@ -201,8 +233,7 @@ // and store the instance in the ExtensionContext. ClassExtensionContext extensionContext = (ClassExtensionContext) context.getExtensionContext(); throwableCollector.execute(() -> { - TestInstances testInstances = context.getTestInstancesProvider().getTestInstances( - context.getExtensionRegistry(), throwableCollector); + TestInstances testInstances = context.getTestInstancesProvider().getTestInstances(context); extensionContext.setTestInstances(testInstances); }); } @@ -223,7 +254,7 @@ } @Override - public void after(JupiterEngineExecutionContext context) { + public final void after(JupiterEngineExecutionContext context) { ThrowableCollector throwableCollector = context.getThrowableCollector(); Throwable previousThrowable = throwableCollector.getThrowable(); @@ -250,6 +281,13 @@ } } + @Override + public void cleanUp(JupiterEngineExecutionContext context) throws Exception { + super.cleanUp(context); + this.lifecycleMethods = null; + this.testInstanceFactory = null; + } + private TestInstanceFactory resolveTestInstanceFactory(ExtensionRegistry registry) { List factories = registry.getExtensions(TestInstanceFactory.class); @@ -264,7 +302,7 @@ String errorMessage = String.format( "The following TestInstanceFactory extensions were registered for test class [%s], but only one is permitted: %s", - testClass.getName(), factoryNames); + getTestClass().getName(), factoryNames); throw new ExtensionConfigurationException(errorMessage); } @@ -273,52 +311,57 @@ } private TestInstancesProvider testInstancesProvider(JupiterEngineExecutionContext parentExecutionContext, - ClassExtensionContext extensionContext) { + ClassExtensionContext ourExtensionContext) { - return (registry, registrar, throwableCollector) -> extensionContext.getTestInstances().orElseGet( - () -> instantiateAndPostProcessTestInstance(parentExecutionContext, extensionContext, registry, registrar, - throwableCollector)); + // For Lifecycle.PER_CLASS, ourExtensionContext.getTestInstances() is used to store the instance. + // Otherwise, extensionContext.getTestInstances() is always empty and we always create a new instance. + return (registry, context) -> ourExtensionContext.getTestInstances().orElseGet( + () -> instantiateAndPostProcessTestInstance(parentExecutionContext, ourExtensionContext, registry, + context)); } private TestInstances instantiateAndPostProcessTestInstance(JupiterEngineExecutionContext parentExecutionContext, - ExtensionContext extensionContext, ExtensionRegistry registry, ExtensionRegistrar registrar, - ThrowableCollector throwableCollector) { + ClassExtensionContext ourExtensionContext, ExtensionRegistry registry, + JupiterEngineExecutionContext context) { - TestInstances instances = instantiateTestClass(parentExecutionContext, registry, registrar, extensionContext, - throwableCollector); - throwableCollector.execute(() -> { + ExtensionContextSupplier extensionContext = ExtensionContextSupplier.create(context.getExtensionContext(), + ourExtensionContext, configuration); + TestInstances instances = instantiateTestClass(parentExecutionContext, extensionContext, registry, context); + context.getThrowableCollector().execute(() -> { invokeTestInstancePostProcessors(instances.getInnermostInstance(), registry, extensionContext); // In addition, we initialize extension registered programmatically from instance fields here // since the best time to do that is immediately following test class instantiation // and post-processing. - registrar.initializeExtensions(this.testClass, instances.getInnermostInstance()); + context.getExtensionRegistry().initializeExtensions(getTestClass(), instances.getInnermostInstance()); }); return instances; } protected abstract TestInstances instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext, - ExtensionRegistry registry, ExtensionRegistrar registrar, ExtensionContext extensionContext, - ThrowableCollector throwableCollector); + ExtensionContextSupplier extensionContext, ExtensionRegistry registry, + JupiterEngineExecutionContext context); - protected TestInstances instantiateTestClass(Optional outerInstances, ExtensionRegistry registry, - ExtensionContext extensionContext) { + protected final TestInstances instantiateTestClass(Optional outerInstances, + ExtensionRegistry registry, ExtensionContextSupplier extensionContext) { Optional outerInstance = outerInstances.map(TestInstances::getInnermostInstance); - invokeTestInstancePreConstructCallbacks(new DefaultTestInstanceFactoryContext(this.testClass, outerInstance), + invokeTestInstancePreConstructCallbacks(new DefaultTestInstanceFactoryContext(getTestClass(), outerInstance), registry, extensionContext); Object instance = this.testInstanceFactory != null // ? invokeTestInstanceFactory(outerInstance, extensionContext) // : invokeTestClassConstructor(outerInstance, registry, extensionContext); - return outerInstances.map(instances -> DefaultTestInstances.of(instances, instance)).orElse( - DefaultTestInstances.of(instance)); + return outerInstances.map(instances -> DefaultTestInstances.of(instances, instance)) // + .orElse(DefaultTestInstances.of(instance)); } - private Object invokeTestInstanceFactory(Optional outerInstance, ExtensionContext extensionContext) { + private Object invokeTestInstanceFactory(Optional outerInstance, + ExtensionContextSupplier extensionContext) { Object instance; try { + ExtensionContext actualExtensionContext = extensionContext.get(this.testInstanceFactory); instance = this.testInstanceFactory.createTestInstance( - new DefaultTestInstanceFactoryContext(this.testClass, outerInstance), extensionContext); + new DefaultTestInstanceFactoryContext(getTestClass(), outerInstance), actualExtensionContext); } catch (Throwable throwable) { UnrecoverableExceptions.rethrowIfUnrecoverable(throwable); @@ -328,15 +371,15 @@ } String message = String.format("TestInstanceFactory [%s] failed to instantiate test class [%s]", - this.testInstanceFactory.getClass().getName(), this.testClass.getName()); + this.testInstanceFactory.getClass().getName(), getTestClass().getName()); if (StringUtils.isNotBlank(throwable.getMessage())) { message += ": " + throwable.getMessage(); } throw new TestInstantiationException(message, throwable); } - if (!this.testClass.isInstance(instance)) { - String testClassName = this.testClass.getName(); + if (!getTestClass().isInstance(instance)) { + String testClassName = getTestClass().getName(); Class instanceClass = (instance == null ? null : instance.getClass()); String instanceClassName = (instanceClass == null ? "null" : instanceClass.getName()); @@ -344,7 +387,7 @@ // the identity hash codes to the type names to help users disambiguate // between otherwise identical "fully qualified class names". if (testClassName.equals(instanceClassName)) { - testClassName += "@" + Integer.toHexString(System.identityHashCode(this.testClass)); + testClassName += "@" + Integer.toHexString(System.identityHashCode(getTestClass())); instanceClassName += "@" + Integer.toHexString(System.identityHashCode(instanceClass)); } String message = String.format( @@ -358,24 +401,24 @@ } private Object invokeTestClassConstructor(Optional outerInstance, ExtensionRegistry registry, - ExtensionContext extensionContext) { + ExtensionContextSupplier extensionContext) { - Constructor constructor = ReflectionUtils.getDeclaredConstructor(this.testClass); + Constructor constructor = ReflectionUtils.getDeclaredConstructor(getTestClass()); return executableInvoker.invoke(constructor, outerInstance, extensionContext, registry, InvocationInterceptor::interceptTestClassConstructor); } private void invokeTestInstancePreConstructCallbacks(TestInstanceFactoryContext factoryContext, - ExtensionRegistry registry, ExtensionContext context) { - registry.stream(TestInstancePreConstructCallback.class).forEach( - extension -> executeAndMaskThrowable(() -> extension.preConstructTestInstance(factoryContext, context))); + ExtensionRegistry registry, ExtensionContextSupplier context) { + registry.stream(TestInstancePreConstructCallback.class).forEach(extension -> executeAndMaskThrowable( + () -> extension.preConstructTestInstance(factoryContext, context.get(extension)))); } private void invokeTestInstancePostProcessors(Object instance, ExtensionRegistry registry, - ExtensionContext context) { + ExtensionContextSupplier context) { - registry.stream(TestInstancePostProcessor.class).forEach( - extension -> executeAndMaskThrowable(() -> extension.postProcessTestInstance(instance, context))); + registry.stream(TestInstancePostProcessor.class).forEach(extension -> executeAndMaskThrowable( + () -> extension.postProcessTestInstance(instance, context.get(extension)))); } private void executeAndMaskThrowable(Executable executable) { @@ -388,16 +431,7 @@ } private void invokeBeforeAllCallbacks(JupiterEngineExecutionContext context) { - ExtensionRegistry registry = context.getExtensionRegistry(); - ExtensionContext extensionContext = context.getExtensionContext(); - ThrowableCollector throwableCollector = context.getThrowableCollector(); - - for (BeforeAllCallback callback : registry.getExtensions(BeforeAllCallback.class)) { - throwableCollector.execute(() -> callback.beforeAll(extensionContext)); - if (throwableCollector.isNotEmpty()) { - break; - } - } + invokeBeforeCallbacks(BeforeAllCallback.class, context, BeforeAllCallback::beforeAll); } private void invokeBeforeAllMethods(JupiterEngineExecutionContext context) { @@ -406,7 +440,7 @@ ThrowableCollector throwableCollector = context.getThrowableCollector(); Object testInstance = extensionContext.getTestInstance().orElse(null); - for (Method method : this.beforeAllMethods) { + for (Method method : this.lifecycleMethods.beforeAll) { throwableCollector.execute(() -> { try { executableInvoker.invoke(method, testInstance, extensionContext, registry, @@ -435,7 +469,7 @@ ThrowableCollector throwableCollector = context.getThrowableCollector(); Object testInstance = extensionContext.getTestInstance().orElse(null); - this.afterAllMethods.forEach(method -> throwableCollector.execute(() -> { + this.lifecycleMethods.afterAll.forEach(method -> throwableCollector.execute(() -> { try { executableInvoker.invoke(method, testInstance, extensionContext, registry, ReflectiveInterceptorCall.ofVoidMethod(InvocationInterceptor::interceptAfterAllMethod)); @@ -454,20 +488,12 @@ } private void invokeAfterAllCallbacks(JupiterEngineExecutionContext context) { - ExtensionRegistry registry = context.getExtensionRegistry(); - ExtensionContext extensionContext = context.getExtensionContext(); - ThrowableCollector throwableCollector = context.getThrowableCollector(); - - forEachInReverseOrder(registry.getExtensions(AfterAllCallback.class), // - extension -> throwableCollector.execute(() -> extension.afterAll(extensionContext))); + invokeAfterCallbacks(AfterAllCallback.class, context, AfterAllCallback::afterAll); } private void invokeTestInstancePreDestroyCallbacks(JupiterEngineExecutionContext context) { - ExtensionContext extensionContext = context.getExtensionContext(); - ThrowableCollector throwableCollector = context.getThrowableCollector(); - - forEachInReverseOrder(context.getExtensionRegistry().getExtensions(TestInstancePreDestroyCallback.class), // - extension -> throwableCollector.execute(() -> extension.preDestroyTestInstance(extensionContext))); + invokeAfterCallbacks(TestInstancePreDestroyCallback.class, context, + TestInstancePreDestroyCallback::preDestroyTestInstance); } private boolean isPerClassLifecycle(JupiterEngineExecutionContext context) { @@ -476,13 +502,13 @@ } private void registerBeforeEachMethodAdapters(ExtensionRegistrar registrar) { - List beforeEachMethods = findBeforeEachMethods(this.testClass); - registerMethodsAsExtensions(beforeEachMethods, registrar, this::synthesizeBeforeEachMethodAdapter); + registerMethodsAsExtensions(this.lifecycleMethods.beforeEach, registrar, + this::synthesizeBeforeEachMethodAdapter); } private void registerAfterEachMethodAdapters(ExtensionRegistrar registrar) { // Make a local copy since findAfterEachMethods() returns an immutable list. - List afterEachMethods = new ArrayList<>(findAfterEachMethods(this.testClass)); + List afterEachMethods = new ArrayList<>(this.lifecycleMethods.afterEach); // Since the bottom-up ordering of afterEachMethods will later be reversed when the // synthesized AfterEachMethodAdapters are executed within TestMethodTestDescriptor, @@ -515,11 +541,53 @@ private void invokeMethodInExtensionContext(Method method, ExtensionContext context, ExtensionRegistry registry, VoidMethodInterceptorCall interceptorCall) { TestInstances testInstances = context.getRequiredTestInstances(); - Object target = testInstances.findInstance(this.testClass).orElseThrow( + Object target = testInstances.findInstance(getTestClass()).orElseThrow( () -> new JUnitException("Failed to find instance for method: " + method.toGenericString())); executableInvoker.invoke(method, target, context, registry, ReflectiveInterceptorCall.ofVoidMethod(interceptorCall)); } + protected static class ClassInfo { + + private final List discoveryIssues = new ArrayList<>(); + + final Class testClass; + final Set tags; + final Lifecycle lifecycle; + ExecutionMode defaultChildExecutionMode; + final ExclusiveResourceCollector exclusiveResourceCollector; + + ClassInfo(Class testClass, JupiterConfiguration configuration) { + this.testClass = testClass; + this.tags = getTags(testClass, // + () -> String.format("class '%s'", testClass.getName()), // + () -> ClassSource.from(testClass), // + discoveryIssues::add); + this.lifecycle = getTestInstanceLifecycle(testClass, configuration); + this.defaultChildExecutionMode = (this.lifecycle == Lifecycle.PER_CLASS ? ExecutionMode.SAME_THREAD : null); + this.exclusiveResourceCollector = ExclusiveResourceCollector.from(testClass); + } + } + + private static class LifecycleMethods { + + private final List discoveryIssues = new ArrayList<>(); + + private final List beforeAll; + private final List afterAll; + private final List beforeEach; + private final List afterEach; + + LifecycleMethods(ClassInfo classInfo) { + Class testClass = classInfo.testClass; + boolean requireStatic = classInfo.lifecycle == Lifecycle.PER_METHOD; + DiscoveryIssueReporter issueReporter = DiscoveryIssueReporter.collecting(discoveryIssues); + this.beforeAll = findBeforeAllMethods(testClass, requireStatic, issueReporter); + this.afterAll = findAfterAllMethods(testClass, requireStatic, issueReporter); + this.beforeEach = findBeforeEachMethods(testClass, issueReporter); + this.afterEach = findAfterEachMethods(testClass, issueReporter); + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassExtensionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,14 +12,15 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; -import java.util.function.Function; import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.jupiter.api.extension.ExecutableInvoker; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.support.hierarchical.Node; import org.junit.platform.engine.support.hierarchical.ThrowableCollector; @@ -35,27 +36,12 @@ private TestInstances testInstances; - /** - * Create a new {@code ClassExtensionContext} with {@link Lifecycle#PER_METHOD}. - * - * @see #ClassExtensionContext(ExtensionContext, EngineExecutionListener, ClassBasedTestDescriptor, - * Lifecycle, JupiterConfiguration, ThrowableCollector, Function) - */ - ClassExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, - ClassBasedTestDescriptor testDescriptor, JupiterConfiguration configuration, - ThrowableCollector throwableCollector, - Function executableInvokerFactory) { - - this(parent, engineExecutionListener, testDescriptor, Lifecycle.PER_METHOD, configuration, throwableCollector, - executableInvokerFactory); - } - ClassExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, ClassBasedTestDescriptor testDescriptor, Lifecycle lifecycle, JupiterConfiguration configuration, - ThrowableCollector throwableCollector, - Function executableInvokerFactory) { + ExtensionRegistry extensionRegistry, LauncherStoreFacade launcherStoreFacade, + ThrowableCollector throwableCollector) { - super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory); + super(parent, engineExecutionListener, testDescriptor, configuration, extensionRegistry, launcherStoreFacade); this.lifecycle = lifecycle; this.throwableCollector = throwableCollector; @@ -72,6 +58,11 @@ } @Override + public List> getEnclosingTestClasses() { + return getTestDescriptor().getEnclosingTestClasses(); + } + + @Override public Optional getTestInstanceLifecycle() { return Optional.of(this.lifecycle); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationExtensionContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestInstances; +import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; +import org.junit.platform.engine.EngineExecutionListener; +import org.junit.platform.engine.support.hierarchical.Node; + +/** + * @since 5.13 + */ +final class ClassTemplateInvocationExtensionContext + extends AbstractExtensionContext { + + ClassTemplateInvocationExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, + ClassTemplateInvocationTestDescriptor testDescriptor, JupiterConfiguration configuration, + ExtensionRegistry extensionRegistry, LauncherStoreFacade launcherStoreFacade) { + super(parent, engineExecutionListener, testDescriptor, configuration, extensionRegistry, launcherStoreFacade); + } + + @Override + public Optional getElement() { + return Optional.of(getTestDescriptor().getTestClass()); + } + + @Override + public Optional> getTestClass() { + return Optional.of(getTestDescriptor().getTestClass()); + } + + @Override + public List> getEnclosingTestClasses() { + return getTestDescriptor().getEnclosingTestClasses(); + } + + @Override + public Optional getTestInstanceLifecycle() { + return getParent().flatMap(ExtensionContext::getTestInstanceLifecycle); + } + + @Override + public Optional getTestInstance() { + return getParent().flatMap(ExtensionContext::getTestInstance); + } + + @Override + public Optional getTestInstances() { + return getParent().flatMap(ExtensionContext::getTestInstances); + } + + @Override + public Optional getTestMethod() { + return Optional.empty(); + } + + @Override + public Optional getExecutionException() { + return Optional.empty(); + } + + @Override + protected Node.ExecutionMode getPlatformExecutionMode() { + return getTestDescriptor().getExecutionMode(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationTestDescriptor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateInvocationTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static java.util.Collections.emptySet; +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.jupiter.engine.descriptor.CallbackSupport.invokeAfterCallbacks; +import static org.junit.jupiter.engine.descriptor.CallbackSupport.invokeBeforeCallbacks; +import static org.junit.jupiter.engine.extension.MutableExtensionRegistry.createRegistryFrom; +import static org.junit.jupiter.engine.support.JupiterThrowableCollectorFactory.createThrowableCollector; + +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.parallel.ResourceLocksProvider; +import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; +import org.junit.jupiter.engine.extension.MutableExtensionRegistry; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.hierarchical.ExclusiveResource; +import org.junit.platform.engine.support.hierarchical.ThrowableCollector; + +/** + * @since 5.13 + */ +@API(status = INTERNAL, since = "5.13") +public class ClassTemplateInvocationTestDescriptor extends JupiterTestDescriptor + implements TestClassAware, ResourceLockAware { + + public static final String SEGMENT_TYPE = "class-template-invocation"; + + private final ClassTemplateTestDescriptor parent; + private ClassTemplateInvocationContext invocationContext; + private final int index; + + public ClassTemplateInvocationTestDescriptor(UniqueId uniqueId, ClassTemplateTestDescriptor parent, + ClassTemplateInvocationContext invocationContext, int index, TestSource source, + JupiterConfiguration configuration) { + super(uniqueId, invocationContext.getDisplayName(index), source, configuration); + this.parent = parent; + this.invocationContext = invocationContext; + this.index = index; + } + + public int getIndex() { + return index; + } + + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected ClassTemplateInvocationTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new ClassTemplateInvocationTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), parent, + this.invocationContext, this.index, getSource().orElse(null), this.configuration); + } + + // --- TestDescriptor ------------------------------------------------------ + + @Override + public Type getType() { + return Type.CONTAINER; + } + + @Override + public String getLegacyReportingName() { + return getTestClass().getName() + "[" + index + "]"; + } + + // --- TestClassAware ------------------------------------------------------ + + @Override + public Class getTestClass() { + return parent.getTestClass(); + } + + @Override + public List> getEnclosingTestClasses() { + return parent.getEnclosingTestClasses(); + } + + // --- ResourceLockAware --------------------------------------------------- + + @Override + public ExclusiveResourceCollector getExclusiveResourceCollector() { + return parent.getExclusiveResourceCollector(); + } + + @Override + public Function> getResourceLocksProviderEvaluator() { + return parent.getResourceLocksProviderEvaluator(); + } + + // --- Node ---------------------------------------------------------------- + + @Override + public Set getExclusiveResources() { + // Resources are already collected and returned by the enclosing ClassTemplateTestDescriptor + return emptySet(); + } + + @Override + public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) { + MutableExtensionRegistry registry = context.getExtensionRegistry(); + List additionalExtensions = this.invocationContext.getAdditionalExtensions(); + if (!additionalExtensions.isEmpty()) { + MutableExtensionRegistry childRegistry = createRegistryFrom(registry, Stream.empty()); + additionalExtensions.forEach( + extension -> childRegistry.registerExtension(extension, this.invocationContext)); + registry = childRegistry; + } + ExtensionContext extensionContext = new ClassTemplateInvocationExtensionContext(context.getExtensionContext(), + context.getExecutionListener(), this, context.getConfiguration(), registry, + context.getLauncherStoreFacade()); + ThrowableCollector throwableCollector = createThrowableCollector(); + throwableCollector.execute(() -> this.invocationContext.prepareInvocation(extensionContext)); + return context.extend() // + .withExtensionRegistry(registry) // + .withExtensionContext(extensionContext) // + .withThrowableCollector(throwableCollector) // + .build(); + } + + @Override + public SkipResult shouldBeSkipped(JupiterEngineExecutionContext context) { + context.getThrowableCollector().assertEmpty(); + return SkipResult.doNotSkip(); + } + + @Override + public JupiterEngineExecutionContext before(JupiterEngineExecutionContext context) throws Exception { + invokeBeforeCallbacks(BeforeClassTemplateInvocationCallback.class, context, + BeforeClassTemplateInvocationCallback::beforeClassTemplateInvocation); + context.getThrowableCollector().assertEmpty(); + return context; + } + + @Override + public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext context, + DynamicTestExecutor dynamicTestExecutor) throws Exception { + Visitor visitor = context.getExecutionListener()::dynamicTestRegistered; + getChildren().forEach(child -> child.accept(visitor)); + return context; + } + + @Override + public void after(JupiterEngineExecutionContext context) throws Exception { + + ThrowableCollector throwableCollector = context.getThrowableCollector(); + Throwable previousThrowable = throwableCollector.getThrowable(); + + invokeAfterCallbacks(AfterClassTemplateInvocationCallback.class, context, + AfterClassTemplateInvocationCallback::afterClassTemplateInvocation); + + // If the previous Throwable was not null when this method was called, + // that means an exception was already thrown either before or during + // the execution of this Node. If an exception was already thrown, any + // later exceptions were added as suppressed exceptions to that original + // exception unless a more severe exception occurred in the meantime. + if (previousThrowable != throwableCollector.getThrowable()) { + throwableCollector.assertEmpty(); + } + } + + @Override + public void cleanUp(JupiterEngineExecutionContext context) throws Exception { + // forget invocationContext so it can be garbage collected + this.invocationContext = null; + super.cleanUp(context); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateTestDescriptor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,278 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static java.util.stream.Collectors.toCollection; +import static java.util.stream.Collectors.toList; +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD; +import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.validateClassTemplateInvocationLifecycleMethodsAreDeclaredCorrectly; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.ClassTemplate; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContextProvider; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestInstances; +import org.junit.jupiter.api.parallel.ResourceLocksProvider; +import org.junit.jupiter.engine.execution.ExtensionContextSupplier; +import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; +import org.junit.jupiter.engine.extension.ExtensionRegistry; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestTag; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.engine.support.hierarchical.ExclusiveResource; +import org.junit.platform.engine.support.hierarchical.Node; + +/** + * @since 5.13 + */ +@API(status = INTERNAL, since = "5.13") +public class ClassTemplateTestDescriptor extends ClassBasedTestDescriptor implements Filterable { + + public static final String STANDALONE_CLASS_SEGMENT_TYPE = "class-template"; + public static final String NESTED_CLASS_SEGMENT_TYPE = "nested-class-template"; + + private final Map> childrenPrototypesByIndex = new HashMap<>(); + private final List childrenPrototypes = new ArrayList<>(); + private final ClassBasedTestDescriptor delegate; + private final DynamicDescendantFilter dynamicDescendantFilter; + + public ClassTemplateTestDescriptor(UniqueId uniqueId, ClassBasedTestDescriptor delegate) { + this(uniqueId, delegate, new DynamicDescendantFilter()); + } + + private ClassTemplateTestDescriptor(UniqueId uniqueId, ClassBasedTestDescriptor delegate, + DynamicDescendantFilter dynamicDescendantFilter) { + super(uniqueId, delegate.getTestClass(), delegate.getDisplayName(), delegate.configuration); + this.delegate = delegate; + this.dynamicDescendantFilter = dynamicDescendantFilter; + } + + // --- TestDescriptor ------------------------------------------------------ + + @Override + public Set getTags() { + return this.delegate.getTags(); + } + + // --- Validatable --------------------------------------------------------- + + @Override + protected void validateCoreLifecycleMethods(DiscoveryIssueReporter reporter) { + this.delegate.validateCoreLifecycleMethods(reporter); + } + + @Override + protected void validateClassTemplateInvocationLifecycleMethods(DiscoveryIssueReporter reporter) { + boolean requireStatic = this.classInfo.lifecycle == PER_METHOD; + validateClassTemplateInvocationLifecycleMethodsAreDeclaredCorrectly(getTestClass(), requireStatic, reporter); + } + + // --- Filterable ---------------------------------------------------------- + + @Override + public DynamicDescendantFilter getDynamicDescendantFilter() { + return this.dynamicDescendantFilter; + } + + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected JupiterTestDescriptor copyIncludingDescendants(UnaryOperator uniqueIdTransformer) { + ClassTemplateTestDescriptor copy = (ClassTemplateTestDescriptor) super.copyIncludingDescendants( + uniqueIdTransformer); + this.childrenPrototypes.forEach(oldChild -> { + TestDescriptor newChild = ((JupiterTestDescriptor) oldChild).copyIncludingDescendants(uniqueIdTransformer); + copy.childrenPrototypes.add(newChild); + }); + this.childrenPrototypesByIndex.forEach((index, oldChildren) -> { + List newChildren = oldChildren.stream() // + .map(oldChild -> ((JupiterTestDescriptor) oldChild).copyIncludingDescendants(uniqueIdTransformer)) // + .collect(toList()); + copy.childrenPrototypesByIndex.put(index, newChildren); + }); + return copy; + } + + @Override + protected ClassTemplateTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new ClassTemplateTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), this.delegate, + this.dynamicDescendantFilter.copy(uniqueIdTransformer)); + } + + // --- TestDescriptor ------------------------------------------------------ + + @Override + public void prune() { + super.prune(); + if (this.children.isEmpty()) { + return; + } + // Create copy to avoid ConcurrentModificationException + new LinkedHashSet<>(this.children).forEach(child -> child.accept(TestDescriptor::prune)); + // Second iteration to avoid processing children that were pruned in the first iteration + this.children.forEach(child -> { + if (child instanceof ClassTemplateInvocationTestDescriptor) { + int index = ((ClassTemplateInvocationTestDescriptor) child).getIndex(); + this.dynamicDescendantFilter.allowIndex(index - 1); + this.childrenPrototypesByIndex.put(index, child.getChildren()); + } + else { + this.childrenPrototypes.add(child); + } + }); + this.children.clear(); + } + + @Override + public boolean mayRegisterTests() { + return !childrenPrototypes.isEmpty() || !childrenPrototypesByIndex.isEmpty(); + } + + // --- TestClassAware ------------------------------------------------------ + + @Override + public List> getEnclosingTestClasses() { + return delegate.getEnclosingTestClasses(); + } + + // --- ClassBasedTestDescriptor -------------------------------------------- + + @Override + public TestInstances instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext, + ExtensionContextSupplier extensionContext, ExtensionRegistry registry, + JupiterEngineExecutionContext context) { + return delegate.instantiateTestClass(parentExecutionContext, extensionContext, registry, context); + } + + // --- ResourceLockAware --------------------------------------------------- + + @Override + public Function> getResourceLocksProviderEvaluator() { + return delegate.getResourceLocksProviderEvaluator(); + } + + // --- Node ---------------------------------------------------------------- + + @Override + public Set getExclusiveResources() { + Set result = determineExclusiveResources().collect(toCollection(HashSet::new)); + Visitor visitor = testDescriptor -> { + if (testDescriptor instanceof Node) { + result.addAll(((Node) testDescriptor).getExclusiveResources()); + } + }; + this.childrenPrototypes.forEach(child -> child.accept(visitor)); + this.childrenPrototypesByIndex.values() // + .forEach(prototypes -> prototypes // + .forEach(child -> child.accept(visitor))); + return result; + } + + @Override + public void cleanUp(JupiterEngineExecutionContext context) throws Exception { + this.childrenPrototypes.clear(); + this.childrenPrototypesByIndex.clear(); + this.dynamicDescendantFilter.allowAll(); + super.cleanUp(context); + } + + @Override + public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext context, + DynamicTestExecutor dynamicTestExecutor) throws Exception { + + new ClassTemplateExecutor().execute(context, dynamicTestExecutor); + return context; + } + + class ClassTemplateExecutor + extends TemplateExecutor { + + public ClassTemplateExecutor() { + super(ClassTemplateTestDescriptor.this, ClassTemplateInvocationContextProvider.class); + } + + @Override + boolean supports(ClassTemplateInvocationContextProvider provider, ExtensionContext extensionContext) { + return provider.supportsClassTemplate(extensionContext); + } + + @Override + protected String getNoRegisteredProviderErrorMessage() { + return String.format("You must register at least one %s that supports @%s class [%s]", + ClassTemplateInvocationContextProvider.class.getSimpleName(), ClassTemplate.class.getSimpleName(), + getTestClass().getName()); + } + + @Override + Stream provideContexts( + ClassTemplateInvocationContextProvider provider, ExtensionContext extensionContext) { + return provider.provideClassTemplateInvocationContexts(extensionContext); + } + + @Override + boolean mayReturnZeroContexts(ClassTemplateInvocationContextProvider provider, + ExtensionContext extensionContext) { + return provider.mayReturnZeroClassTemplateInvocationContexts(extensionContext); + } + + @Override + protected String getZeroContextsProvidedErrorMessage(ClassTemplateInvocationContextProvider provider) { + return String.format( + "Provider [%s] did not provide any invocation contexts, but was expected to do so. " + + "You may override mayReturnZeroClassTemplateInvocationContexts() to allow this.", + provider.getClass().getSimpleName()); + } + + @Override + UniqueId createInvocationUniqueId(UniqueId parentUniqueId, int index) { + return parentUniqueId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#" + index); + } + + @Override + TestDescriptor createInvocationTestDescriptor(UniqueId uniqueId, + ClassTemplateInvocationContext invocationContext, int index) { + ClassTemplateInvocationTestDescriptor containerInvocationDescriptor = new ClassTemplateInvocationTestDescriptor( + uniqueId, ClassTemplateTestDescriptor.this, invocationContext, index, getSource().orElse(null), + ClassTemplateTestDescriptor.this.configuration); + + collectChildren(index, uniqueId) // + .forEach(containerInvocationDescriptor::addChild); + + return containerInvocationDescriptor; + } + + private Stream collectChildren(int index, UniqueId invocationUniqueId) { + if (ClassTemplateTestDescriptor.this.childrenPrototypesByIndex.containsKey(index)) { + return ClassTemplateTestDescriptor.this.childrenPrototypesByIndex.remove(index).stream(); + } + UnaryOperator transformer = new UniqueIdPrefixTransformer(getUniqueId(), invocationUniqueId); + return ClassTemplateTestDescriptor.this.childrenPrototypes.stream() // + .map(JupiterTestDescriptor.class::cast) // + .map(it -> it.copyIncludingDescendants(transformer)); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,18 +18,19 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Function; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; -import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; +import org.junit.jupiter.api.parallel.ResourceLocksProvider; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.ExtensionContextSupplier; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; -import org.junit.jupiter.engine.extension.ExtensionRegistrar; import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.support.hierarchical.ThrowableCollector; /** * {@link TestDescriptor} for tests based on Java classes. @@ -51,14 +52,29 @@ super(uniqueId, testClass, createDisplayNameSupplierForClass(testClass, configuration), configuration); } + private ClassTestDescriptor(UniqueId uniqueId, Class testClass, String displayName, + JupiterConfiguration configuration) { + super(uniqueId, testClass, displayName, configuration); + } + + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected ClassTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new ClassTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), getTestClass(), getDisplayName(), + configuration); + } + // --- TestDescriptor ------------------------------------------------------ @Override public Set getTags() { // return modifiable copy - return new LinkedHashSet<>(this.tags); + return new LinkedHashSet<>(this.classInfo.tags); } + // --- TestClassAware ------------------------------------------------------ + @Override public List> getEnclosingTestClasses() { return emptyList(); @@ -72,11 +88,20 @@ () -> JupiterTestDescriptor.toExecutionMode(configuration.getDefaultClassesExecutionMode())); } + // --- ClassBasedTestDescriptor -------------------------------------------- + @Override protected TestInstances instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext, - ExtensionRegistry registry, ExtensionRegistrar registrar, ExtensionContext extensionContext, - ThrowableCollector throwableCollector) { + ExtensionContextSupplier extensionContext, ExtensionRegistry registry, + JupiterEngineExecutionContext context) { return instantiateTestClass(Optional.empty(), registry, extensionContext); } + // --- ResourceLockAware --------------------------------------------------- + + @Override + public Function> getResourceLocksProviderEvaluator() { + return provider -> provider.provideForClass(getTestClass()); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultDynamicTestInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultDynamicTestInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultDynamicTestInvocationContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultDynamicTestInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultTestInstanceFactoryContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultTestInstanceFactoryContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultTestInstanceFactoryContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DefaultTestInstanceFactoryContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,12 +10,16 @@ package org.junit.jupiter.engine.descriptor; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; import java.util.Optional; -import java.util.function.Function; +import java.util.function.BiFunction; import java.util.function.Supplier; import org.junit.jupiter.api.DisplayName; @@ -26,12 +30,13 @@ import org.junit.jupiter.api.DisplayNameGenerator.Simple; import org.junit.jupiter.api.DisplayNameGenerator.Standard; import org.junit.jupiter.engine.config.JupiterConfiguration; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.AnnotationUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Collection of utilities for working with display names. @@ -43,8 +48,6 @@ */ final class DisplayNameUtils { - private static final Logger logger = LoggerFactory.getLogger(DisplayNameUtils.class); - /** * Pre-defined standard display name generator instance. */ @@ -71,58 +74,74 @@ static String determineDisplayName(AnnotatedElement element, Supplier displayNameSupplier) { Preconditions.notNull(element, "Annotated element must not be null"); - Optional displayNameAnnotation = findAnnotation(element, DisplayName.class); - if (displayNameAnnotation.isPresent()) { - String displayName = displayNameAnnotation.get().value().trim(); - - // TODO [#242] Replace logging with precondition check once we have a proper mechanism for - // handling validation exceptions during the TestEngine discovery phase. - if (StringUtils.isBlank(displayName)) { - logger.warn(() -> String.format( - "Configuration error: @DisplayName on [%s] must be declared with a non-empty value.", element)); - } - else { - return displayName; - } - } - // else let a 'DisplayNameGenerator' generate a display name - return displayNameSupplier.get(); + return findAnnotation(element, DisplayName.class) // + .map(DisplayName::value) // + .filter(StringUtils::isNotBlank) // + .map(String::trim) // + .orElseGet(displayNameSupplier); + } + + static void validateAnnotation(AnnotatedElement element, Supplier elementDescription, + Supplier sourceProvider, DiscoveryIssueReporter reporter) { + findAnnotation(element, DisplayName.class) // + .map(DisplayName::value) // + .filter(StringUtils::isBlank) // + .ifPresent(__ -> { + String message = String.format("@DisplayName on %s must be declared with a non-blank value.", + elementDescription.get()); + reporter.reportIssue( + DiscoveryIssue.builder(Severity.WARNING, message).source(sourceProvider.get()).build()); + }); } - static String determineDisplayNameForMethod(Class testClass, Method testMethod, - JupiterConfiguration configuration) { + static String determineDisplayNameForMethod(Supplier>> enclosingInstanceTypes, Class testClass, + Method testMethod, JupiterConfiguration configuration) { return determineDisplayName(testMethod, - createDisplayNameSupplierForMethod(testClass, testMethod, configuration)); + createDisplayNameSupplierForMethod(enclosingInstanceTypes, testClass, testMethod, configuration)); } static Supplier createDisplayNameSupplierForClass(Class testClass, JupiterConfiguration configuration) { - return createDisplayNameSupplier(testClass, configuration, - generator -> generator.generateDisplayNameForClass(testClass)); + return createDisplayNameSupplier(Collections::emptyList, testClass, configuration, + (generator, __) -> generator.generateDisplayNameForClass(testClass)); } - static Supplier createDisplayNameSupplierForNestedClass(Class testClass, + static Supplier createDisplayNameSupplierForNestedClass( + Supplier>> enclosingInstanceTypesSupplier, Class testClass, JupiterConfiguration configuration) { - return createDisplayNameSupplier(testClass, configuration, - generator -> generator.generateDisplayNameForNestedClass(testClass)); + return createDisplayNameSupplier(enclosingInstanceTypesSupplier, testClass, configuration, + (generator, enclosingInstanceTypes) -> generator.generateDisplayNameForNestedClass(enclosingInstanceTypes, + testClass)); } - private static Supplier createDisplayNameSupplierForMethod(Class testClass, Method testMethod, + private static Supplier createDisplayNameSupplierForMethod( + Supplier>> enclosingInstanceTypesSupplier, Class testClass, Method testMethod, JupiterConfiguration configuration) { - return createDisplayNameSupplier(testClass, configuration, - generator -> generator.generateDisplayNameForMethod(testClass, testMethod)); + return createDisplayNameSupplier(enclosingInstanceTypesSupplier, testClass, configuration, + (generator, enclosingInstanceTypes) -> generator.generateDisplayNameForMethod(enclosingInstanceTypes, + testClass, testMethod)); + } + + private static Supplier createDisplayNameSupplier(Supplier>> enclosingInstanceTypesSupplier, + Class testClass, JupiterConfiguration configuration, + BiFunction>, String> generatorFunction) { + return () -> { + List> enclosingInstanceTypes = makeUnmodifiable(enclosingInstanceTypesSupplier.get()); + return findDisplayNameGenerator(enclosingInstanceTypes, testClass) // + .map(it -> generatorFunction.apply(it, enclosingInstanceTypes)) // + .orElseGet(() -> generatorFunction.apply(configuration.getDefaultDisplayNameGenerator(), + enclosingInstanceTypes)); + }; } - private static Supplier createDisplayNameSupplier(Class testClass, JupiterConfiguration configuration, - Function generatorFunction) { - return () -> findDisplayNameGenerator(testClass) // - .map(generatorFunction) // - .orElseGet(() -> generatorFunction.apply(configuration.getDefaultDisplayNameGenerator())); + private static List makeUnmodifiable(List list) { + return list.isEmpty() ? emptyList() : unmodifiableList(list); } - private static Optional findDisplayNameGenerator(Class testClass) { + private static Optional findDisplayNameGenerator(List> enclosingInstanceTypes, + Class testClass) { Preconditions.notNull(testClass, "Test class must not be null"); - return AnnotationUtils.findAnnotation(testClass, DisplayNameGeneration.class, true) // + return findAnnotation(testClass, DisplayNameGeneration.class, enclosingInstanceTypes) // .map(DisplayNameGeneration::value) // .map(displayNameGeneratorClass -> { if (displayNameGeneratorClass == Standard.class) { @@ -137,7 +156,7 @@ if (displayNameGeneratorClass == IndicativeSentences.class) { return indicativeSentencesGenerator; } - return ReflectionUtils.newInstance(displayNameGeneratorClass); + return ReflectionSupport.newInstance(displayNameGeneratorClass); }); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicContainerTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicContainerTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicContainerTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicContainerTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.UnaryOperator; import java.util.stream.Stream; import org.junit.jupiter.api.DynamicContainer; @@ -47,6 +48,12 @@ } @Override + protected DynamicContainerTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new DynamicContainerTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), this.index, + this.dynamicContainer, this.testSource, this.dynamicDescendantFilter, this.configuration); + } + + @Override public Type getType() { return Type.CONTAINER; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicDescendantFilter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicDescendantFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicDescendantFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicDescendantFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,6 +15,7 @@ import java.util.HashSet; import java.util.Set; import java.util.function.BiPredicate; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; import org.junit.platform.engine.TestDescriptor; @@ -40,6 +41,12 @@ } } + public void allowIndex(int index) { + if (this.mode == Mode.EXPLICIT) { + this.allowedIndices.add(index); + } + } + public void allowIndex(Set indices) { if (this.mode == Mode.EXPLICIT) { this.allowedIndices.addAll(indices); @@ -79,6 +86,18 @@ EXPLICIT, ALLOW_ALL } + public DynamicDescendantFilter copy(UnaryOperator uniqueIdTransformer) { + return configure(uniqueIdTransformer, new DynamicDescendantFilter()); + } + + protected DynamicDescendantFilter configure(UnaryOperator uniqueIdTransformer, + DynamicDescendantFilter copy) { + this.allowedUniqueIds.stream().map(uniqueIdTransformer).forEach(copy.allowedUniqueIds::add); + copy.allowedIndices.addAll(this.allowedIndices); + copy.mode = this.mode; + return copy; + } + private class WithoutIndexFiltering extends DynamicDescendantFilter { @Override @@ -90,5 +109,10 @@ public DynamicDescendantFilter withoutIndexFiltering() { return this; } + + @Override + public DynamicDescendantFilter copy(UnaryOperator uniqueIdTransformer) { + return configure(uniqueIdTransformer, new WithoutIndexFiltering()); + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicExtensionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,16 +10,19 @@ package org.junit.jupiter.engine.descriptor; +import static java.util.Collections.emptyList; + import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; -import java.util.function.Function; import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.extension.ExecutableInvoker; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.support.hierarchical.Node; @@ -27,8 +30,8 @@ DynamicExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, DynamicNodeTestDescriptor testDescriptor, JupiterConfiguration configuration, - Function executableInvokerFactory) { - super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory); + ExtensionRegistry extensionRegistry, LauncherStoreFacade launcherStoreFacade) { + super(parent, engineExecutionListener, testDescriptor, configuration, extensionRegistry, launcherStoreFacade); } @Override @@ -42,6 +45,11 @@ } @Override + public List> getEnclosingTestClasses() { + return emptyList(); + } + + @Override public Optional getTestInstanceLifecycle() { return Optional.empty(); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicNodeTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicNodeTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicNodeTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicNodeTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,8 +11,8 @@ package org.junit.jupiter.engine.descriptor; import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.engine.config.JupiterConfiguration; -import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestSource; @@ -25,7 +25,7 @@ */ abstract class DynamicNodeTestDescriptor extends JupiterTestDescriptor { - private final int index; + protected final int index; DynamicNodeTestDescriptor(UniqueId uniqueId, int index, DynamicNode dynamicNode, TestSource testSource, JupiterConfiguration configuration) { @@ -45,9 +45,9 @@ @Override public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) { - DynamicExtensionContext extensionContext = new DynamicExtensionContext(context.getExtensionContext(), - context.getExecutionListener(), this, context.getConfiguration(), - it -> new DefaultExecutableInvoker(it, context.getExtensionRegistry())); + ExtensionContext extensionContext = new DynamicExtensionContext(context.getExtensionContext(), + context.getExecutionListener(), this, context.getConfiguration(), context.getExtensionRegistry(), + context.getLauncherStoreFacade()); // @formatter:off return context.extend() .withExtensionContext(extensionContext) diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicTestTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicTestTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicTestTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DynamicTestTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,8 @@ package org.junit.jupiter.engine.descriptor; +import java.util.function.UnaryOperator; + import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.extension.DynamicTestInvocationContext; import org.junit.jupiter.api.extension.ExtensionContext; @@ -42,6 +44,12 @@ } @Override + protected DynamicTestTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new DynamicTestTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), this.index, this.dynamicTest, + this.getSource().orElse(null), this.configuration); + } + + @Override public Type getType() { return Type.TEST; } @@ -70,7 +78,7 @@ * on the heap. * * @since 5.5 - * @see Issue 1865 + * @see Issue 1865 */ @Override public void after(JupiterEngineExecutionContext context) throws Exception { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExclusiveResourceCollector.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExclusiveResourceCollector.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExclusiveResourceCollector.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExclusiveResourceCollector.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,122 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static org.junit.jupiter.api.parallel.ResourceLockTarget.SELF; +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; +import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; + +import java.lang.reflect.AnnotatedElement; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.junit.jupiter.api.parallel.ResourceAccessMode; +import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.parallel.ResourceLockTarget; +import org.junit.jupiter.api.parallel.ResourceLocksProvider; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.util.StringUtils; +import org.junit.platform.engine.support.hierarchical.ExclusiveResource; + +/** + * @since 5.12 + */ +abstract class ExclusiveResourceCollector { + + private static final ExclusiveResourceCollector NO_EXCLUSIVE_RESOURCES = new ExclusiveResourceCollector() { + + @Override + Stream getAllExclusiveResources( + Function> providerToLocks) { + return Stream.empty(); + } + + @Override + Stream getStaticResourcesFor(ResourceLockTarget target) { + return Stream.empty(); + } + + @Override + Stream getDynamicResources( + Function> providerToLocks) { + return Stream.empty(); + } + }; + + Stream getAllExclusiveResources( + Function> providerToLocks) { + return Stream.concat(getStaticResourcesFor(SELF), getDynamicResources(providerToLocks)); + } + + abstract Stream getStaticResourcesFor(ResourceLockTarget target); + + abstract Stream getDynamicResources( + Function> providerToLocks); + + static ExclusiveResourceCollector from(AnnotatedElement element) { + List annotations = findRepeatableAnnotations(element, ResourceLock.class); + return annotations.isEmpty() ? NO_EXCLUSIVE_RESOURCES : new DefaultExclusiveResourceCollector(annotations); + } + + private static class DefaultExclusiveResourceCollector extends ExclusiveResourceCollector { + + private final List annotations; + private List providers; + + DefaultExclusiveResourceCollector(List annotations) { + this.annotations = annotations; + } + + @Override + Stream getStaticResourcesFor(ResourceLockTarget target) { + return annotations.stream() // + .filter(annotation -> StringUtils.isNotBlank(annotation.value())) // + .filter(annotation -> annotation.target() == target) // + .map(annotation -> new ExclusiveResource(annotation.value(), toLockMode(annotation.mode()))); + } + + @Override + Stream getDynamicResources( + Function> providerToLocks) { + List providers = getProviders(); + if (providers.isEmpty()) { + return Stream.empty(); + } + return providers.stream() // + .map(providerToLocks) // + .flatMap(Collection::stream) // + .map(lock -> new ExclusiveResource(lock.getKey(), toLockMode(lock.getAccessMode()))); + } + + private List getProviders() { + if (this.providers == null) { + this.providers = annotations.stream() // + .flatMap(annotation -> Stream.of(annotation.providers()).map(ReflectionUtils::newInstance)) // + .collect(toUnmodifiableList()); + } + return providers; + } + + private static ExclusiveResource.LockMode toLockMode(ResourceAccessMode mode) { + switch (mode) { + case READ: + return ExclusiveResource.LockMode.READ; + case READ_WRITE: + return ExclusiveResource.LockMode.READ_WRITE; + } + throw new JUnitException("Unknown ResourceAccessMode: " + mode); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExtensionUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExtensionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExtensionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ExtensionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,9 +11,9 @@ package org.junit.jupiter.engine.descriptor; import static java.util.stream.Collectors.toList; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.TOP_DOWN; import static org.junit.platform.commons.util.ReflectionUtils.getDeclaredConstructor; import static org.junit.platform.commons.util.ReflectionUtils.streamFields; @@ -36,6 +36,7 @@ import org.junit.jupiter.engine.extension.ExtensionRegistrar; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.ModifierSupport; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; @@ -89,7 +90,7 @@ * @since 5.11 */ static void registerExtensionsFromStaticFields(ExtensionRegistrar registrar, Class clazz) { - streamExtensionRegisteringFields(clazz, ReflectionUtils::isStatic) // + streamExtensionRegisteringFields(clazz, ModifierSupport::isStatic) // .forEach(field -> { List> extensionTypes = streamDeclarativeExtensionTypes(field).collect( toList()); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Filterable.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Filterable.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Filterable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Filterable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,7 +16,6 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.engine.config.JupiterConfiguration; -import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; import org.junit.platform.engine.EngineExecutionListener; @@ -53,7 +52,7 @@ context.getConfiguration()); EngineExecutionListener executionListener = context.getExecutionListener(); ExtensionContext extensionContext = new JupiterEngineExtensionContext(executionListener, this, - context.getConfiguration(), it -> new DefaultExecutableInvoker(it, extensionRegistry)); + context.getConfiguration(), extensionRegistry, context.getLauncherStoreFacade()); // @formatter:off return context.extend() diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineExtensionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterEngineExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,16 +10,18 @@ package org.junit.jupiter.engine.descriptor; +import static java.util.Collections.emptyList; + import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; -import java.util.function.Function; import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.jupiter.api.extension.ExecutableInvoker; -import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.support.hierarchical.Node; @@ -30,9 +32,9 @@ JupiterEngineExtensionContext(EngineExecutionListener engineExecutionListener, JupiterEngineDescriptor testDescriptor, JupiterConfiguration configuration, - Function executableInvokerFactory) { + ExtensionRegistry extensionRegistry, LauncherStoreFacade launcherStoreFacade) { - super(null, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory); + super(null, engineExecutionListener, testDescriptor, configuration, extensionRegistry, launcherStoreFacade); } @Override @@ -46,6 +48,11 @@ } @Override + public List> getEnclosingTestClasses() { + return emptyList(); + } + + @Override public Optional getTestInstanceLifecycle() { return Optional.empty(); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,13 +10,14 @@ package org.junit.jupiter.engine.descriptor; +import static java.util.Collections.emptySet; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toSet; import static org.apiguardian.api.API.Status.INTERNAL; import static org.junit.jupiter.engine.descriptor.DisplayNameUtils.determineDisplayName; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; -import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; import java.lang.reflect.AnnotatedElement; import java.util.Collections; @@ -24,31 +25,32 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ResourceAccessMode; -import org.junit.jupiter.api.parallel.ResourceLock; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.execution.ConditionEvaluator; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.UnrecoverableExceptions; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor; import org.junit.platform.engine.support.hierarchical.ExclusiveResource; -import org.junit.platform.engine.support.hierarchical.ExclusiveResource.LockMode; import org.junit.platform.engine.support.hierarchical.Node; /** @@ -58,8 +60,6 @@ public abstract class JupiterTestDescriptor extends AbstractTestDescriptor implements Node { - private static final Logger logger = LoggerFactory.getLogger(JupiterTestDescriptor.class); - private static final ConditionEvaluator conditionEvaluator = new ConditionEvaluator(); final JupiterConfiguration configuration; @@ -77,27 +77,27 @@ // --- TestDescriptor ------------------------------------------------------ - static Set getTags(AnnotatedElement element) { - // @formatter:off - return findRepeatableAnnotations(element, Tag.class).stream() - .map(Tag::value) + static Set getTags(AnnotatedElement element, Supplier elementDescription, + Supplier sourceProvider, Consumer issueCollector) { + AtomicReference source = new AtomicReference<>(); + return findRepeatableAnnotations(element, Tag.class).stream() // + .map(Tag::value) // .filter(tag -> { boolean isValid = TestTag.isValid(tag); if (!isValid) { - // TODO [#242] Replace logging with precondition check once we have a proper mechanism for - // handling validation exceptions during the TestEngine discovery phase. - // - // As an alternative to a precondition check here, we could catch any - // PreconditionViolationException thrown by TestTag::create. - logger.warn(() -> String.format( - "Configuration error: invalid tag syntax in @Tag(\"%s\") declaration on [%s]. Tag will be ignored.", - tag, element)); + String message = String.format( + "Invalid tag syntax in @Tag(\"%s\") declaration on %s. Tag will be ignored.", tag, + elementDescription.get()); + if (source.get() == null) { + source.set(sourceProvider.get()); + } + issueCollector.accept( + DiscoveryIssue.builder(Severity.WARNING, message).source(source.get()).build()); } return isValid; - }) - .map(TestTag::create) + }) // + .map(TestTag::create) // .collect(collectingAndThen(toCollection(LinkedHashSet::new), Collections::unmodifiableSet)); - // @formatter:on } /** @@ -180,26 +180,16 @@ throw new JUnitException("Unknown ExecutionMode: " + mode); } - Set getExclusiveResourcesFromAnnotation(AnnotatedElement element) { - // @formatter:off - return findRepeatableAnnotations(element, ResourceLock.class).stream() - .map(resource -> new ExclusiveResource(resource.value(), toLockMode(resource.mode()))) - .collect(toSet()); - // @formatter:on - } - - private static LockMode toLockMode(ResourceAccessMode mode) { - switch (mode) { - case READ: - return LockMode.READ; - case READ_WRITE: - return LockMode.READ_WRITE; + @Override + public Set getExclusiveResources() { + if (this instanceof ResourceLockAware) { + return ((ResourceLockAware) this).determineExclusiveResources().collect(toSet()); } - throw new JUnitException("Unknown ResourceAccessMode: " + mode); + return emptySet(); } @Override - public SkipResult shouldBeSkipped(JupiterEngineExecutionContext context) throws Exception { + public SkipResult shouldBeSkipped(JupiterEngineExecutionContext context) { context.getThrowableCollector().assertEmpty(); ConditionEvaluationResult evaluationResult = conditionEvaluator.evaluate(context.getExtensionRegistry(), context.getConfiguration(), context.getExtensionContext()); @@ -214,7 +204,8 @@ } /** - * Must be overridden and return a new context so cleanUp() does not accidentally close the parent context. + * Must be overridden and return a new context with a new {@link ExtensionContext} + * so cleanUp() does not accidentally close the parent context. */ @Override public abstract JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) throws Exception; @@ -225,6 +216,23 @@ } /** + * {@return a deep copy (with copies of children) of this descriptor with the supplied unique ID} + */ + protected JupiterTestDescriptor copyIncludingDescendants(UnaryOperator uniqueIdTransformer) { + JupiterTestDescriptor result = withUniqueId(uniqueIdTransformer); + getChildren().forEach(oldChild -> { + TestDescriptor newChild = ((JupiterTestDescriptor) oldChild).copyIncludingDescendants(uniqueIdTransformer); + result.addChild(newChild); + }); + return result; + } + + /** + * {@return shallow copy (without children) of this descriptor with the supplied unique ID} + */ + protected abstract JupiterTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer); + + /** * @since 5.5 */ @FunctionalInterface diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,20 +10,32 @@ package org.junit.jupiter.engine.descriptor; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedMethods; -import static org.junit.platform.commons.util.ReflectionUtils.returnsPrimitiveVoid; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedMethods; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; +import static org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.Condition.alwaysSatisfied; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.platform.commons.JUnitException; +import org.junit.jupiter.api.extension.ClassTemplateInvocationLifecycleMethod; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ModifierSupport; import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.Condition; /** * Collection of utilities for working with test lifecycle methods. @@ -36,70 +48,156 @@ /* no-op */ } - static List findBeforeAllMethods(Class testClass, boolean requireStatic) { - return findMethodsAndAssertStaticAndNonPrivate(testClass, requireStatic, BeforeAll.class, - HierarchyTraversalMode.TOP_DOWN); + static List findBeforeAllMethods(Class testClass, boolean requireStatic, + DiscoveryIssueReporter issueReporter) { + return findMethodsAndCheckStatic(testClass, requireStatic, BeforeAll.class, HierarchyTraversalMode.TOP_DOWN, + issueReporter); } - static List findAfterAllMethods(Class testClass, boolean requireStatic) { - return findMethodsAndAssertStaticAndNonPrivate(testClass, requireStatic, AfterAll.class, - HierarchyTraversalMode.BOTTOM_UP); + static List findAfterAllMethods(Class testClass, boolean requireStatic, + DiscoveryIssueReporter issueReporter) { + return findMethodsAndCheckStatic(testClass, requireStatic, AfterAll.class, HierarchyTraversalMode.BOTTOM_UP, + issueReporter); } - static List findBeforeEachMethods(Class testClass) { - return findMethodsAndAssertNonStaticAndNonPrivate(testClass, BeforeEach.class, HierarchyTraversalMode.TOP_DOWN); + static List findBeforeEachMethods(Class testClass, DiscoveryIssueReporter issueReporter) { + return findMethodsAndCheckNonStatic(testClass, BeforeEach.class, HierarchyTraversalMode.TOP_DOWN, + issueReporter); } - static List findAfterEachMethods(Class testClass) { - return findMethodsAndAssertNonStaticAndNonPrivate(testClass, AfterEach.class, HierarchyTraversalMode.BOTTOM_UP); + static List findAfterEachMethods(Class testClass, DiscoveryIssueReporter issueReporter) { + return findMethodsAndCheckNonStatic(testClass, AfterEach.class, HierarchyTraversalMode.BOTTOM_UP, + issueReporter); } - private static List findMethodsAndAssertStaticAndNonPrivate(Class testClass, boolean requireStatic, - Class annotationType, HierarchyTraversalMode traversalMode) { + static void validateNoClassTemplateInvocationLifecycleMethodsAreDeclared(Class testClass, + DiscoveryIssueReporter issueReporter) { - List methods = findMethodsAndCheckVoidReturnType(testClass, annotationType, traversalMode); - if (requireStatic) { - methods.forEach(method -> assertStatic(annotationType, method)); - } - return methods; + findAllClassTemplateInvocationLifecycleMethods(testClass) // + .forEach(method -> findClassTemplateInvocationLifecycleMethodAnnotation(method) // + .ifPresent(annotation -> { + String message = String.format( + "@%s method '%s' must not be declared in test class '%s' because it is not annotated with @%s.", + annotation.lifecycleMethodAnnotation().getSimpleName(), method.toGenericString(), + testClass.getName(), annotation.classTemplateAnnotation().getSimpleName()); + issueReporter.reportIssue(createIssue(Severity.ERROR, message, method)); + })); } - private static List findMethodsAndAssertNonStaticAndNonPrivate(Class testClass, - Class annotationType, HierarchyTraversalMode traversalMode) { + static void validateClassTemplateInvocationLifecycleMethodsAreDeclaredCorrectly(Class testClass, + boolean requireStatic, DiscoveryIssueReporter issueReporter) { - List methods = findMethodsAndCheckVoidReturnType(testClass, annotationType, traversalMode); - methods.forEach(method -> assertNonStatic(annotationType, method)); - return methods; + findAllClassTemplateInvocationLifecycleMethods(testClass) // + .forEach(isNotPrivateError(issueReporter) // + .and(returnsPrimitiveVoid(issueReporter, + LifecycleMethodUtils::classTemplateInvocationLifecycleMethodAnnotationName)) // + .and(requireStatic + ? isStatic(issueReporter, + LifecycleMethodUtils::classTemplateInvocationLifecycleMethodAnnotationName) + : alwaysSatisfied()) // + .toConsumer()); + } + + private static Stream findAllClassTemplateInvocationLifecycleMethods(Class testClass) { + Stream allMethods = Stream.concat( // + findAnnotatedMethods(testClass, ClassTemplateInvocationLifecycleMethod.class, + HierarchyTraversalMode.TOP_DOWN).stream(), // + findAnnotatedMethods(testClass, ClassTemplateInvocationLifecycleMethod.class, + HierarchyTraversalMode.BOTTOM_UP).stream() // + ); + return allMethods.distinct(); + } + + private static List findMethodsAndCheckStatic(Class testClass, boolean requireStatic, + Class annotationType, HierarchyTraversalMode traversalMode, + DiscoveryIssueReporter issueReporter) { + + Condition additionalCondition = requireStatic + ? isStatic(issueReporter, __ -> annotationType.getSimpleName()) + : alwaysSatisfied(); + return findMethodsAndCheckVoidReturnType(testClass, annotationType, traversalMode, issueReporter, + additionalCondition); + } + + private static List findMethodsAndCheckNonStatic(Class testClass, + Class annotationType, HierarchyTraversalMode traversalMode, + DiscoveryIssueReporter issueReporter) { + + return findMethodsAndCheckVoidReturnType(testClass, annotationType, traversalMode, issueReporter, + isNotStatic(issueReporter, __ -> annotationType.getSimpleName())); } private static List findMethodsAndCheckVoidReturnType(Class testClass, - Class annotationType, HierarchyTraversalMode traversalMode) { + Class annotationType, HierarchyTraversalMode traversalMode, + DiscoveryIssueReporter issueReporter, Condition additionalCondition) { - List methods = findAnnotatedMethods(testClass, annotationType, traversalMode); - methods.forEach(method -> assertVoid(annotationType, method)); - return methods; + return findAnnotatedMethods(testClass, annotationType, traversalMode).stream() // + .peek(isNotPrivateWarning(issueReporter, annotationType::getSimpleName).toConsumer()) // + .filter(returnsPrimitiveVoid(issueReporter, __ -> annotationType.getSimpleName()).and( + additionalCondition).toPredicate()) // + .collect(toUnmodifiableList()); } - private static void assertStatic(Class annotationType, Method method) { - if (ReflectionUtils.isNotStatic(method)) { - throw new JUnitException(String.format( + private static Condition isStatic(DiscoveryIssueReporter issueReporter, + Function annotationNameProvider) { + return issueReporter.createReportingCondition(ModifierSupport::isStatic, method -> { + String message = String.format( "@%s method '%s' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).", - annotationType.getSimpleName(), method.toGenericString())); - } + annotationNameProvider.apply(method), method.toGenericString()); + return createIssue(Severity.ERROR, message, method); + }); + } + + private static Condition isNotStatic(DiscoveryIssueReporter issueReporter, + Function annotationNameProvider) { + return issueReporter.createReportingCondition(ModifierSupport::isNotStatic, method -> { + String message = String.format("@%s method '%s' must not be static.", annotationNameProvider.apply(method), + method.toGenericString()); + return createIssue(Severity.ERROR, message, method); + }); + } + + private static Condition isNotPrivateError(DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ModifierSupport::isNotPrivate, method -> { + String message = String.format("@%s method '%s' must not be private.", + classTemplateInvocationLifecycleMethodAnnotationName(method), method.toGenericString()); + return createIssue(Severity.ERROR, message, method); + }); + } + + private static Condition isNotPrivateWarning(DiscoveryIssueReporter issueReporter, + Supplier annotationNameProvider) { + return issueReporter.createReportingCondition(ModifierSupport::isNotPrivate, method -> { + String message = String.format( + "@%s method '%s' should not be private. This will be disallowed in a future release.", + annotationNameProvider.get(), method.toGenericString()); + return createIssue(Severity.WARNING, message, method); + }); + } + + private static Condition returnsPrimitiveVoid(DiscoveryIssueReporter issueReporter, + Function annotationNameProvider) { + return issueReporter.createReportingCondition(ReflectionUtils::returnsPrimitiveVoid, method -> { + String message = String.format("@%s method '%s' must not return a value.", + annotationNameProvider.apply(method), method.toGenericString()); + return createIssue(Severity.ERROR, message, method); + }); + } + + private static String classTemplateInvocationLifecycleMethodAnnotationName(Method method) { + return findClassTemplateInvocationLifecycleMethodAnnotation(method) // + .map(ClassTemplateInvocationLifecycleMethod::lifecycleMethodAnnotation) // + .map(Class::getSimpleName) // + .orElseGet(ClassTemplateInvocationLifecycleMethod.class::getSimpleName); + } + + private static Optional findClassTemplateInvocationLifecycleMethodAnnotation( + Method method) { + return findAnnotation(method, ClassTemplateInvocationLifecycleMethod.class); } - private static void assertNonStatic(Class annotationType, Method method) { - if (ReflectionUtils.isStatic(method)) { - throw new JUnitException(String.format("@%s method '%s' must not be static.", - annotationType.getSimpleName(), method.toGenericString())); - } - } - - private static void assertVoid(Class annotationType, Method method) { - if (!returnsPrimitiveVoid(method)) { - throw new JUnitException(String.format("@%s method '%s' must not return a value.", - annotationType.getSimpleName(), method.toGenericString())); - } + private static DiscoveryIssue createIssue(Severity severity, String message, Method method) { + return DiscoveryIssue.builder(severity, message).source(MethodSource.from(method)).build(); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,32 +11,41 @@ package org.junit.jupiter.engine.descriptor; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.jupiter.api.parallel.ResourceLockTarget.CHILDREN; import static org.junit.jupiter.engine.descriptor.DisplayNameUtils.determineDisplayNameForMethod; +import static org.junit.jupiter.engine.descriptor.ResourceLockAware.enclosingInstanceTypesDependentResourceLocksProviderEvaluator; import static org.junit.platform.commons.util.CollectionUtils.forEachInReverseOrder; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestWatcher; +import org.junit.jupiter.api.parallel.ResourceLocksProvider; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; +import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.UnrecoverableExceptions; +import org.junit.platform.engine.DiscoveryIssue; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.support.descriptor.MethodSource; -import org.junit.platform.engine.support.hierarchical.ExclusiveResource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Base class for {@link TestDescriptor TestDescriptors} based on Java methods. @@ -44,63 +53,99 @@ * @since 5.0 */ @API(status = INTERNAL, since = "5.0") -public abstract class MethodBasedTestDescriptor extends JupiterTestDescriptor { +public abstract class MethodBasedTestDescriptor extends JupiterTestDescriptor + implements ResourceLockAware, TestClassAware, Validatable { private static final Logger logger = LoggerFactory.getLogger(MethodBasedTestDescriptor.class); - private final Class testClass; - private final Method testMethod; - - /** - * Set of method-level tags; does not contain tags from parent. - */ - private final Set tags; + private final MethodInfo methodInfo; MethodBasedTestDescriptor(UniqueId uniqueId, Class testClass, Method testMethod, - JupiterConfiguration configuration) { - this(uniqueId, determineDisplayNameForMethod(testClass, testMethod, configuration), testClass, testMethod, - configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + this(uniqueId, determineDisplayNameForMethod(enclosingInstanceTypes, testClass, testMethod, configuration), + testClass, testMethod, configuration); } MethodBasedTestDescriptor(UniqueId uniqueId, String displayName, Class testClass, Method testMethod, JupiterConfiguration configuration) { super(uniqueId, displayName, MethodSource.from(testClass, testMethod), configuration); + this.methodInfo = new MethodInfo(testClass, testMethod); + } - this.testClass = Preconditions.notNull(testClass, "Class must not be null"); - this.testMethod = testMethod; - this.tags = getTags(testMethod); + public final Method getTestMethod() { + return this.methodInfo.testMethod; } + // --- TestDescriptor ------------------------------------------------------ + @Override public final Set getTags() { // return modifiable copy - Set allTags = new LinkedHashSet<>(this.tags); + Set allTags = new LinkedHashSet<>(this.methodInfo.tags); getParent().ifPresent(parentDescriptor -> allTags.addAll(parentDescriptor.getTags())); return allTags; } @Override - public Set getExclusiveResources() { - return getExclusiveResourcesFromAnnotation(getTestMethod()); + public String getLegacyReportingName() { + return String.format("%s(%s)", getTestMethod().getName(), + ClassUtils.nullSafeToString(Class::getSimpleName, getTestMethod().getParameterTypes())); } + // --- TestClassAware ------------------------------------------------------ + @Override - protected Optional getExplicitExecutionMode() { - return getExecutionModeFromAnnotation(getTestMethod()); + public final Class getTestClass() { + return this.methodInfo.testClass; } - public final Class getTestClass() { - return this.testClass; + @Override + public List> getEnclosingTestClasses() { + return getParent() // + .filter(TestClassAware.class::isInstance) // + .map(TestClassAware.class::cast) // + .map(TestClassAware::getEnclosingTestClasses) // + .orElseGet(Collections::emptyList); } - public final Method getTestMethod() { - return this.testMethod; + // --- Validatable --------------------------------------------------------- + + @Override + public void validate(DiscoveryIssueReporter reporter) { + Validatable.reportAndClear(this.methodInfo.discoveryIssues, reporter); + DisplayNameUtils.validateAnnotation(getTestMethod(), // + () -> String.format("method '%s'", getTestMethod().toGenericString()), // + // Use _declaring_ class here because that's where the `@DisplayName` annotation is declared + () -> MethodSource.from(getTestMethod()), // + reporter); } + // --- Node ---------------------------------------------------------------- + @Override - public String getLegacyReportingName() { - return String.format("%s(%s)", testMethod.getName(), - ClassUtils.nullSafeToString(Class::getSimpleName, testMethod.getParameterTypes())); + public ExclusiveResourceCollector getExclusiveResourceCollector() { + // There's no need to cache this as this method should only be called once + ExclusiveResourceCollector collector = ExclusiveResourceCollector.from(getTestMethod()); + + if (collector.getStaticResourcesFor(CHILDREN).findAny().isPresent()) { + String message = "'ResourceLockTarget.CHILDREN' is not supported for methods." + // + " Invalid method: " + getTestMethod(); + throw new JUnitException(message); + } + + return collector; + } + + @Override + public Function> getResourceLocksProviderEvaluator() { + return enclosingInstanceTypesDependentResourceLocksProviderEvaluator(this::getEnclosingTestClasses, + (provider, enclosingInstanceTypes) -> provider.provideForMethod(enclosingInstanceTypes, getTestClass(), + getTestMethod())); + } + + @Override + protected Optional getExplicitExecutionMode() { + return getExecutionModeFromAnnotation(getTestMethod()); } /** @@ -148,4 +193,27 @@ } } + private static class MethodInfo { + + private final List discoveryIssues = new ArrayList<>(); + + private final Class testClass; + private final Method testMethod; + + /** + * Set of method-level tags; does not contain tags from parent. + */ + private final Set tags; + + MethodInfo(Class testClass, Method testMethod) { + this.testClass = Preconditions.notNull(testClass, "Class must not be null"); + this.testMethod = testMethod; + this.tags = getTags(testMethod, // + () -> String.format("method '%s'", testMethod.toGenericString()), // + // Use _declaring_ class here because that's where the `@Tag` annotation is declared + () -> MethodSource.from(testMethod.getDeclaringClass(), testMethod), // + discoveryIssues::add); + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodExtensionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,14 +12,15 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; -import java.util.function.Function; import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.jupiter.api.extension.ExecutableInvoker; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.support.hierarchical.Node; import org.junit.platform.engine.support.hierarchical.ThrowableCollector; @@ -35,10 +36,10 @@ MethodExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, TestMethodTestDescriptor testDescriptor, JupiterConfiguration configuration, - ThrowableCollector throwableCollector, - Function executableInvokerFactory) { + ExtensionRegistry extensionRegistry, LauncherStoreFacade launcherStoreFacade, + ThrowableCollector throwableCollector) { - super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory); + super(parent, engineExecutionListener, testDescriptor, configuration, extensionRegistry, launcherStoreFacade); this.throwableCollector = throwableCollector; } @@ -54,6 +55,11 @@ } @Override + public List> getEnclosingTestClasses() { + return getTestDescriptor().getEnclosingTestClasses(); + } + + @Override public Optional getTestInstanceLifecycle() { return getParent().flatMap(ExtensionContext::getTestInstanceLifecycle); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodSourceSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodSourceSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodSourceSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodSourceSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,24 +13,27 @@ import static java.util.Collections.emptyList; import static org.apiguardian.api.API.Status.INTERNAL; import static org.junit.jupiter.engine.descriptor.DisplayNameUtils.createDisplayNameSupplierForNestedClass; +import static org.junit.jupiter.engine.descriptor.ResourceLockAware.enclosingInstanceTypesDependentResourceLocksProviderEvaluator; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; -import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; +import org.junit.jupiter.api.parallel.ResourceLocksProvider; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.ExtensionContextSupplier; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; -import org.junit.jupiter.engine.extension.ExtensionRegistrar; import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.support.hierarchical.ThrowableCollector; /** * {@link TestDescriptor} for tests based on nested (but not static) Java classes. @@ -47,8 +50,23 @@ public static final String SEGMENT_TYPE = "nested-class"; - public NestedClassTestDescriptor(UniqueId uniqueId, Class testClass, JupiterConfiguration configuration) { - super(uniqueId, testClass, createDisplayNameSupplierForNestedClass(testClass, configuration), configuration); + public NestedClassTestDescriptor(UniqueId uniqueId, Class testClass, + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, + createDisplayNameSupplierForNestedClass(enclosingInstanceTypes, testClass, configuration), configuration); + } + + private NestedClassTestDescriptor(UniqueId uniqueId, Class testClass, String displayName, + JupiterConfiguration configuration) { + super(uniqueId, testClass, displayName, configuration); + } + + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected NestedClassTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new NestedClassTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), getTestClass(), getDisplayName(), + configuration); } // --- TestDescriptor ------------------------------------------------------ @@ -56,16 +74,22 @@ @Override public final Set getTags() { // return modifiable copy - Set allTags = new LinkedHashSet<>(this.tags); + Set allTags = new LinkedHashSet<>(this.classInfo.tags); getParent().ifPresent(parentDescriptor -> allTags.addAll(parentDescriptor.getTags())); return allTags; } + // --- TestClassAware ------------------------------------------------------ + @Override public List> getEnclosingTestClasses() { - TestDescriptor parent = getParent().orElse(null); - if (parent instanceof ClassBasedTestDescriptor) { - ClassBasedTestDescriptor parentClassDescriptor = (ClassBasedTestDescriptor) parent; + return getEnclosingTestClasses(getParent().orElse(null)); + } + + @API(status = INTERNAL, since = "5.12") + public static List> getEnclosingTestClasses(TestDescriptor parent) { + if (parent instanceof TestClassAware) { + TestClassAware parentClassDescriptor = (TestClassAware) parent; List> result = new ArrayList<>(parentClassDescriptor.getEnclosingTestClasses()); result.add(parentClassDescriptor.getTestClass()); return result; @@ -73,18 +97,26 @@ return emptyList(); } - // --- Node ---------------------------------------------------------------- + // --- ClassBasedTestDescriptor -------------------------------------------- @Override protected TestInstances instantiateTestClass(JupiterEngineExecutionContext parentExecutionContext, - ExtensionRegistry registry, ExtensionRegistrar registrar, ExtensionContext extensionContext, - ThrowableCollector throwableCollector) { + ExtensionContextSupplier extensionContext, ExtensionRegistry registry, + JupiterEngineExecutionContext context) { // Extensions registered for nested classes and below are not to be used for instantiating and initializing outer classes ExtensionRegistry extensionRegistryForOuterInstanceCreation = parentExecutionContext.getExtensionRegistry(); TestInstances outerInstances = parentExecutionContext.getTestInstancesProvider().getTestInstances( - extensionRegistryForOuterInstanceCreation, registrar, throwableCollector); + extensionRegistryForOuterInstanceCreation, context); return instantiateTestClass(Optional.of(outerInstances), registry, extensionContext); } + // --- ResourceLockAware --------------------------------------------------- + + @Override + public Function> getResourceLocksProviderEvaluator() { + return enclosingInstanceTypesDependentResourceLocksProviderEvaluator(this::getEnclosingTestClasses, (provider, + enclosingInstanceTypes) -> provider.provideForNestedClass(enclosingInstanceTypes, getTestClass())); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ResourceLockAware.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ResourceLockAware.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ResourceLockAware.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ResourceLockAware.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,92 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static org.junit.jupiter.api.parallel.ResourceLockTarget.CHILDREN; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.junit.jupiter.api.parallel.ResourceLocksProvider; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.hierarchical.ExclusiveResource; + +/** + * @since 5.12 + */ +interface ResourceLockAware extends TestDescriptor { + + default Stream determineExclusiveResources() { + + Deque ancestors = new ArrayDeque<>(); + TestDescriptor parent = this.getParent().orElse(null); + while (parent instanceof ResourceLockAware) { + ancestors.addFirst((ResourceLockAware) parent); + parent = parent.getParent().orElse(null); + } + + Function> evaluator = getResourceLocksProviderEvaluator(); + + if (ancestors.isEmpty()) { + return determineOwnExclusiveResources(evaluator); + } + + Stream parentStaticResourcesForChildren = ancestors.getLast() // + .getExclusiveResourceCollector().getStaticResourcesFor(CHILDREN); + + Stream ancestorDynamicResources = ancestors.stream() // + .map(ResourceLockAware::getExclusiveResourceCollector) // + .flatMap(collector -> collector.getDynamicResources(evaluator)); + + return Stream.of(ancestorDynamicResources, parentStaticResourcesForChildren, + determineOwnExclusiveResources(evaluator))// + .flatMap(s -> s); + } + + default Stream determineOwnExclusiveResources( + Function> providerToLocks) { + return this.getExclusiveResourceCollector().getAllExclusiveResources(providerToLocks); + } + + ExclusiveResourceCollector getExclusiveResourceCollector(); + + Function> getResourceLocksProviderEvaluator(); + + static Function> enclosingInstanceTypesDependentResourceLocksProviderEvaluator( + Supplier>> enclosingInstanceTypesSupplier, + BiFunction>, Set> evaluator) { + return new Function>() { + + private List> enclosingInstanceTypes; + + @Override + public Set apply(ResourceLocksProvider provider) { + if (this.enclosingInstanceTypes == null) { + this.enclosingInstanceTypes = makeUnmodifiable(enclosingInstanceTypesSupplier.get()); + } + return evaluator.apply(provider, this.enclosingInstanceTypes); + } + + private List makeUnmodifiable(List list) { + return list.isEmpty() ? emptyList() : unmodifiableList(list); + } + }; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TemplateExecutor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TemplateExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TemplateExecutor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TemplateExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,115 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static java.util.stream.Collectors.toList; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TemplateInvocationValidationException; +import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; +import org.junit.jupiter.engine.extension.ExtensionRegistry; +import org.junit.platform.commons.util.ExceptionUtils; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.hierarchical.Node; + +abstract class TemplateExecutor

{ + + private final TestDescriptor parent; + private final Class

providerType; + private final DynamicDescendantFilter dynamicDescendantFilter; + + TemplateExecutor(T parent, Class

providerType) { + this.parent = parent; + this.providerType = providerType; + this.dynamicDescendantFilter = parent.getDynamicDescendantFilter(); + } + + void execute(JupiterEngineExecutionContext context, Node.DynamicTestExecutor dynamicTestExecutor) { + ExtensionContext extensionContext = context.getExtensionContext(); + List

providers = validateProviders(extensionContext, context.getExtensionRegistry()); + AtomicInteger invocationIndex = new AtomicInteger(); + for (P provider : providers) { + executeForProvider(provider, invocationIndex, dynamicTestExecutor, extensionContext); + } + } + + private void executeForProvider(P provider, AtomicInteger invocationIndex, + Node.DynamicTestExecutor dynamicTestExecutor, ExtensionContext extensionContext) { + + int initialValue = invocationIndex.get(); + + Stream stream = provideContexts(provider, extensionContext); + try { + stream.forEach(invocationContext -> createInvocationTestDescriptor(invocationContext, + invocationIndex.incrementAndGet()) // + .ifPresent(testDescriptor -> execute(dynamicTestExecutor, testDescriptor))); + } + catch (Throwable t) { + try { + stream.close(); + } + catch (TemplateInvocationValidationException ignore) { + // ignore exceptions from close() to avoid masking the original failure + } + throw ExceptionUtils.throwAsUncheckedException(t); + } + finally { + stream.close(); + } + + Preconditions.condition( + invocationIndex.get() != initialValue || mayReturnZeroContexts(provider, extensionContext), + getZeroContextsProvidedErrorMessage(provider)); + } + + private List

validateProviders(ExtensionContext extensionContext, ExtensionRegistry extensionRegistry) { + List

providers = extensionRegistry.stream(providerType) // + .filter(provider -> supports(provider, extensionContext)) // + .collect(toList()); + return Preconditions.notEmpty(providers, this::getNoRegisteredProviderErrorMessage); + } + + private Optional createInvocationTestDescriptor(C invocationContext, int index) { + UniqueId invocationUniqueId = createInvocationUniqueId(parent.getUniqueId(), index); + if (this.dynamicDescendantFilter.test(invocationUniqueId, index - 1)) { + return Optional.of(createInvocationTestDescriptor(invocationUniqueId, invocationContext, index)); + } + return Optional.empty(); + } + + private void execute(Node.DynamicTestExecutor dynamicTestExecutor, TestDescriptor testDescriptor) { + testDescriptor.setParent(parent); + dynamicTestExecutor.execute(testDescriptor); + } + + abstract boolean supports(P provider, ExtensionContext extensionContext); + + protected abstract String getNoRegisteredProviderErrorMessage(); + + abstract Stream provideContexts(P provider, ExtensionContext extensionContext); + + abstract boolean mayReturnZeroContexts(P provider, ExtensionContext extensionContext); + + protected abstract String getZeroContextsProvidedErrorMessage(P provider); + + abstract UniqueId createInvocationUniqueId(UniqueId parentUniqueId, int index); + + abstract TestDescriptor createInvocationTestDescriptor(UniqueId uniqueId, C invocationContext, int index); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestClassAware.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestClassAware.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestClassAware.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestClassAware.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.List; + +import org.apiguardian.api.API; + +/** + * @since 5.13 + */ +@API(status = INTERNAL, since = "5.13") +public interface TestClassAware { + + Class getTestClass(); + + List> getEnclosingTestClasses(); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,8 +18,10 @@ import java.lang.reflect.Method; import java.net.URI; import java.util.Iterator; +import java.util.List; import java.util.Optional; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import java.util.stream.Stream; import org.apiguardian.api.API; @@ -33,7 +35,6 @@ import org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.ReflectiveInterceptorCall; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.CollectionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.TestDescriptor; @@ -60,11 +61,26 @@ private static final ReflectiveInterceptorCall interceptorCall = InvocationInterceptor::interceptTestFactoryMethod; private static final InterceptingExecutableInvoker executableInvoker = new InterceptingExecutableInvoker(); - private final DynamicDescendantFilter dynamicDescendantFilter = new DynamicDescendantFilter(); + private final DynamicDescendantFilter dynamicDescendantFilter; public TestFactoryTestDescriptor(UniqueId uniqueId, Class testClass, Method testMethod, - JupiterConfiguration configuration) { - super(uniqueId, testClass, testMethod, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, testMethod, enclosingInstanceTypes, configuration); + this.dynamicDescendantFilter = new DynamicDescendantFilter(); + } + + private TestFactoryTestDescriptor(UniqueId uniqueId, String displayName, Class testClass, Method testMethod, + JupiterConfiguration configuration, DynamicDescendantFilter dynamicDescendantFilter) { + super(uniqueId, displayName, testClass, testMethod, configuration); + this.dynamicDescendantFilter = dynamicDescendantFilter; + } + + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected TestFactoryTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new TestFactoryTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), getDisplayName(), getTestClass(), + getTestMethod(), this.configuration, this.dynamicDescendantFilter.copy(uniqueIdTransformer)); } // --- Filterable ---------------------------------------------------------- @@ -121,17 +137,11 @@ if (testFactoryMethodResult instanceof DynamicNode) { return Stream.of((DynamicNode) testFactoryMethodResult); } - try { - return (Stream) CollectionUtils.toStream(testFactoryMethodResult); - } - catch (PreconditionViolationException ex) { - throw invalidReturnTypeException(ex); - } + return (Stream) CollectionUtils.toStream(testFactoryMethodResult); } private JUnitException invalidReturnTypeException(Throwable cause) { - String message = String.format( - "@TestFactory method [%s] must return a single %2$s or a Stream, Collection, Iterable, Iterator, or array of %2$s.", + String message = String.format("Objects produced by @TestFactory method '%s' must be of type %s.", getTestMethod().toGenericString(), DynamicNode.class.getName()); return new JUnitException(message, cause); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,7 +15,7 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.engine.config.JupiterConfiguration; -import org.junit.platform.commons.util.AnnotationUtils; +import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.commons.util.Preconditions; /** @@ -37,7 +37,7 @@ Preconditions.notNull(configuration, "configuration must not be null"); // @formatter:off - return AnnotationUtils.findAnnotation(testClass, TestInstance.class) + return AnnotationSupport.findAnnotation(testClass, TestInstance.class) .map(TestInstance::value) .orElseGet(configuration::getDefaultTestInstanceLifecycle); // @formatter:on diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,12 +11,16 @@ package org.junit.jupiter.engine.descriptor; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.jupiter.engine.descriptor.CallbackSupport.invokeAfterCallbacks; +import static org.junit.jupiter.engine.descriptor.CallbackSupport.invokeBeforeCallbacks; import static org.junit.jupiter.engine.descriptor.ExtensionUtils.populateNewExtensionRegistryFromExtendWithAnnotation; import static org.junit.jupiter.engine.descriptor.ExtensionUtils.registerExtensionsFromExecutableParameters; import static org.junit.jupiter.engine.support.JupiterThrowableCollectorFactory.createThrowableCollector; -import static org.junit.platform.commons.util.CollectionUtils.forEachInReverseOrder; import java.lang.reflect.Method; +import java.util.List; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; import org.junit.jupiter.api.TestInstance.Lifecycle; @@ -24,7 +28,6 @@ import org.junit.jupiter.api.extension.AfterTestExecutionCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; -import org.junit.jupiter.api.extension.Extension; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.InvocationInterceptor; import org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler; @@ -35,7 +38,6 @@ import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.execution.AfterEachMethodAdapter; import org.junit.jupiter.engine.execution.BeforeEachMethodAdapter; -import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; import org.junit.jupiter.engine.execution.InterceptingExecutableInvoker; import org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.ReflectiveInterceptorCall; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; @@ -76,17 +78,32 @@ private final ReflectiveInterceptorCall interceptorCall; public TestMethodTestDescriptor(UniqueId uniqueId, Class testClass, Method testMethod, - JupiterConfiguration configuration) { - super(uniqueId, testClass, testMethod, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, testMethod, enclosingInstanceTypes, configuration); this.interceptorCall = defaultInterceptorCall; } TestMethodTestDescriptor(UniqueId uniqueId, String displayName, Class testClass, Method testMethod, + JupiterConfiguration configuration) { + this(uniqueId, displayName, testClass, testMethod, configuration, defaultInterceptorCall); + } + + TestMethodTestDescriptor(UniqueId uniqueId, String displayName, Class testClass, Method testMethod, JupiterConfiguration configuration, ReflectiveInterceptorCall interceptorCall) { super(uniqueId, displayName, testClass, testMethod, configuration); this.interceptorCall = interceptorCall; } + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected TestMethodTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new TestMethodTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), getDisplayName(), getTestClass(), + getTestMethod(), this.configuration, interceptorCall); + } + + // --- TestDescriptor ------------------------------------------------------ + @Override public Type getType() { return Type.TEST; @@ -99,21 +116,25 @@ MutableExtensionRegistry registry = populateNewExtensionRegistry(context); ThrowableCollector throwableCollector = createThrowableCollector(); MethodExtensionContext extensionContext = new MethodExtensionContext(context.getExtensionContext(), - context.getExecutionListener(), this, context.getConfiguration(), throwableCollector, - it -> new DefaultExecutableInvoker(it, registry)); - throwableCollector.execute(() -> { - TestInstances testInstances = context.getTestInstancesProvider().getTestInstances(registry, - throwableCollector); - extensionContext.setTestInstances(testInstances); - }); - + context.getExecutionListener(), this, context.getConfiguration(), registry, + context.getLauncherStoreFacade(), throwableCollector); // @formatter:off - return context.extend() + JupiterEngineExecutionContext newContext = context.extend() .withExtensionRegistry(registry) .withExtensionContext(extensionContext) .withThrowableCollector(throwableCollector) .build(); // @formatter:on + throwableCollector.execute(() -> { + TestInstances testInstances = newContext.getTestInstancesProvider().getTestInstances(newContext); + extensionContext.setTestInstances(testInstances); + prepareExtensionContext(extensionContext); + }); + return newContext; + } + + protected void prepareExtensionContext(ExtensionContext extensionContext) { + // nothing to do by default } protected MutableExtensionRegistry populateNewExtensionRegistry(JupiterEngineExecutionContext context) { @@ -162,21 +183,19 @@ } private void invokeBeforeEachCallbacks(JupiterEngineExecutionContext context) { - invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(BeforeEachCallback.class, context, - (callback, extensionContext) -> callback.beforeEach(extensionContext)); + invokeBeforeCallbacks(BeforeEachCallback.class, context, BeforeEachCallback::beforeEach); } private void invokeBeforeEachMethods(JupiterEngineExecutionContext context) { ExtensionRegistry registry = context.getExtensionRegistry(); - invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(BeforeEachMethodAdapter.class, context, - (adapter, extensionContext) -> { - try { - adapter.invokeBeforeEachMethod(extensionContext, registry); - } - catch (Throwable throwable) { - invokeBeforeEachExecutionExceptionHandlers(extensionContext, registry, throwable); - } - }); + invokeBeforeCallbacks(BeforeEachMethodAdapter.class, context, (adapter, extensionContext) -> { + try { + adapter.invokeBeforeEachMethod(extensionContext, registry); + } + catch (Throwable throwable) { + invokeBeforeEachExecutionExceptionHandlers(extensionContext, registry, throwable); + } + }); } private void invokeBeforeEachExecutionExceptionHandlers(ExtensionContext context, ExtensionRegistry registry, @@ -187,23 +206,8 @@ } private void invokeBeforeTestExecutionCallbacks(JupiterEngineExecutionContext context) { - invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(BeforeTestExecutionCallback.class, context, - (callback, extensionContext) -> callback.beforeTestExecution(extensionContext)); - } - - private void invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(Class type, - JupiterEngineExecutionContext context, CallbackInvoker callbackInvoker) { - - ExtensionRegistry registry = context.getExtensionRegistry(); - ExtensionContext extensionContext = context.getExtensionContext(); - ThrowableCollector throwableCollector = context.getThrowableCollector(); - - for (T callback : registry.getExtensions(type)) { - throwableCollector.execute(() -> callbackInvoker.invoke(callback, extensionContext)); - if (throwableCollector.isNotEmpty()) { - break; - } - } + invokeBeforeCallbacks(BeforeTestExecutionCallback.class, context, + BeforeTestExecutionCallback::beforeTestExecution); } protected void invokeTestMethod(JupiterEngineExecutionContext context, DynamicTestExecutor dynamicTestExecutor) { @@ -232,13 +236,12 @@ } private void invokeAfterTestExecutionCallbacks(JupiterEngineExecutionContext context) { - invokeAllAfterMethodsOrCallbacks(AfterTestExecutionCallback.class, context, - (callback, extensionContext) -> callback.afterTestExecution(extensionContext)); + invokeAfterCallbacks(AfterTestExecutionCallback.class, context, AfterTestExecutionCallback::afterTestExecution); } private void invokeAfterEachMethods(JupiterEngineExecutionContext context) { ExtensionRegistry registry = context.getExtensionRegistry(); - invokeAllAfterMethodsOrCallbacks(AfterEachMethodAdapter.class, context, (adapter, extensionContext) -> { + invokeAfterCallbacks(AfterEachMethodAdapter.class, context, (adapter, extensionContext) -> { try { adapter.invokeAfterEachMethod(extensionContext, registry); } @@ -256,27 +259,14 @@ } private void invokeAfterEachCallbacks(JupiterEngineExecutionContext context) { - invokeAllAfterMethodsOrCallbacks(AfterEachCallback.class, context, - (callback, extensionContext) -> callback.afterEach(extensionContext)); + invokeAfterCallbacks(AfterEachCallback.class, context, AfterEachCallback::afterEach); } private void invokeTestInstancePreDestroyCallbacks(JupiterEngineExecutionContext context) { - invokeAllAfterMethodsOrCallbacks(TestInstancePreDestroyCallback.class, context, + invokeAfterCallbacks(TestInstancePreDestroyCallback.class, context, TestInstancePreDestroyCallback::preDestroyTestInstance); } - private void invokeAllAfterMethodsOrCallbacks(Class type, - JupiterEngineExecutionContext context, CallbackInvoker callbackInvoker) { - - ExtensionRegistry registry = context.getExtensionRegistry(); - ExtensionContext extensionContext = context.getExtensionContext(); - ThrowableCollector throwableCollector = context.getThrowableCollector(); - - forEachInReverseOrder(registry.getExtensions(type), callback -> { - throwableCollector.execute(() -> callbackInvoker.invoke(callback, extensionContext)); - }); - } - /** * Invoke {@link TestWatcher#testSuccessful testSuccessful()}, * {@link TestWatcher#testAborted testAborted()}, or @@ -310,14 +300,4 @@ } } - /** - * @since 5.5 - */ - @FunctionalInterface - private interface CallbackInvoker { - - void invoke(T t, ExtensionContext context) throws Throwable; - - } - } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateExtensionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateExtensionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateExtensionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateExtensionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,14 +12,15 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; -import java.util.function.Function; import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.jupiter.api.extension.ExecutableInvoker; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.support.hierarchical.Node; @@ -31,10 +32,10 @@ private final TestInstances testInstances; TestTemplateExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, - TestTemplateTestDescriptor testDescriptor, JupiterConfiguration configuration, TestInstances testInstances, - Function executableInvokerFactory) { + TestTemplateTestDescriptor testDescriptor, JupiterConfiguration configuration, + ExtensionRegistry extensionRegistry, LauncherStoreFacade launcherStoreFacade, TestInstances testInstances) { - super(parent, engineExecutionListener, testDescriptor, configuration, executableInvokerFactory); + super(parent, engineExecutionListener, testDescriptor, configuration, extensionRegistry, launcherStoreFacade); this.testInstances = testInstances; } @@ -49,6 +50,11 @@ } @Override + public List> getEnclosingTestClasses() { + return getTestDescriptor().getEnclosingTestClasses(); + } + + @Override public Optional getTestInstanceLifecycle() { return getParent().flatMap(ExtensionContext::getTestInstanceLifecycle); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,8 +15,10 @@ import java.lang.reflect.Method; import java.util.Set; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.InvocationInterceptor; import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.engine.config.JupiterConfiguration; @@ -51,9 +53,19 @@ this.index = index; } + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected TestTemplateInvocationTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new TestTemplateInvocationTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), getTestClass(), + getTestMethod(), this.invocationContext, this.index, this.configuration); + } + + // --- TestDescriptor ------------------------------------------------------ + @Override public Set getExclusiveResources() { - // @ResourceLock annotations are already collected and returned by the enclosing container + // Resources are already collected and returned by the enclosing container return emptySet(); } @@ -65,15 +77,20 @@ @Override protected MutableExtensionRegistry populateNewExtensionRegistry(JupiterEngineExecutionContext context) { MutableExtensionRegistry registry = super.populateNewExtensionRegistry(context); - invocationContext.getAdditionalExtensions().forEach( + this.invocationContext.getAdditionalExtensions().forEach( extension -> registry.registerExtension(extension, invocationContext)); return registry; } @Override + protected void prepareExtensionContext(ExtensionContext extensionContext) { + this.invocationContext.prepareInvocation(extensionContext); + } + + @Override public void after(JupiterEngineExecutionContext context) { // forget invocationContext so it can be garbage collected - invocationContext = null; + this.invocationContext = null; } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,27 +10,24 @@ package org.junit.jupiter.engine.descriptor; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.INTERNAL; import static org.junit.jupiter.engine.descriptor.ExtensionUtils.populateNewExtensionRegistryFromExtendWithAnnotation; import java.lang.reflect.Method; import java.util.List; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; import org.apiguardian.api.API; +import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestInstances; import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; import org.junit.jupiter.engine.config.JupiterConfiguration; -import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; -import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; -import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; @@ -44,11 +41,27 @@ public class TestTemplateTestDescriptor extends MethodBasedTestDescriptor implements Filterable { public static final String SEGMENT_TYPE = "test-template"; - private final DynamicDescendantFilter dynamicDescendantFilter = new DynamicDescendantFilter(); + private final DynamicDescendantFilter dynamicDescendantFilter; public TestTemplateTestDescriptor(UniqueId uniqueId, Class testClass, Method templateMethod, - JupiterConfiguration configuration) { - super(uniqueId, testClass, templateMethod, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, templateMethod, enclosingInstanceTypes, configuration); + this.dynamicDescendantFilter = new DynamicDescendantFilter(); + } + + private TestTemplateTestDescriptor(UniqueId uniqueId, String displayName, Class testClass, Method templateMethod, + JupiterConfiguration configuration, DynamicDescendantFilter dynamicDescendantFilter) { + super(uniqueId, displayName, testClass, templateMethod, configuration); + this.dynamicDescendantFilter = dynamicDescendantFilter; + } + + // --- JupiterTestDescriptor ----------------------------------------------- + + @Override + protected TestTemplateTestDescriptor withUniqueId(UnaryOperator uniqueIdTransformer) { + return new TestTemplateTestDescriptor(uniqueIdTransformer.apply(getUniqueId()), getDisplayName(), + getTestClass(), getTestMethod(), this.configuration, + this.dynamicDescendantFilter.copy(uniqueIdTransformer)); } // --- Filterable ---------------------------------------------------------- @@ -81,8 +94,8 @@ TestInstances testInstances = context.getExtensionContext().getTestInstances().orElse(null); ExtensionContext extensionContext = new TestTemplateExtensionContext(context.getExtensionContext(), - context.getExecutionListener(), this, context.getConfiguration(), testInstances, - it -> new DefaultExecutableInvoker(it, registry)); + context.getExecutionListener(), this, context.getConfiguration(), registry, + context.getLauncherStoreFacade(), testInstances); // @formatter:off return context.extend() @@ -96,59 +109,59 @@ public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext context, DynamicTestExecutor dynamicTestExecutor) throws Exception { - ExtensionContext extensionContext = context.getExtensionContext(); - List providers = validateProviders(extensionContext, - context.getExtensionRegistry()); - AtomicInteger invocationIndex = new AtomicInteger(); - // @formatter:off - providers.stream() - .flatMap(provider -> provider.provideTestTemplateInvocationContexts(extensionContext)) - .map(invocationContext -> createInvocationTestDescriptor(invocationContext, invocationIndex.incrementAndGet())) - .filter(Optional::isPresent) - .map(Optional::get) - .forEach(invocationTestDescriptor -> execute(dynamicTestExecutor, invocationTestDescriptor)); - // @formatter:on - validateWasAtLeastInvokedOnce(invocationIndex.get(), providers); + new TestTemplateExecutor().execute(context, dynamicTestExecutor); return context; } - private List validateProviders(ExtensionContext extensionContext, - ExtensionRegistry extensionRegistry) { + private class TestTemplateExecutor + extends TemplateExecutor { - // @formatter:off - List providers = extensionRegistry.stream(TestTemplateInvocationContextProvider.class) - .filter(provider -> provider.supportsTestTemplate(extensionContext)) - .collect(toList()); - // @formatter:on + TestTemplateExecutor() { + super(TestTemplateTestDescriptor.this, TestTemplateInvocationContextProvider.class); + } - return Preconditions.notEmpty(providers, - () -> String.format("You must register at least one %s that supports @TestTemplate method [%s]", - TestTemplateInvocationContextProvider.class.getSimpleName(), getTestMethod())); - } + @Override + boolean supports(TestTemplateInvocationContextProvider provider, ExtensionContext extensionContext) { + return provider.supportsTestTemplate(extensionContext); + } - private Optional createInvocationTestDescriptor(TestTemplateInvocationContext invocationContext, - int index) { - UniqueId uniqueId = getUniqueId().append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#" + index); - if (getDynamicDescendantFilter().test(uniqueId, index - 1)) { - return Optional.of(new TestTemplateInvocationTestDescriptor(uniqueId, getTestClass(), getTestMethod(), - invocationContext, index, configuration)); + @Override + protected String getNoRegisteredProviderErrorMessage() { + return String.format("You must register at least one %s that supports @%s method [%s]", + TestTemplateInvocationContextProvider.class.getSimpleName(), TestTemplate.class.getSimpleName(), + getTestMethod()); } - return Optional.empty(); - } - private void execute(DynamicTestExecutor dynamicTestExecutor, TestDescriptor testDescriptor) { - testDescriptor.setParent(this); - dynamicTestExecutor.execute(testDescriptor); - } + @Override + Stream provideContexts(TestTemplateInvocationContextProvider provider, + ExtensionContext extensionContext) { + return provider.provideTestTemplateInvocationContexts(extensionContext); + } - private void validateWasAtLeastInvokedOnce(int invocationIndex, - List providers) { + @Override + boolean mayReturnZeroContexts(TestTemplateInvocationContextProvider provider, + ExtensionContext extensionContext) { + return provider.mayReturnZeroTestTemplateInvocationContexts(extensionContext); + } - Preconditions.condition(invocationIndex > 0, - () -> "None of the supporting " + TestTemplateInvocationContextProvider.class.getSimpleName() + "s " - + providers.stream().map(provider -> provider.getClass().getSimpleName()).collect( - joining(", ", "[", "]")) - + " provided a non-empty stream"); - } + @Override + protected String getZeroContextsProvidedErrorMessage(TestTemplateInvocationContextProvider provider) { + return String.format( + "Provider [%s] did not provide any invocation contexts, but was expected to do so. " + + "You may override mayReturnZeroTestTemplateInvocationContexts() to allow this.", + provider.getClass().getSimpleName()); + } + + @Override + UniqueId createInvocationUniqueId(UniqueId parentUniqueId, int index) { + return parentUniqueId.append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#" + index); + } + @Override + TestDescriptor createInvocationTestDescriptor(UniqueId uniqueId, + TestTemplateInvocationContext invocationContext, int index) { + return new TestTemplateInvocationTestDescriptor(uniqueId, getTestClass(), getTestMethod(), + invocationContext, index, TestTemplateTestDescriptor.this.configuration); + } + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/UniqueIdPrefixTransformer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/UniqueIdPrefixTransformer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/UniqueIdPrefixTransformer.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/UniqueIdPrefixTransformer.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import java.util.List; +import java.util.function.UnaryOperator; + +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.UniqueId; + +/** + * @since 5.13 + */ +class UniqueIdPrefixTransformer implements UnaryOperator { + + private final UniqueId oldPrefix; + private final UniqueId newPrefix; + private final int oldPrefixLength; + + UniqueIdPrefixTransformer(UniqueId oldPrefix, UniqueId newPrefix) { + this.oldPrefix = oldPrefix; + this.newPrefix = newPrefix; + this.oldPrefixLength = oldPrefix.getSegments().size(); + } + + @Override + public UniqueId apply(UniqueId uniqueId) { + Preconditions.condition(uniqueId.hasPrefix(oldPrefix), + () -> String.format("Unique ID %s does not have the expected prefix %s", uniqueId, oldPrefix)); + List oldSegments = uniqueId.getSegments(); + List suffix = oldSegments.subList(oldPrefixLength, oldSegments.size()); + UniqueId newValue = newPrefix; + for (UniqueId.Segment segment : suffix) { + newValue = newValue.append(segment); + } + return newValue; + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Validatable.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Validatable.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Validatable.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/Validatable.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.List; + +import org.apiguardian.api.API; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; + +/** + * Interface for descriptors that can be validated during discovery. + * + * @since 5.13 + */ +@API(status = INTERNAL, since = "5.13") +public interface Validatable { + + /** + * Validate the state of this descriptor and report any issues found to the + * supplied {@link DiscoveryIssueReporter}. + */ + void validate(DiscoveryIssueReporter reporter); + + /** + * Report and clear the given list of {@link DiscoveryIssue}s using the + * supplied {@link DiscoveryIssueReporter}. + */ + static void reportAndClear(List issues, DiscoveryIssueReporter reporter) { + issues.forEach(reporter::reportIssue); + issues.clear(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractAnnotatedDescriptorWrapper.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractAnnotatedDescriptorWrapper.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractAnnotatedDescriptorWrapper.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractAnnotatedDescriptorWrapper.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,7 +15,7 @@ import java.util.List; import java.util.Optional; -import org.junit.platform.commons.util.AnnotationUtils; +import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.TestDescriptor; @@ -49,17 +49,17 @@ public final boolean isAnnotated(Class annotationType) { Preconditions.notNull(annotationType, "annotationType must not be null"); - return AnnotationUtils.isAnnotated(getAnnotatedElement(), annotationType); + return AnnotationSupport.isAnnotated(getAnnotatedElement(), annotationType); } public final Optional findAnnotation(Class annotationType) { Preconditions.notNull(annotationType, "annotationType must not be null"); - return AnnotationUtils.findAnnotation(getAnnotatedElement(), annotationType); + return AnnotationSupport.findAnnotation(getAnnotatedElement(), annotationType); } public final List findRepeatableAnnotations(Class annotationType) { Preconditions.notNull(annotationType, "annotationType must not be null"); - return AnnotationUtils.findRepeatableAnnotations(getAnnotatedElement(), annotationType); + return AnnotationSupport.findRepeatableAnnotations(getAnnotatedElement(), annotationType); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractOrderingVisitor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractOrderingVisitor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractOrderingVisitor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/AbstractOrderingVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,40 +10,45 @@ package org.junit.jupiter.engine.discovery; +import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toCollection; +import static java.util.stream.Collectors.toList; import java.util.ArrayList; -import java.util.LinkedHashSet; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.UnrecoverableExceptions; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Abstract base class for {@linkplain TestDescriptor.Visitor visitors} that * order children nodes. * - * @param the parent container type to search in for matching children - * @param the type of children (containers or tests) to order - * @param the wrapper type for the children to order * @since 5.8 */ -abstract class AbstractOrderingVisitor> - implements TestDescriptor.Visitor { +abstract class AbstractOrderingVisitor implements TestDescriptor.Visitor { - private static final Logger logger = LoggerFactory.getLogger(AbstractOrderingVisitor.class); + private final DiscoveryIssueReporter issueReporter; + AbstractOrderingVisitor(DiscoveryIssueReporter issueReporter) { + this.issueReporter = issueReporter; + } + + /** + * @param the parent container type to search in for matching children + */ @SuppressWarnings("unchecked") - protected void doWithMatchingDescriptor(Class parentTestDescriptorType, TestDescriptor testDescriptor, - Consumer action, Function errorMessageBuilder) { + protected void doWithMatchingDescriptor(Class parentTestDescriptorType, + TestDescriptor testDescriptor, Consumer action, Function errorMessageBuilder) { if (parentTestDescriptorType.isInstance(testDescriptor)) { PARENT parentTestDescriptor = (PARENT) testDescriptor; @@ -52,19 +57,37 @@ } catch (Throwable t) { UnrecoverableExceptions.rethrowIfUnrecoverable(t); - logger.error(t, () -> errorMessageBuilder.apply(parentTestDescriptor)); + String message = errorMessageBuilder.apply(parentTestDescriptor); + this.issueReporter.reportIssue(DiscoveryIssue.builder(Severity.ERROR, message) // + .source(parentTestDescriptor.getSource()) // + .cause(t)); } } } - protected void orderChildrenTestDescriptors(TestDescriptor parentTestDescriptor, Class matchingChildrenType, - Function descriptorWrapperFactory, DescriptorWrapperOrderer descriptorWrapperOrderer) { - - Set children = parentTestDescriptor.getChildren(); + /** + * @param the type of children (containers or tests) to order + */ + protected > void orderChildrenTestDescriptors( + TestDescriptor parentTestDescriptor, Class matchingChildrenType, + Optional> validationAction, Function descriptorWrapperFactory, + DescriptorWrapperOrderer descriptorWrapperOrderer) { - List matchingDescriptorWrappers = children.stream()// + Stream matchingChildren = parentTestDescriptor.getChildren()// + .stream()// .filter(matchingChildrenType::isInstance)// - .map(matchingChildrenType::cast)// + .map(matchingChildrenType::cast); + + if (!descriptorWrapperOrderer.canOrderWrappers()) { + validationAction.ifPresent(matchingChildren::forEach); + return; + } + + if (validationAction.isPresent()) { + matchingChildren = matchingChildren.peek(validationAction.get()); + } + + List matchingDescriptorWrappers = matchingChildren// .map(descriptorWrapperFactory)// .collect(toCollection(ArrayList::new)); @@ -73,109 +96,105 @@ return; } - if (descriptorWrapperOrderer.canOrderWrappers()) { - List nonMatchingTestDescriptors = children.stream()// - .filter(childTestDescriptor -> !matchingChildrenType.isInstance(childTestDescriptor))// - .collect(Collectors.toList()); - - // Make a local copy for later validation - Set originalWrappers = new LinkedHashSet<>(matchingDescriptorWrappers); - - descriptorWrapperOrderer.orderWrappers(matchingDescriptorWrappers); - - int difference = matchingDescriptorWrappers.size() - originalWrappers.size(); - if (difference > 0) { - descriptorWrapperOrderer.logDescriptorsAddedWarning(difference); - } - else if (difference < 0) { - descriptorWrapperOrderer.logDescriptorsRemovedWarning(difference); - } - - Set orderedTestDescriptors = matchingDescriptorWrappers.stream()// - .filter(originalWrappers::contains)// - .map(AbstractAnnotatedDescriptorWrapper::getTestDescriptor)// - .collect(toCollection(LinkedHashSet::new)); - - // There is currently no way to removeAll or addAll children at once, so we - // first remove them all and then add them all back. - Stream.concat(orderedTestDescriptors.stream(), nonMatchingTestDescriptors.stream())// - .forEach(parentTestDescriptor::removeChild); - - // If we are ordering children of type ClassBasedTestDescriptor, that means we - // are ordering top-level classes or @Nested test classes. Thus, the - // nonMatchingTestDescriptors list is either empty (for top-level classes) or - // contains only local test methods (for @Nested classes) which must be executed - // before tests in @Nested test classes. So we add the test methods before adding - // the @Nested test classes. - if (matchingChildrenType == ClassBasedTestDescriptor.class) { - Stream.concat(nonMatchingTestDescriptors.stream(), orderedTestDescriptors.stream())// - .forEach(parentTestDescriptor::addChild); - } - // Otherwise, we add the ordered descriptors before the non-matching descriptors, - // which is the case when we are ordering test methods. In other words, local - // test methods always get added before @Nested test classes. + parentTestDescriptor.orderChildren(children -> { + Stream nonMatchingTestDescriptors = children.stream()// + .filter(childTestDescriptor -> !matchingChildrenType.isInstance(childTestDescriptor)); + + descriptorWrapperOrderer.orderWrappers(matchingDescriptorWrappers, + message -> reportWarning(parentTestDescriptor, message)); + + Stream orderedTestDescriptors = matchingDescriptorWrappers.stream()// + .map(AbstractAnnotatedDescriptorWrapper::getTestDescriptor); + + if (shouldNonMatchingDescriptorsComeBeforeOrderedOnes()) { + return Stream.concat(nonMatchingTestDescriptors, orderedTestDescriptors)// + .collect(toList()); + } else { - Stream.concat(orderedTestDescriptors.stream(), nonMatchingTestDescriptors.stream())// - .forEach(parentTestDescriptor::addChild); + return Stream.concat(orderedTestDescriptors, nonMatchingTestDescriptors)// + .collect(toList()); } - } - - // Recurse through the children in order to support ordering for @Nested test classes. - matchingDescriptorWrappers.forEach(descriptorWrapper -> { - TestDescriptor newParentTestDescriptor = descriptorWrapper.getTestDescriptor(); - DescriptorWrapperOrderer newDescriptorWrapperOrderer = getDescriptorWrapperOrderer(descriptorWrapperOrderer, - descriptorWrapper); - - orderChildrenTestDescriptors(newParentTestDescriptor, matchingChildrenType, descriptorWrapperFactory, - newDescriptorWrapperOrderer); }); } + private void reportWarning(TestDescriptor parentTestDescriptor, String message) { + issueReporter.reportIssue(DiscoveryIssue.builder(Severity.WARNING, message) // + .source(parentTestDescriptor.getSource())); + } + + protected abstract boolean shouldNonMatchingDescriptorsComeBeforeOrderedOnes(); + /** - * Get the {@link DescriptorWrapperOrderer} for the supplied {@link AbstractAnnotatedDescriptorWrapper}. - * - *

The default implementation returns the supplied {@code DescriptorWrapperOrderer}. - * - * @return a new {@code DescriptorWrapperOrderer} or the one supplied as an argument + * @param the wrapper type for the children to order */ - protected DescriptorWrapperOrderer getDescriptorWrapperOrderer( - DescriptorWrapperOrderer inheritedDescriptorWrapperOrderer, - AbstractAnnotatedDescriptorWrapper descriptorWrapper) { + protected static class DescriptorWrapperOrderer { - return inheritedDescriptorWrapperOrderer; - } + private static final DescriptorWrapperOrderer NOOP = new DescriptorWrapperOrderer<>(null, null, __ -> "", + ___ -> ""); - protected class DescriptorWrapperOrderer { + @SuppressWarnings("unchecked") + protected static DescriptorWrapperOrderer noop() { + return (DescriptorWrapperOrderer) NOOP; + } + private final ORDERER orderer; private final Consumer> orderingAction; - private final MessageGenerator descriptorsAddedMessageGenerator; - private final MessageGenerator descriptorsRemovedMessageGenerator; - DescriptorWrapperOrderer(Consumer> orderingAction, + DescriptorWrapperOrderer(ORDERER orderer, Consumer> orderingAction, MessageGenerator descriptorsAddedMessageGenerator, MessageGenerator descriptorsRemovedMessageGenerator) { + this.orderer = orderer; this.orderingAction = orderingAction; this.descriptorsAddedMessageGenerator = descriptorsAddedMessageGenerator; this.descriptorsRemovedMessageGenerator = descriptorsRemovedMessageGenerator; } + ORDERER getOrderer() { + return orderer; + } + private boolean canOrderWrappers() { return this.orderingAction != null; } - private void orderWrappers(List wrappers) { - this.orderingAction.accept(wrappers); + private void orderWrappers(List wrappers, Consumer errorHandler) { + List orderedWrappers = new ArrayList<>(wrappers); + this.orderingAction.accept(orderedWrappers); + Map distinctWrappersToIndex = distinctWrappersToIndex(orderedWrappers); + + int difference = orderedWrappers.size() - wrappers.size(); + int distinctDifference = distinctWrappersToIndex.size() - wrappers.size(); + if (difference > 0) { // difference >= distinctDifference + reportDescriptorsAddedWarning(difference, errorHandler); + } + if (distinctDifference < 0) { // distinctDifference <= difference + reportDescriptorsRemovedWarning(distinctDifference, errorHandler); + } + + wrappers.sort(comparing(wrapper -> distinctWrappersToIndex.getOrDefault(wrapper, -1))); + } + + private Map distinctWrappersToIndex(List wrappers) { + Map toIndex = new HashMap<>(); + for (int i = 0; i < wrappers.size(); i++) { + // Avoid ClassCastException if a misbehaving ordering action added a non-WRAPPER + Object wrapper = wrappers.get(i); + if (!toIndex.containsKey(wrapper)) { + toIndex.put(wrapper, i); + } + } + return toIndex; } - private void logDescriptorsAddedWarning(int number) { - logger.warn(() -> this.descriptorsAddedMessageGenerator.generateMessage(number)); + private void reportDescriptorsAddedWarning(int number, Consumer errorHandler) { + errorHandler.accept(this.descriptorsAddedMessageGenerator.generateMessage(number)); } - private void logDescriptorsRemovedWarning(int number) { - logger.warn(() -> this.descriptorsRemovedMessageGenerator.generateMessage(Math.abs(number))); + private void reportDescriptorsRemovedWarning(int number, Consumer errorHandler) { + errorHandler.accept(this.descriptorsRemovedMessageGenerator.generateMessage(Math.abs(number))); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassOrderingVisitor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassOrderingVisitor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassOrderingVisitor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassOrderingVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,78 +10,146 @@ package org.junit.jupiter.engine.discovery; -import java.lang.reflect.AnnotatedElement; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; + import java.util.List; +import java.util.Optional; import java.util.function.Consumer; import org.junit.jupiter.api.ClassOrderer; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.TestClassOrder; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor; import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; -import org.junit.platform.commons.util.AnnotationUtils; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.AnnotationSupport; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.util.LruCache; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.Condition; /** * @since 5.8 */ -class ClassOrderingVisitor - extends AbstractOrderingVisitor { +class ClassOrderingVisitor extends AbstractOrderingVisitor { + private final LruCache> ordererCache = new LruCache<>( + 10); private final JupiterConfiguration configuration; + private final DescriptorWrapperOrderer globalOrderer; + private final Condition noOrderAnnotation; - ClassOrderingVisitor(JupiterConfiguration configuration) { + ClassOrderingVisitor(JupiterConfiguration configuration, DiscoveryIssueReporter issueReporter) { + super(issueReporter); this.configuration = configuration; + this.globalOrderer = createGlobalOrderer(configuration); + this.noOrderAnnotation = issueReporter.createReportingCondition( + testDescriptor -> !isAnnotated(testDescriptor.getTestClass(), Order.class), testDescriptor -> { + String message = String.format("Ineffective @Order annotation on class '%s'. ", + testDescriptor.getTestClass().getName()) + + "It will not be applied because ClassOrderer.OrderAnnotation is not in use. " + + "Note that the annotation may be either directly present or meta-present on the class."; + return DiscoveryIssue.builder(Severity.INFO, message) // + .source(testDescriptor.getSource()) // + .build(); + }); } @Override public void visit(TestDescriptor testDescriptor) { - ClassOrderer globalClassOrderer = this.configuration.getDefaultTestClassOrderer().orElse(null); - doWithMatchingDescriptor(JupiterEngineDescriptor.class, testDescriptor, - descriptor -> orderContainedClasses(descriptor, globalClassOrderer), - descriptor -> "Failed to order classes"); + doWithMatchingDescriptor(JupiterEngineDescriptor.class, testDescriptor, this::orderTopLevelClasses, + descriptor -> "Failed to order top-level classes"); + doWithMatchingDescriptor(ClassBasedTestDescriptor.class, testDescriptor, this::orderNestedClasses, + descriptor -> "Failed to order nested classes for " + descriptor.getTestClass()); + } + + @Override + protected boolean shouldNonMatchingDescriptorsComeBeforeOrderedOnes() { + // Non-matching descriptors can only occur when ordering nested classes in which + // case they contain only local test methods (for @Nested classes) which must be + // executed before tests in @Nested test classes. So we add the test methods before + // adding the @Nested test classes. + return true; } - private void orderContainedClasses(JupiterEngineDescriptor jupiterEngineDescriptor, ClassOrderer classOrderer) { + private void orderTopLevelClasses(JupiterEngineDescriptor engineDescriptor) { orderChildrenTestDescriptors(// - jupiterEngineDescriptor, // + engineDescriptor, // ClassBasedTestDescriptor.class, // + toValidationAction(globalOrderer), // DefaultClassDescriptor::new, // - createDescriptorWrapperOrderer(classOrderer)); + globalOrderer); } - @Override - protected DescriptorWrapperOrderer getDescriptorWrapperOrderer( - DescriptorWrapperOrderer inheritedDescriptorWrapperOrderer, - AbstractAnnotatedDescriptorWrapper descriptorWrapper) { + private void orderNestedClasses(ClassBasedTestDescriptor descriptor) { + DescriptorWrapperOrderer wrapperOrderer = createAndCacheClassLevelOrderer( + descriptor); + orderChildrenTestDescriptors(// + descriptor, // + ClassBasedTestDescriptor.class, // + toValidationAction(wrapperOrderer), // + DefaultClassDescriptor::new, // + wrapperOrderer); + } - AnnotatedElement annotatedElement = descriptorWrapper.getAnnotatedElement(); - return AnnotationUtils.findAnnotation(annotatedElement, TestClassOrder.class)// - .map(TestClassOrder::value)// - . map(ReflectionUtils::newInstance)// - .map(this::createDescriptorWrapperOrderer)// - .orElse(inheritedDescriptorWrapperOrderer); + private DescriptorWrapperOrderer createGlobalOrderer( + JupiterConfiguration configuration) { + ClassOrderer classOrderer = configuration.getDefaultTestClassOrderer().orElse(null); + return classOrderer == null ? DescriptorWrapperOrderer.noop() : createDescriptorWrapperOrderer(classOrderer); + } + + private DescriptorWrapperOrderer createAndCacheClassLevelOrderer( + ClassBasedTestDescriptor classBasedTestDescriptor) { + DescriptorWrapperOrderer orderer = createClassLevelOrderer( + classBasedTestDescriptor); + ordererCache.put(classBasedTestDescriptor, orderer); + return orderer; } - private DescriptorWrapperOrderer createDescriptorWrapperOrderer(ClassOrderer classOrderer) { - Consumer> orderingAction = classOrderer == null ? null : // - classDescriptors -> classOrderer.orderClasses( - new DefaultClassOrdererContext(classDescriptors, this.configuration)); + private DescriptorWrapperOrderer createClassLevelOrderer( + ClassBasedTestDescriptor classBasedTestDescriptor) { + return AnnotationSupport.findAnnotation(classBasedTestDescriptor.getTestClass(), TestClassOrder.class)// + .map(TestClassOrder::value)// + .map(ReflectionSupport::newInstance)// + .map(this::createDescriptorWrapperOrderer)// + .orElseGet(() -> { + Object parent = classBasedTestDescriptor.getParent().orElse(null); + if (parent instanceof ClassBasedTestDescriptor) { + ClassBasedTestDescriptor parentClassTestDescriptor = (ClassBasedTestDescriptor) parent; + DescriptorWrapperOrderer cacheEntry = ordererCache.get( + parentClassTestDescriptor); + return cacheEntry != null ? cacheEntry : createClassLevelOrderer(parentClassTestDescriptor); + } + return globalOrderer; + }); + } + + private DescriptorWrapperOrderer createDescriptorWrapperOrderer( + ClassOrderer classOrderer) { + Consumer> orderingAction = classDescriptors -> classOrderer.orderClasses( + new DefaultClassOrdererContext(classDescriptors, this.configuration)); MessageGenerator descriptorsAddedMessageGenerator = number -> String.format( - "ClassOrderer [%s] added %s ClassDescriptor(s) which will be ignored.", nullSafeToString(classOrderer), + "ClassOrderer [%s] added %s ClassDescriptor(s) which will be ignored.", classOrderer.getClass().getName(), number); MessageGenerator descriptorsRemovedMessageGenerator = number -> String.format( "ClassOrderer [%s] removed %s ClassDescriptor(s) which will be retained with arbitrary ordering.", - nullSafeToString(classOrderer), number); + classOrderer.getClass().getName(), number); - return new DescriptorWrapperOrderer(orderingAction, descriptorsAddedMessageGenerator, + return new DescriptorWrapperOrderer<>(classOrderer, orderingAction, descriptorsAddedMessageGenerator, descriptorsRemovedMessageGenerator); } - private static String nullSafeToString(ClassOrderer classOrderer) { - return (classOrderer != null ? classOrderer.getClass().getName() : ""); + private Optional> toValidationAction( + DescriptorWrapperOrderer wrapperOrderer) { + + if (wrapperOrderer.getOrderer() instanceof ClassOrderer.OrderAnnotation) { + return Optional.empty(); + } + return Optional.of(noOrderAnnotation::check); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,12 +10,18 @@ package org.junit.jupiter.engine.discovery; +import static java.util.Collections.emptyList; import static java.util.function.Predicate.isEqual; import static java.util.stream.Collectors.toCollection; -import static org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests.isTestOrTestFactoryOrTestTemplateMethod; -import static org.junit.platform.commons.support.ReflectionSupport.streamNestedClasses; +import static java.util.stream.Collectors.toSet; +import static org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor.getEnclosingTestClasses; +import static org.junit.jupiter.engine.discovery.predicates.TestClassPredicates.NestedClassInvalidityReason.NOT_INNER; +import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN; +import static org.junit.platform.commons.support.ReflectionSupport.findMethods; import static org.junit.platform.commons.util.FunctionUtils.where; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; +import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; +import static org.junit.platform.commons.util.ReflectionUtils.isNotAbstract; +import static org.junit.platform.commons.util.ReflectionUtils.streamNestedClasses; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; @@ -25,24 +31,37 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor; +import org.junit.jupiter.engine.descriptor.ClassTemplateInvocationTestDescriptor; +import org.junit.jupiter.engine.descriptor.ClassTemplateTestDescriptor; import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; +import org.junit.jupiter.engine.descriptor.Filterable; import org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor; -import org.junit.jupiter.engine.discovery.predicates.IsNestedTestClass; -import org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests; +import org.junit.jupiter.engine.descriptor.TestClassAware; +import org.junit.jupiter.engine.discovery.predicates.TestClassPredicates; +import org.junit.jupiter.engine.discovery.predicates.TestClassPredicates.NestedClassInvalidityReason; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.util.ReflectionUtils.CycleErrorHandling; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.discovery.ClassSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.engine.discovery.IterationSelector; import org.junit.platform.engine.discovery.NestedClassSelector; import org.junit.platform.engine.discovery.UniqueIdSelector; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.discovery.SelectorResolver; /** @@ -50,39 +69,69 @@ */ class ClassSelectorResolver implements SelectorResolver { - private static final IsTestClassWithTests isTestClassWithTests = new IsTestClassWithTests(); - private static final IsNestedTestClass isNestedTestClass = new IsNestedTestClass(); - private final Predicate classNameFilter; private final JupiterConfiguration configuration; + private final TestClassPredicates predicates; + private final DiscoveryIssueReporter issueReporter; - ClassSelectorResolver(Predicate classNameFilter, JupiterConfiguration configuration) { + ClassSelectorResolver(Predicate classNameFilter, JupiterConfiguration configuration, + DiscoveryIssueReporter issueReporter) { this.classNameFilter = classNameFilter; this.configuration = configuration; + this.predicates = new TestClassPredicates(issueReporter); + this.issueReporter = issueReporter; } @Override public Resolution resolve(ClassSelector selector, Context context) { Class testClass = selector.getJavaClass(); - if (isTestClassWithTests.test(testClass)) { - // Nested tests are never filtered out - if (classNameFilter.test(testClass.getName())) { + + if (this.predicates.isAnnotatedWithNested.test(testClass)) { + // Class name filter is not applied to nested test classes + NestedClassInvalidityReason invalidityReason = this.predicates.validateNestedTestClass(testClass); + if (invalidityReason == null) { return toResolution( - context.addToParent(parent -> Optional.of(newClassTestDescriptor(parent, testClass)))); + context.addToParent(() -> DiscoverySelectors.selectClass(testClass.getEnclosingClass()), + parent -> Optional.of(newMemberClassTestDescriptor(parent, testClass)))); } + if (invalidityReason == NOT_INNER) { + return resolveStandaloneTestClass(context, testClass); + } + return unresolved(); } - else if (isNestedTestClass.test(testClass)) { - return toResolution(context.addToParent(() -> DiscoverySelectors.selectClass(testClass.getEnclosingClass()), - parent -> Optional.of(newNestedClassTestDescriptor(parent, testClass)))); + return resolveStandaloneTestClass(context, testClass); + } + + private Resolution resolveStandaloneTestClass(Context context, Class testClass) { + if (isAcceptedStandaloneTestClass(testClass)) { + return toResolution( + context.addToParent(parent -> Optional.of(newStandaloneClassTestDescriptor(parent, testClass)))); } return unresolved(); } + private boolean isAcceptedStandaloneTestClass(Class testClass) { + return this.classNameFilter.test(testClass.getName()) // + && this.predicates.looksLikeIntendedTestClass(testClass) // + && this.predicates.isValidStandaloneTestClass(testClass); + } + @Override public Resolution resolve(NestedClassSelector selector, Context context) { - if (isNestedTestClass.test(selector.getNestedClass())) { - return toResolution(context.addToParent(() -> selectClass(selector.getEnclosingClasses()), - parent -> Optional.of(newNestedClassTestDescriptor(parent, selector.getNestedClass())))); + Class nestedClass = selector.getNestedClass(); + if (this.predicates.isAnnotatedWithNested.test(nestedClass)) { + if (this.predicates.isValidNestedTestClass(nestedClass)) { + return toResolution(context.addToParent(() -> selectClass(selector.getEnclosingClasses()), + parent -> Optional.of(newMemberClassTestDescriptor(parent, nestedClass)))); + } + } + else if (isInnerClass(nestedClass) && isNotAbstract(nestedClass) + && predicates.looksLikeIntendedTestClass(nestedClass)) { + String message = String.format( + "Inner class '%s' looks like it was intended to be a test class but will not be executed. It must be static or annotated with @Nested.", + nestedClass.getName()); + issueReporter.reportIssue(DiscoveryIssue.builder(Severity.WARNING, message) // + .source(ClassSource.from(nestedClass))); } return unresolved(); } @@ -92,55 +141,183 @@ UniqueId uniqueId = selector.getUniqueId(); UniqueId.Segment lastSegment = uniqueId.getLastSegment(); if (ClassTestDescriptor.SEGMENT_TYPE.equals(lastSegment.getType())) { - String className = lastSegment.getValue(); - return ReflectionUtils.tryToLoadClass(className).toOptional().filter(isTestClassWithTests).map( - testClass -> toResolution( - context.addToParent(parent -> Optional.of(newClassTestDescriptor(parent, testClass))))).orElse( - unresolved()); + return resolveStandaloneClassUniqueId(context, lastSegment, __ -> true, this::newClassTestDescriptor); + } + if (ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE.equals(lastSegment.getType())) { + return resolveStandaloneClassUniqueId(context, lastSegment, this.predicates.isAnnotatedWithClassTemplate, + this::newClassTemplateTestDescriptor); } if (NestedClassTestDescriptor.SEGMENT_TYPE.equals(lastSegment.getType())) { - String simpleClassName = lastSegment.getValue(); - return toResolution(context.addToParent(() -> selectUniqueId(uniqueId.removeLastSegment()), parent -> { - if (parent instanceof ClassBasedTestDescriptor) { - Class parentTestClass = ((ClassBasedTestDescriptor) parent).getTestClass(); - return ReflectionUtils.findNestedClasses(parentTestClass, - isNestedTestClass.and( - where(Class::getSimpleName, isEqual(simpleClassName)))).stream().findFirst().flatMap( - testClass -> Optional.of(newNestedClassTestDescriptor(parent, testClass))); - } - return Optional.empty(); - })); + return resolveNestedClassUniqueId(context, uniqueId, __ -> true, this::newNestedClassTestDescriptor); + } + if (ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE.equals(lastSegment.getType())) { + return resolveNestedClassUniqueId(context, uniqueId, this.predicates.isAnnotatedWithClassTemplate, + this::newNestedClassTemplateTestDescriptor); + } + if (ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE.equals(lastSegment.getType())) { + Optional testDescriptor = context.addToParent( + () -> selectUniqueId(uniqueId.removeLastSegment()), parent -> { + int index = Integer.parseInt(lastSegment.getValue().substring(1)); + return Optional.of(newDummyClassTemplateInvocationTestDescriptor(parent, index)); + }); + return toInvocationMatch(testDescriptor) // + .map(Resolution::match) // + .orElse(unresolved()); + } + return unresolved(); + } + + @Override + public Resolution resolve(IterationSelector selector, Context context) { + DiscoverySelector parentSelector = selector.getParentSelector(); + if (parentSelector instanceof ClassSelector + && this.predicates.isAnnotatedWithClassTemplate.test(((ClassSelector) parentSelector).getJavaClass())) { + return resolveIterations(selector, context); + } + if (parentSelector instanceof NestedClassSelector && this.predicates.isAnnotatedWithClassTemplate.test( + ((NestedClassSelector) parentSelector).getNestedClass())) { + return resolveIterations(selector, context); } return unresolved(); } + private Resolution resolveIterations(IterationSelector selector, Context context) { + DiscoverySelector parentSelector = selector.getParentSelector(); + Set matches = selector.getIterationIndices().stream() // + .map(index -> context.addToParent(() -> parentSelector, + parent -> Optional.of(newDummyClassTemplateInvocationTestDescriptor(parent, index + 1)))) // + .map(this::toInvocationMatch) // + .filter(Optional::isPresent) // + .map(Optional::get) // + .collect(toSet()); + return matches.isEmpty() ? unresolved() : Resolution.matches(matches); + } + + private Resolution resolveStandaloneClassUniqueId(Context context, UniqueId.Segment lastSegment, + Predicate> condition, + BiFunction, ClassBasedTestDescriptor> factory) { + + String className = lastSegment.getValue(); + return ReflectionSupport.tryToLoadClass(className).toOptional() // + .filter(this.predicates::isValidStandaloneTestClass) // + .filter(condition) // + .map(testClass -> toResolution( + context.addToParent(parent -> Optional.of(factory.apply(parent, testClass))))) // + .orElse(unresolved()); + } + + private Resolution resolveNestedClassUniqueId(Context context, UniqueId uniqueId, + Predicate> condition, + BiFunction, ClassBasedTestDescriptor> factory) { + + String simpleClassName = uniqueId.getLastSegment().getValue(); + return toResolution(context.addToParent(() -> selectUniqueId(uniqueId.removeLastSegment()), parent -> { + Class parentTestClass = ((TestClassAware) parent).getTestClass(); + return ReflectionSupport.findNestedClasses(parentTestClass, + this.predicates.isAnnotatedWithNestedAndValid.and( + where(Class::getSimpleName, isEqual(simpleClassName)))).stream() // + .findFirst() // + .filter(condition) // + .map(testClass -> factory.apply(parent, testClass)); + })); + } + + private ClassTemplateInvocationTestDescriptor newDummyClassTemplateInvocationTestDescriptor(TestDescriptor parent, + int index) { + UniqueId uniqueId = parent.getUniqueId().append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, + "#" + index); + return new ClassTemplateInvocationTestDescriptor(uniqueId, (ClassTemplateTestDescriptor) parent, + DummyClassTemplateInvocationContext.INSTANCE, index, parent.getSource().orElse(null), configuration); + } + + private ClassBasedTestDescriptor newStandaloneClassTestDescriptor(TestDescriptor parent, Class testClass) { + return this.predicates.isAnnotatedWithClassTemplate.test(testClass) // + ? newClassTemplateTestDescriptor(parent, testClass) // + : newClassTestDescriptor(parent, testClass); + } + + private ClassTemplateTestDescriptor newClassTemplateTestDescriptor(TestDescriptor parent, Class testClass) { + return newClassTemplateTestDescriptor(parent, ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + newClassTestDescriptor(parent, testClass)); + } + private ClassTestDescriptor newClassTestDescriptor(TestDescriptor parent, Class testClass) { return new ClassTestDescriptor( parent.getUniqueId().append(ClassTestDescriptor.SEGMENT_TYPE, testClass.getName()), testClass, configuration); } + private ClassBasedTestDescriptor newMemberClassTestDescriptor(TestDescriptor parent, Class testClass) { + return this.predicates.isAnnotatedWithClassTemplate.test(testClass) // + ? newNestedClassTemplateTestDescriptor(parent, testClass) // + : newNestedClassTestDescriptor(parent, testClass); + } + + private ClassTemplateTestDescriptor newNestedClassTemplateTestDescriptor(TestDescriptor parent, + Class testClass) { + return newClassTemplateTestDescriptor(parent, ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, + newNestedClassTestDescriptor(parent, testClass)); + } + private NestedClassTestDescriptor newNestedClassTestDescriptor(TestDescriptor parent, Class testClass) { - return new NestedClassTestDescriptor( - parent.getUniqueId().append(NestedClassTestDescriptor.SEGMENT_TYPE, testClass.getSimpleName()), testClass, - configuration); + UniqueId uniqueId = parent.getUniqueId().append(NestedClassTestDescriptor.SEGMENT_TYPE, + testClass.getSimpleName()); + return new NestedClassTestDescriptor(uniqueId, testClass, () -> getEnclosingTestClasses(parent), configuration); + } + + private ClassTemplateTestDescriptor newClassTemplateTestDescriptor(TestDescriptor parent, String segmentType, + ClassBasedTestDescriptor delegate) { + + delegate.setParent(parent); + String segmentValue = delegate.getUniqueId().getLastSegment().getValue(); + UniqueId uniqueId = parent.getUniqueId().append(segmentType, segmentValue); + return new ClassTemplateTestDescriptor(uniqueId, delegate); + } + + private Optional toInvocationMatch(Optional testDescriptor) { + return testDescriptor // + .map(it -> Match.exact(it, expansionCallback(it, + () -> it.getParent().map(parent -> getTestClasses((TestClassAware) parent)).orElse(emptyList())))); } private Resolution toResolution(Optional testDescriptor) { - return testDescriptor.map(it -> { - Class testClass = it.getTestClass(); - List> testClasses = new ArrayList<>(it.getEnclosingTestClasses()); - testClasses.add(testClass); - // @formatter:off - return Resolution.match(Match.exact(it, () -> { - Stream methods = findMethods(testClass, isTestOrTestFactoryOrTestTemplateMethod).stream() + return testDescriptor // + .map(it -> Resolution.match(Match.exact(it, expansionCallback(it)))) // + .orElse(unresolved()); + } + + private Supplier> expansionCallback(ClassBasedTestDescriptor testDescriptor) { + return expansionCallback(testDescriptor, () -> getTestClasses(testDescriptor)); + } + + private static List> getTestClasses(TestClassAware testDescriptor) { + List> testClasses = new ArrayList<>(testDescriptor.getEnclosingTestClasses()); + testClasses.add(testDescriptor.getTestClass()); + return testClasses; + } + + private Supplier> expansionCallback(TestDescriptor testDescriptor, + Supplier>> testClassesSupplier) { + return () -> { + if (testDescriptor instanceof Filterable) { + Filterable filterable = (Filterable) testDescriptor; + filterable.getDynamicDescendantFilter().allowAll(); + } + List> testClasses = testClassesSupplier.get(); + Class testClass = testClasses.get(testClasses.size() - 1); + Stream methods = findMethods(testClass, + this.predicates.isTestOrTestFactoryOrTestTemplateMethod, TOP_DOWN).stream() // .map(method -> selectMethod(testClasses, method)); - Stream nestedClasses = streamNestedClasses(testClass, isNestedTestClass) - .map(nestedClass -> DiscoverySelectors.selectNestedClass(testClasses, nestedClass)); - return Stream.concat(methods, nestedClasses).collect(toCollection((Supplier>) LinkedHashSet::new)); - })); - // @formatter:on - }).orElse(unresolved()); + Stream> annotatedNestedClasses = streamNestedClasses(testClass, + this.predicates.isAnnotatedWithNested); + Stream> notAnnotatedInnerClasses = streamNestedClasses(testClass, + this.predicates.isAnnotatedWithNested.negate().and(ReflectionUtils::isInnerClass), + CycleErrorHandling.ABORT_VISIT); + Stream nestedClasses = Stream.concat(annotatedNestedClasses, notAnnotatedInnerClasses) // + .map(nestedClass -> DiscoverySelectors.selectNestedClass(testClasses, nestedClass)); + return Stream.concat(methods, nestedClasses).collect( + toCollection((Supplier>) LinkedHashSet::new)); + }; } private DiscoverySelector selectClass(List> classes) { @@ -152,11 +329,10 @@ } private DiscoverySelector selectMethod(List> classes, Method method) { - if (classes.size() == 1) { - return DiscoverySelectors.selectMethod(classes.get(0), method); - } - int lastIndex = classes.size() - 1; - return DiscoverySelectors.selectNestedMethod(classes.subList(0, lastIndex), classes.get(lastIndex), method); + return new DeclaredMethodSelector(classes, method); } + static class DummyClassTemplateInvocationContext implements ClassTemplateInvocationContext { + private static final DummyClassTemplateInvocationContext INSTANCE = new DummyClassTemplateInvocationContext(); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DeclaredMethodSelector.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DeclaredMethodSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DeclaredMethodSelector.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DeclaredMethodSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.discovery; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Objects; + +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.discovery.MethodSelector; + +/** + * Jupiter-specific selector for methods, potentially in nested classes. + * + *

The important difference to {@link MethodSelector} is that this selector's + * {@link #equals(Object)} method takes into account the selected method's + * {@linkplain Method#getDeclaringClass() declaring class} to support cases + * where a package-private method is declared in a super class in a different + * package and a method with the same signature is declared in a subclass. In + * that case both methods should be discovered because the one declared in the + * subclass does not override the one in the super class. + * + * @since 5.14.1 + */ +final class DeclaredMethodSelector implements DiscoverySelector { + + private final List> testClasses; + private final Method method; + + DeclaredMethodSelector(List> testClasses, Method method) { + Preconditions.notEmpty(testClasses, "testClasses must not be empty"); + this.testClasses = Preconditions.containsNoNullElements(testClasses, + "testClasses must not contain null elements"); + this.method = Preconditions.notNull(method, "method must not be null"); + } + + List> testClasses() { + return testClasses; + } + + Method method() { + return method; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof DeclaredMethodSelector)) { + return false; + } + DeclaredMethodSelector that = (DeclaredMethodSelector) o; + return Objects.equals(testClasses, that.testClasses) // + && Objects.equals(method, that.method); + } + + @Override + public int hashCode() { + return Objects.hash(testClasses, method); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassOrdererContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassOrdererContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassOrdererContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultClassOrdererContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodOrdererContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodOrdererContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodOrdererContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DefaultMethodOrdererContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,11 +13,15 @@ import static org.apiguardian.api.API.Status.INTERNAL; import org.apiguardian.api.API; +import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; -import org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests; +import org.junit.jupiter.engine.descriptor.Validatable; +import org.junit.jupiter.engine.discovery.predicates.TestClassPredicates; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver; +import org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver.InitializationContext; /** * {@code DiscoverySelectorResolver} resolves {@link TestDescriptor TestDescriptors} @@ -33,19 +37,30 @@ @API(status = INTERNAL, since = "5.0") public class DiscoverySelectorResolver { - // @formatter:off - private static final EngineDiscoveryRequestResolver resolver = EngineDiscoveryRequestResolver.builder() - .addClassContainerSelectorResolver(new IsTestClassWithTests()) - .addSelectorResolver(context -> new ClassSelectorResolver(context.getClassNameFilter(), context.getEngineDescriptor().getConfiguration())) - .addSelectorResolver(context -> new MethodSelectorResolver(context.getEngineDescriptor().getConfiguration())) - .addTestDescriptorVisitor(context -> new ClassOrderingVisitor(context.getEngineDescriptor().getConfiguration())) - .addTestDescriptorVisitor(context -> new MethodOrderingVisitor(context.getEngineDescriptor().getConfiguration())) - .addTestDescriptorVisitor(context -> TestDescriptor::prune) + private static final EngineDiscoveryRequestResolver resolver = EngineDiscoveryRequestResolver. builder() // + .addClassContainerSelectorResolverWithContext( + ctx -> new TestClassPredicates(ctx.getIssueReporter()).looksLikeNestedOrStandaloneTestClass) // + .addSelectorResolver(ctx -> new ClassSelectorResolver(ctx.getClassNameFilter(), getConfiguration(ctx), + ctx.getIssueReporter())) // + .addSelectorResolver(ctx -> new MethodSelectorResolver(getConfiguration(ctx), ctx.getIssueReporter())) // + .addTestDescriptorVisitor(ctx -> TestDescriptor.Visitor.composite( // + new ClassOrderingVisitor(getConfiguration(ctx), ctx.getIssueReporter()), // + new MethodOrderingVisitor(getConfiguration(ctx), ctx.getIssueReporter()), // + descriptor -> { + if (descriptor instanceof Validatable) { + ((Validatable) descriptor).validate(ctx.getIssueReporter()); + } + })) // .build(); - // @formatter:on + + private static JupiterConfiguration getConfiguration(InitializationContext context) { + return context.getEngineDescriptor().getConfiguration(); + } public void resolveSelectors(EngineDiscoveryRequest request, JupiterEngineDescriptor engineDescriptor) { - resolver.resolve(request, engineDescriptor); + DiscoveryIssueReporter issueReporter = DiscoveryIssueReporter.deduplicating( + DiscoveryIssueReporter.forwarding(request.getDiscoveryListener(), engineDescriptor.getUniqueId())); + resolver.resolve(request, engineDescriptor, issueReporter); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodFinder.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodFinder.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodFinder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodFinder.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery; - -import java.lang.reflect.Method; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; - -/** - * @since 5.0 - */ -class MethodFinder { - - // Pattern: methodName(comma-separated list of parameter type names) - private static final Pattern METHOD_PATTERN = Pattern.compile("(.+)\\((.*)\\)"); - - Optional findMethod(String methodSpecPart, Class clazz) { - Matcher matcher = METHOD_PATTERN.matcher(methodSpecPart); - - Preconditions.condition(matcher.matches(), - () -> String.format("Method [%s] does not match pattern [%s]", methodSpecPart, METHOD_PATTERN)); - - String methodName = matcher.group(1); - String parameterTypeNames = matcher.group(2); - return ReflectionUtils.findMethod(clazz, methodName, parameterTypeNames); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodOrderingVisitor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodOrderingVisitor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodOrderingVisitor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodOrderingVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,31 +10,55 @@ package org.junit.jupiter.engine.discovery; +import static java.util.Comparator.comparing; import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; +import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import java.util.function.UnaryOperator; import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor; import org.junit.jupiter.engine.descriptor.JupiterTestDescriptor; import org.junit.jupiter.engine.descriptor.MethodBasedTestDescriptor; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.Condition; /** * @since 5.5 */ -class MethodOrderingVisitor - extends AbstractOrderingVisitor { +class MethodOrderingVisitor extends AbstractOrderingVisitor { private final JupiterConfiguration configuration; + private final Condition noOrderAnnotation; - MethodOrderingVisitor(JupiterConfiguration configuration) { + // Not a static field to avoid initialization at build time for GraalVM + private final UnaryOperator> methodsBeforeNestedClassesOrderer; + + MethodOrderingVisitor(JupiterConfiguration configuration, DiscoveryIssueReporter issueReporter) { + super(issueReporter); this.configuration = configuration; + this.noOrderAnnotation = issueReporter.createReportingCondition( + testDescriptor -> !isAnnotated(testDescriptor.getTestMethod(), Order.class), testDescriptor -> { + String message = String.format("Ineffective @Order annotation on method '%s'. ", + testDescriptor.getTestMethod().toGenericString()) + + "It will not be applied because MethodOrderer.OrderAnnotation is not in use. " + + "Note that the annotation may be either directly present or meta-present on the method."; + return DiscoveryIssue.builder(Severity.INFO, message) // + .source(testDescriptor.getSource()) // + .build(); + }); + this.methodsBeforeNestedClassesOrderer = createMethodsBeforeNestedClassesOrderer(); } @Override @@ -44,41 +68,87 @@ descriptor -> "Failed to order methods for " + descriptor.getTestClass()); } + @Override + protected boolean shouldNonMatchingDescriptorsComeBeforeOrderedOnes() { + // Non-matching descriptors can only contain @Nested test classes which should be + // added after local test methods. + return false; + } + /** * @since 5.4 */ private void orderContainedMethods(ClassBasedTestDescriptor classBasedTestDescriptor, Class testClass) { - findAnnotation(testClass, TestMethodOrder.class)// + Optional methodOrderer = findAnnotation(testClass, TestMethodOrder.class)// .map(TestMethodOrder::value)// - . map(ReflectionUtils::newInstance)// + . map(ReflectionSupport::newInstance)// .map(Optional::of)// - .orElseGet(configuration::getDefaultTestMethodOrderer)// - .ifPresent(methodOrderer -> { + .orElseGet(configuration::getDefaultTestMethodOrderer); + orderContainedMethods(classBasedTestDescriptor, testClass, methodOrderer); + } + + private void orderContainedMethods(ClassBasedTestDescriptor classBasedTestDescriptor, Class testClass, + Optional methodOrderer) { + + DescriptorWrapperOrderer descriptorWrapperOrderer = createDescriptorWrapperOrderer( + testClass, methodOrderer); + + orderChildrenTestDescriptors(classBasedTestDescriptor, // + MethodBasedTestDescriptor.class, // + toValidationAction(methodOrderer), // + DefaultMethodDescriptor::new, // + descriptorWrapperOrderer); + + if (!methodOrderer.isPresent()) { + // If there is an orderer, this is ensured by the call above + classBasedTestDescriptor.orderChildren(methodsBeforeNestedClassesOrderer); + } + + // Note: MethodOrderer#getDefaultExecutionMode() is guaranteed + // to be invoked after MethodOrderer#orderMethods(). + methodOrderer // + .flatMap(it -> it.getDefaultExecutionMode().map(JupiterTestDescriptor::toExecutionMode)) // + .ifPresent(classBasedTestDescriptor::setDefaultChildExecutionMode); + } - Consumer> orderingAction = methodDescriptors -> methodOrderer.orderMethods( - new DefaultMethodOrdererContext(testClass, methodDescriptors, this.configuration)); + private DescriptorWrapperOrderer createDescriptorWrapperOrderer(Class testClass, + Optional methodOrderer) { + + return methodOrderer // + .map(it -> createDescriptorWrapperOrderer(testClass, it)) // + .orElseGet(DescriptorWrapperOrderer::noop); + + } + + private DescriptorWrapperOrderer createDescriptorWrapperOrderer(Class testClass, + MethodOrderer methodOrderer) { + Consumer> orderingAction = methodDescriptors -> methodOrderer.orderMethods( + new DefaultMethodOrdererContext(testClass, methodDescriptors, this.configuration)); + + MessageGenerator descriptorsAddedMessageGenerator = number -> String.format( + "MethodOrderer [%s] added %s MethodDescriptor(s) for test class [%s] which will be ignored.", + methodOrderer.getClass().getName(), number, testClass.getName()); + MessageGenerator descriptorsRemovedMessageGenerator = number -> String.format( + "MethodOrderer [%s] removed %s MethodDescriptor(s) for test class [%s] which will be retained with arbitrary ordering.", + methodOrderer.getClass().getName(), number, testClass.getName()); + + return new DescriptorWrapperOrderer<>(methodOrderer, orderingAction, descriptorsAddedMessageGenerator, + descriptorsRemovedMessageGenerator); + } + + private Optional> toValidationAction(Optional methodOrderer) { + if (methodOrderer.orElse(null) instanceof MethodOrderer.OrderAnnotation) { + return Optional.empty(); + } + return Optional.of(noOrderAnnotation::check); + } - MessageGenerator descriptorsAddedMessageGenerator = number -> String.format( - "MethodOrderer [%s] added %s MethodDescriptor(s) for test class [%s] which will be ignored.", - methodOrderer.getClass().getName(), number, testClass.getName()); - MessageGenerator descriptorsRemovedMessageGenerator = number -> String.format( - "MethodOrderer [%s] removed %s MethodDescriptor(s) for test class [%s] which will be retained with arbitrary ordering.", - methodOrderer.getClass().getName(), number, testClass.getName()); - - DescriptorWrapperOrderer descriptorWrapperOrderer = new DescriptorWrapperOrderer(orderingAction, - descriptorsAddedMessageGenerator, descriptorsRemovedMessageGenerator); - - orderChildrenTestDescriptors(classBasedTestDescriptor, // - MethodBasedTestDescriptor.class, // - DefaultMethodDescriptor::new, // - descriptorWrapperOrderer); - - // Note: MethodOrderer#getDefaultExecutionMode() is guaranteed - // to be invoked after MethodOrderer#orderMethods(). - methodOrderer.getDefaultExecutionMode()// - .map(JupiterTestDescriptor::toExecutionMode)// - .ifPresent(classBasedTestDescriptor::setDefaultChildExecutionMode); - }); + private static UnaryOperator> createMethodsBeforeNestedClassesOrderer() { + Comparator methodsFirst = comparing(MethodBasedTestDescriptor.class::isInstance).reversed(); + return children -> { + children.sort(methodsFirst); + return children; + }; } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSegmentResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSegmentResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSegmentResolver.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSegmentResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.discovery; + +import static org.junit.platform.commons.util.ReflectionUtils.isDeclaredInSamePackage; +import static org.junit.platform.commons.util.ReflectionUtils.isPackagePrivate; + +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.util.ClassUtils; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ReflectionUtils; + +/** + * @since 5.0 + */ +class MethodSegmentResolver { + + // Pattern: [declaringClassName#]methodName(comma-separated list of parameter type names) + private static final Pattern METHOD_PATTERN = Pattern.compile( + "(?:(?.+)#)?(?.+)\\((?.*)\\)"); + + /** + * If the {@code method} is package-private and declared a class in a + * different package than {@code testClass}, the declaring class name is + * included in the method's unique ID segment. Otherwise, it only + * consists of the method name and its parameter types. + */ + String formatMethodSpecPart(Method method, Class testClass) { + String parameterTypes = ClassUtils.nullSafeToString(method.getParameterTypes()); + if (isPackagePrivate(method) && !isDeclaredInSamePackage(method.getDeclaringClass(), testClass)) { + return String.format("%s#%s(%s)", method.getDeclaringClass().getName(), method.getName(), parameterTypes); + } + return String.format("%s(%s)", method.getName(), parameterTypes); + } + + Optional findMethod(String methodSpecPart, Class testClass) { + Matcher matcher = METHOD_PATTERN.matcher(methodSpecPart); + + Preconditions.condition(matcher.matches(), + () -> String.format("Method [%s] does not match pattern [%s]", methodSpecPart, METHOD_PATTERN)); + + Class targetClass = testClass; + String declaringClass = matcher.group("declaringClass"); + if (declaringClass != null) { + targetClass = ReflectionUtils.tryToLoadClass(declaringClass).getOrThrow( + cause -> new PreconditionViolationException( + "Could not load declaring class with name: " + declaringClass, cause)); + } + String methodName = matcher.group("method"); + String parameterTypeNames = matcher.group("parameters"); + return ReflectionSupport.findMethod(targetClass, methodName, parameterTypeNames); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -30,20 +30,18 @@ import java.util.stream.Stream; import org.junit.jupiter.engine.config.JupiterConfiguration; -import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor; import org.junit.jupiter.engine.descriptor.Filterable; +import org.junit.jupiter.engine.descriptor.TestClassAware; import org.junit.jupiter.engine.descriptor.TestFactoryTestDescriptor; import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; import org.junit.jupiter.engine.descriptor.TestTemplateInvocationTestDescriptor; import org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor; -import org.junit.jupiter.engine.discovery.predicates.IsNestedTestClass; -import org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests; import org.junit.jupiter.engine.discovery.predicates.IsTestFactoryMethod; import org.junit.jupiter.engine.discovery.predicates.IsTestMethod; import org.junit.jupiter.engine.discovery.predicates.IsTestTemplateMethod; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.ClassUtils; +import org.junit.jupiter.engine.discovery.predicates.TestClassPredicates; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; @@ -52,6 +50,8 @@ import org.junit.platform.engine.discovery.MethodSelector; import org.junit.platform.engine.discovery.NestedMethodSelector; import org.junit.platform.engine.discovery.UniqueIdSelector; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.discovery.SelectorResolver; /** @@ -59,15 +59,18 @@ */ class MethodSelectorResolver implements SelectorResolver { - private static final Logger logger = LoggerFactory.getLogger(MethodSelectorResolver.class); - private static final MethodFinder methodFinder = new MethodFinder(); - private static final Predicate> testClassPredicate = new IsTestClassWithTests().or( - new IsNestedTestClass()); + private static final MethodSegmentResolver methodSegmentResolver = new MethodSegmentResolver(); + private final Predicate> testClassPredicate; - protected final JupiterConfiguration configuration; + private final JupiterConfiguration configuration; + private final DiscoveryIssueReporter issueReporter; + private final List methodTypes; - MethodSelectorResolver(JupiterConfiguration configuration) { + MethodSelectorResolver(JupiterConfiguration configuration, DiscoveryIssueReporter issueReporter) { this.configuration = configuration; + this.issueReporter = issueReporter; + this.methodTypes = MethodType.allPossibilities(issueReporter); + this.testClassPredicate = new TestClassPredicates(issueReporter).looksLikeNestedOrStandaloneTestClass; } @Override @@ -81,6 +84,21 @@ Match::exact); } + @Override + public Resolution resolve(DiscoverySelector selector, Context context) { + if (selector instanceof DeclaredMethodSelector) { + DeclaredMethodSelector methodSelector = (DeclaredMethodSelector) selector; + List> testClasses = methodSelector.testClasses(); + if (testClasses.size() == 1) { + return resolve(context, emptyList(), testClasses.get(0), methodSelector::method, Match::exact); + } + int lastIndex = testClasses.size() - 1; + return resolve(context, testClasses.subList(0, lastIndex), testClasses.get(lastIndex), + methodSelector::method, Match::exact); + } + return unresolved(); + } + private Resolution resolve(Context context, List> enclosingClasses, Class testClass, Supplier methodSupplier, BiFunction>, Match> matchFactory) { @@ -89,7 +107,7 @@ } Method method = methodSupplier.get(); // @formatter:off - Set matches = Arrays.stream(MethodType.values()) + Set matches = methodTypes.stream() .map(methodType -> methodType.resolve(enclosingClasses, testClass, method, context, configuration)) .filter(Optional::isPresent) .map(Optional::get) @@ -97,14 +115,14 @@ .collect(toSet()); // @formatter:on if (matches.size() > 1) { - logger.warn(() -> { - Stream testDescriptors = matches.stream().map(Match::getTestDescriptor); - return String.format( - "Possible configuration error: method [%s] resulted in multiple TestDescriptors %s. " - + "This is typically the result of annotating a method with multiple competing annotations " - + "such as @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, etc.", - method.toGenericString(), testDescriptors.map(d -> d.getClass().getName()).collect(toList())); - }); + Stream testDescriptors = matches.stream().map(Match::getTestDescriptor); + String message = String.format( + "Possible configuration error: method [%s] resulted in multiple TestDescriptors %s. " + + "This is typically the result of annotating a method with multiple competing annotations " + + "such as @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, etc.", + method.toGenericString(), testDescriptors.map(d -> d.getClass().getName()).collect(toList())); + issueReporter.reportIssue( + DiscoveryIssue.builder(Severity.WARNING, message).source(MethodSource.from(method))); } return matches.isEmpty() ? unresolved() : matches(matches); } @@ -113,7 +131,7 @@ public Resolution resolve(UniqueIdSelector selector, Context context) { UniqueId uniqueId = selector.getUniqueId(); // @formatter:off - return Arrays.stream(MethodType.values()) + return methodTypes.stream() .map(methodType -> methodType.resolveUniqueIdIntoTestDescriptor(uniqueId, context, configuration)) .filter(Optional::isPresent) .map(Optional::get) @@ -161,53 +179,40 @@ }; } - private enum MethodType { + private static class MethodType { - TEST(new IsTestMethod(), TestMethodTestDescriptor.SEGMENT_TYPE) { - @Override - protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration) { - return new TestMethodTestDescriptor(uniqueId, testClass, method, configuration); - } - }, - - TEST_FACTORY(new IsTestFactoryMethod(), TestFactoryTestDescriptor.SEGMENT_TYPE, - TestFactoryTestDescriptor.DYNAMIC_CONTAINER_SEGMENT_TYPE, - TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE) { - @Override - protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration) { - return new TestFactoryTestDescriptor(uniqueId, testClass, method, configuration); - } - }, - - TEST_TEMPLATE(new IsTestTemplateMethod(), TestTemplateTestDescriptor.SEGMENT_TYPE, - TestTemplateInvocationTestDescriptor.SEGMENT_TYPE) { - @Override - protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration) { - return new TestTemplateTestDescriptor(uniqueId, testClass, method, configuration); - } - }; + static List allPossibilities(DiscoveryIssueReporter issueReporter) { + return Arrays.asList( // + new MethodType(new IsTestMethod(issueReporter), TestMethodTestDescriptor::new, + TestMethodTestDescriptor.SEGMENT_TYPE), // + new MethodType(new IsTestFactoryMethod(issueReporter), TestFactoryTestDescriptor::new, + TestFactoryTestDescriptor.SEGMENT_TYPE, TestFactoryTestDescriptor.DYNAMIC_CONTAINER_SEGMENT_TYPE, + TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE), // + new MethodType(new IsTestTemplateMethod(issueReporter), TestTemplateTestDescriptor::new, + TestTemplateTestDescriptor.SEGMENT_TYPE, TestTemplateInvocationTestDescriptor.SEGMENT_TYPE) // + ); + } private final Predicate methodPredicate; + private final TestDescriptorFactory testDescriptorFactory; private final String segmentType; private final Set dynamicDescendantSegmentTypes; - MethodType(Predicate methodPredicate, String segmentType, String... dynamicDescendantSegmentTypes) { + private MethodType(Predicate methodPredicate, TestDescriptorFactory testDescriptorFactory, + String segmentType, String... dynamicDescendantSegmentTypes) { this.methodPredicate = methodPredicate; + this.testDescriptorFactory = testDescriptorFactory; this.segmentType = segmentType; this.dynamicDescendantSegmentTypes = new LinkedHashSet<>(Arrays.asList(dynamicDescendantSegmentTypes)); } - private Optional resolve(List> enclosingClasses, Class testClass, Method method, + Optional resolve(List> enclosingClasses, Class testClass, Method method, Context context, JupiterConfiguration configuration) { if (!methodPredicate.test(method)) { return Optional.empty(); } return context.addToParent(() -> selectClass(enclosingClasses, testClass), // - parent -> Optional.of( - createTestDescriptor(createUniqueId(method, parent), testClass, method, configuration))); + parent -> Optional.of(createTestDescriptor(parent, testClass, method, configuration))); } private DiscoverySelector selectClass(List> enclosingClasses, Class testClass) { @@ -217,17 +222,17 @@ return DiscoverySelectors.selectNestedClass(enclosingClasses, testClass); } - private Optional resolveUniqueIdIntoTestDescriptor(UniqueId uniqueId, Context context, + Optional resolveUniqueIdIntoTestDescriptor(UniqueId uniqueId, Context context, JupiterConfiguration configuration) { UniqueId.Segment lastSegment = uniqueId.getLastSegment(); if (segmentType.equals(lastSegment.getType())) { return context.addToParent(() -> selectUniqueId(uniqueId.removeLastSegment()), parent -> { String methodSpecPart = lastSegment.getValue(); - Class testClass = ((ClassBasedTestDescriptor) parent).getTestClass(); + Class testClass = ((TestClassAware) parent).getTestClass(); // @formatter:off - return methodFinder.findMethod(methodSpecPart, testClass) + return methodSegmentResolver.findMethod(methodSpecPart, testClass) .filter(methodPredicate) - .map(method -> createTestDescriptor(createUniqueId(method, parent), testClass, method, configuration)); + .map(method -> createTestDescriptor(parent, testClass, method, configuration)); // @formatter:on }); } @@ -237,14 +242,22 @@ return Optional.empty(); } - private UniqueId createUniqueId(Method method, TestDescriptor parent) { - String methodId = String.format("%s(%s)", method.getName(), - ClassUtils.nullSafeToString(method.getParameterTypes())); - return parent.getUniqueId().append(segmentType, methodId); + private TestDescriptor createTestDescriptor(TestDescriptor parent, Class testClass, Method method, + JupiterConfiguration configuration) { + UniqueId uniqueId = createUniqueId(method, parent, testClass); + return testDescriptorFactory.create(uniqueId, testClass, method, + ((TestClassAware) parent)::getEnclosingTestClasses, configuration); + } + + private UniqueId createUniqueId(Method method, TestDescriptor parent, Class testClass) { + return parent.getUniqueId().append(segmentType, + methodSegmentResolver.formatMethodSpecPart(method, testClass)); } - protected abstract TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration); + interface TestDescriptorFactory { + TestDescriptor create(UniqueId uniqueId, Class testClass, Method method, + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClass.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClass.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClass.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; -import static org.junit.platform.commons.util.ReflectionUtils.isPrivate; - -import java.util.function.Predicate; - -import org.apiguardian.api.API; - -/** - * Test if a class is a non-private inner class (i.e., a non-static nested class). - * - * @since 5.0 - */ -@API(status = INTERNAL, since = "5.0") -public class IsInnerClass implements Predicate> { - - @Override - public boolean test(Class candidate) { - // Do not collapse into a single return statement. - if (isPrivate(candidate)) { - return false; - } - if (!isInnerClass(candidate)) { - return false; - } - - return true; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClass.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClass.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClass.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; - -import java.util.function.Predicate; - -import org.apiguardian.api.API; -import org.junit.jupiter.api.Nested; - -/** - * Test if a class is a JUnit Jupiter {@link Nested @Nested} test class. - * - * @since 5.0 - */ -@API(status = INTERNAL, since = "5.0") -public class IsNestedTestClass implements Predicate> { - - private static final IsInnerClass isInnerClass = new IsInnerClass(); - - @Override - public boolean test(Class candidate) { - //please do not collapse into single return - if (!isInnerClass.test(candidate)) { - return false; - } - return isAnnotated(candidate, Nested.class); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainer.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.ReflectionUtils.isAbstract; -import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; -import static org.junit.platform.commons.util.ReflectionUtils.isPrivate; - -import java.util.function.Predicate; - -import org.apiguardian.api.API; - -/** - * Test if a class is a potential top-level JUnit Jupiter test container, even if - * it does not contain tests. - * - * @since 5.0 - */ -@API(status = INTERNAL, since = "5.0") -public class IsPotentialTestContainer implements Predicate> { - - @Override - public boolean test(Class candidate) { - // Please do not collapse the following into a single statement. - if (isPrivate(candidate)) { - return false; - } - if (isAbstract(candidate)) { - return false; - } - if (candidate.isLocalClass()) { - return false; - } - if (candidate.isAnonymousClass()) { - return false; - } - return !isInnerClass(candidate); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTests.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTests.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.lang.reflect.Method; -import java.util.function.Predicate; - -import org.apiguardian.api.API; -import org.junit.platform.commons.util.ReflectionUtils; - -/** - * Test if a class is a JUnit Jupiter test class containing executable tests, - * test factories, test templates, or nested tests. - * - * @since 5.0 - */ -@API(status = INTERNAL, since = "5.1") -public class IsTestClassWithTests implements Predicate> { - - private static final IsTestMethod isTestMethod = new IsTestMethod(); - - private static final IsTestFactoryMethod isTestFactoryMethod = new IsTestFactoryMethod(); - - private static final IsTestTemplateMethod isTestTemplateMethod = new IsTestTemplateMethod(); - - public static final Predicate isTestOrTestFactoryOrTestTemplateMethod = isTestMethod.or( - isTestFactoryMethod).or(isTestTemplateMethod); - - private static final IsPotentialTestContainer isPotentialTestContainer = new IsPotentialTestContainer(); - - private static final IsNestedTestClass isNestedTestClass = new IsNestedTestClass(); - - @Override - public boolean test(Class candidate) { - return isPotentialTestContainer.test(candidate) - && (hasTestOrTestFactoryOrTestTemplateMethods(candidate) || hasNestedTests(candidate)); - } - - private boolean hasTestOrTestFactoryOrTestTemplateMethods(Class candidate) { - return ReflectionUtils.isMethodPresent(candidate, isTestOrTestFactoryOrTestTemplateMethod); - } - - private boolean hasNestedTests(Class candidate) { - return !ReflectionUtils.findNestedClasses(candidate, isNestedTestClass).isEmpty(); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethod.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,9 +11,21 @@ package org.junit.jupiter.engine.discovery.predicates; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.util.CollectionUtils.isConvertibleToStream; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; import org.apiguardian.api.API; +import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Test if a method is a JUnit Jupiter {@link TestFactory @TestFactory} method. @@ -26,8 +38,74 @@ @API(status = INTERNAL, since = "5.0") public class IsTestFactoryMethod extends IsTestableMethod { - public IsTestFactoryMethod() { - super(TestFactory.class, false); + private static final String EXPECTED_RETURN_TYPE_MESSAGE = String.format( + "must return a single %1$s or a Stream, Collection, Iterable, Iterator, Iterator provider, or array of %1$s", + DynamicNode.class.getName()); + + public IsTestFactoryMethod(DiscoveryIssueReporter issueReporter) { + super(TestFactory.class, IsTestFactoryMethod::hasCompatibleReturnType, issueReporter); + } + + private static DiscoveryIssueReporter.Condition hasCompatibleReturnType( + Class annotationType, DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(method -> isCompatible(method, issueReporter), + method -> createIssue(annotationType, method, EXPECTED_RETURN_TYPE_MESSAGE)); + } + + private static boolean isCompatible(Method method, DiscoveryIssueReporter issueReporter) { + Class returnType = method.getReturnType(); + if (DynamicNode.class.isAssignableFrom(returnType) || DynamicNode[].class.isAssignableFrom(returnType)) { + return true; + } + if (returnType == Object.class || returnType == Object[].class) { + issueReporter.reportIssue(createTooGenericReturnTypeIssue(method)); + return true; + } + boolean validContainerType = !returnType.isArray() && isConvertibleToStream(returnType); + return validContainerType && isCompatibleContainerType(method, issueReporter); + } + + private static boolean isCompatibleContainerType(Method method, DiscoveryIssueReporter issueReporter) { + Type genericReturnType = method.getGenericReturnType(); + + if (genericReturnType instanceof ParameterizedType) { + Type[] typeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); + if (typeArguments.length == 1) { + Type typeArgument = typeArguments[0]; + if (typeArgument instanceof Class) { + // Stream etc. + return DynamicNode.class.isAssignableFrom((Class) typeArgument); + } + if (typeArgument instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) typeArgument; + Type[] upperBounds = wildcardType.getUpperBounds(); + Type[] lowerBounds = wildcardType.getLowerBounds(); + if (upperBounds.length == 1 && lowerBounds.length == 0 && upperBounds[0] instanceof Class) { + Class upperBound = (Class) upperBounds[0]; + if (Object.class.equals(upperBound)) { // Stream etc. + issueReporter.reportIssue(createTooGenericReturnTypeIssue(method)); + return true; + } + // Stream etc. + return DynamicNode.class.isAssignableFrom(upperBound); + } + } + } + return false; + } + + // Raw Stream etc. without type argument + issueReporter.reportIssue(createTooGenericReturnTypeIssue(method)); + return true; + } + + private static DiscoveryIssue.Builder createTooGenericReturnTypeIssue(Method method) { + String message = String.format( + "The declared return type of @TestFactory method '%s' does not support static validation. It " + + EXPECTED_RETURN_TYPE_MESSAGE + ".", + method.toGenericString()); + return DiscoveryIssue.builder(Severity.INFO, message) // + .source(MethodSource.from(method)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethod.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.Test; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Test if a method is a JUnit Jupiter {@link Test @Test} method. @@ -23,8 +24,8 @@ @API(status = INTERNAL, since = "5.0") public class IsTestMethod extends IsTestableMethod { - public IsTestMethod() { - super(Test.class, true); + public IsTestMethod(DiscoveryIssueReporter issueReporter) { + super(Test.class, IsTestableMethod::hasVoidReturnType, issueReporter); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethod.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.TestTemplate; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Test if a method is a JUnit Jupiter {@link TestTemplate @TestTemplate} method. @@ -23,8 +24,8 @@ @API(status = INTERNAL, since = "5.0") public class IsTestTemplateMethod extends IsTestableMethod { - public IsTestTemplateMethod() { - super(TestTemplate.class, true); + public IsTestTemplateMethod(DiscoveryIssueReporter issueReporter) { + super(TestTemplate.class, IsTestableMethod::hasVoidReturnType, issueReporter); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestableMethod.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestableMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestableMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestableMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,46 +10,72 @@ package org.junit.jupiter.engine.discovery.predicates; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; -import static org.junit.platform.commons.util.ReflectionUtils.isAbstract; -import static org.junit.platform.commons.util.ReflectionUtils.isPrivate; -import static org.junit.platform.commons.util.ReflectionUtils.isStatic; -import static org.junit.platform.commons.util.ReflectionUtils.returnsPrimitiveVoid; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; +import static org.junit.platform.commons.support.ModifierSupport.isNotAbstract; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.function.BiFunction; import java.util.function.Predicate; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.Condition; + /** * @since 5.0 */ abstract class IsTestableMethod implements Predicate { private final Class annotationType; - private final boolean mustReturnPrimitiveVoid; + private final Condition condition; - IsTestableMethod(Class annotationType, boolean mustReturnPrimitiveVoid) { + IsTestableMethod(Class annotationType, + BiFunction, DiscoveryIssueReporter, Condition> returnTypeConditionFactory, + DiscoveryIssueReporter issueReporter) { this.annotationType = annotationType; - this.mustReturnPrimitiveVoid = mustReturnPrimitiveVoid; + this.condition = isNotStatic(annotationType, issueReporter) // + .and(isNotPrivate(annotationType, issueReporter)) // + .and(returnTypeConditionFactory.apply(annotationType, issueReporter)); } @Override public boolean test(Method candidate) { - // Please do not collapse the following into a single statement. - if (isStatic(candidate)) { - return false; - } - if (isPrivate(candidate)) { - return false; - } - if (isAbstract(candidate)) { - return false; - } - if (returnsPrimitiveVoid(candidate) != this.mustReturnPrimitiveVoid) { - return false; + if (isAnnotated(candidate, this.annotationType)) { + return condition.check(candidate) && isNotAbstract(candidate); } + return false; + } + + private static Condition isNotStatic(Class annotationType, + DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ModifierSupport::isNotStatic, + method -> createIssue(annotationType, method, "must not be static")); + } + + private static Condition isNotPrivate(Class annotationType, + DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ModifierSupport::isNotPrivate, + method -> createIssue(annotationType, method, "must not be private")); + } + + protected static Condition hasVoidReturnType(Class annotationType, + DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ReflectionUtils::returnsPrimitiveVoid, + method -> createIssue(annotationType, method, "must not return a value")); + } - return isAnnotated(candidate, this.annotationType); + protected static DiscoveryIssue createIssue(Class annotationType, Method method, + String condition) { + String message = String.format("@%s method '%s' %s. It will not be executed.", annotationType.getSimpleName(), + method.toGenericString(), condition); + return DiscoveryIssue.builder(Severity.WARNING, message) // + .source(MethodSource.from(method)) // + .build(); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicates.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicates.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicates.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicates.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.discovery.predicates; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; +import static org.junit.platform.commons.support.ModifierSupport.isAbstract; +import static org.junit.platform.commons.support.ModifierSupport.isNotAbstract; +import static org.junit.platform.commons.support.ModifierSupport.isNotPrivate; +import static org.junit.platform.commons.util.KotlinReflectionUtils.isKotlinInterfaceDefaultImplsClass; +import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; +import static org.junit.platform.commons.util.ReflectionUtils.isMethodPresent; +import static org.junit.platform.commons.util.ReflectionUtils.isNestedClassPresent; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.ClassTemplate; +import org.junit.jupiter.api.Nested; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.util.ReflectionUtils.CycleErrorHandling; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.Condition; + +/** + * Predicates for determining whether a class is a JUnit Jupiter test class. + * + * @since 5.13 + */ +@API(status = INTERNAL, since = "5.13") +public class TestClassPredicates { + + public final Predicate> isAnnotatedWithNested = candidate -> isAnnotatedButNotComposed(candidate, + Nested.class); + public final Predicate> isAnnotatedWithClassTemplate = candidate -> isAnnotatedButNotComposed(candidate, + ClassTemplate.class); + + public final Predicate> isAnnotatedWithNestedAndValid = candidate -> this.isAnnotatedWithNested.test( + candidate) && isValidNestedTestClass(candidate); + public final Predicate> looksLikeNestedOrStandaloneTestClass = candidate -> this.isAnnotatedWithNested.test( + candidate) || looksLikeIntendedTestClass(candidate); + public final Predicate isTestOrTestFactoryOrTestTemplateMethod; + + private final Condition> isNotPrivateUnlessAbstractNestedClass; + private final Condition> isInnerNestedClass; + private final Condition> isValidStandaloneTestClass; + + public TestClassPredicates(DiscoveryIssueReporter issueReporter) { + this.isTestOrTestFactoryOrTestTemplateMethod = new IsTestMethod(issueReporter) // + .or(new IsTestFactoryMethod(issueReporter)) // + .or(new IsTestTemplateMethod(issueReporter)); + this.isNotPrivateUnlessAbstractNestedClass = isNotPrivateUnlessAbstract("@Nested", issueReporter); + this.isInnerNestedClass = isInner(issueReporter); + this.isValidStandaloneTestClass = isNotPrivateUnlessAbstract("Test", issueReporter) // + .and(isNotLocal(issueReporter)) // + .and(isNotInnerUnlessAbstract(issueReporter)) // + .and(isNotAnonymous(issueReporter)); + } + + public boolean looksLikeIntendedTestClass(Class candidate) { + return looksLikeIntendedTestClass(candidate, new HashSet<>()); + } + + private boolean looksLikeIntendedTestClass(Class candidate, Set> seen) { + if (seen.add(candidate) && !isKotlinInterfaceDefaultImplsClass(candidate)) { + return this.isAnnotatedWithClassTemplate.test(candidate) // + || hasTestOrTestFactoryOrTestTemplateMethods(candidate) // + || hasNestedTests(candidate, seen); + } + return false; + } + + public boolean isValidNestedTestClass(Class candidate) { + return validateNestedTestClass(candidate) == null; + } + + public NestedClassInvalidityReason validateNestedTestClass(Class candidate) { + boolean isInner = this.isInnerNestedClass.check(candidate); + boolean isNotPrivateUnlessAbstract = this.isNotPrivateUnlessAbstractNestedClass.check(candidate); + if (isNotPrivateUnlessAbstract && isNotAbstract(candidate)) { + return isInner ? null : NestedClassInvalidityReason.NOT_INNER; + } + return NestedClassInvalidityReason.OTHER; + } + + public boolean isValidStandaloneTestClass(Class candidate) { + return this.isValidStandaloneTestClass.check(candidate) // + && isNotAbstract(candidate); + } + + private boolean hasTestOrTestFactoryOrTestTemplateMethods(Class candidate) { + return isMethodPresent(candidate, this.isTestOrTestFactoryOrTestTemplateMethod); + } + + private boolean hasNestedTests(Class candidate, Set> seen) { + boolean hasAnnotatedClass = isNestedClassPresent(candidate, this.isAnnotatedWithNested, + CycleErrorHandling.THROW_EXCEPTION); + if (hasAnnotatedClass) { + return true; + } + return isNestedClassPresent( // + candidate, // + it -> isInnerClass(it) && looksLikeIntendedTestClass(it, seen), // + CycleErrorHandling.ABORT_VISIT // + ); + } + + private static Condition> isNotPrivateUnlessAbstract(String prefix, DiscoveryIssueReporter issueReporter) { + // Allow abstract test classes to be private because subclasses may widen access. + return issueReporter.createReportingCondition(testClass -> isNotPrivate(testClass) || isAbstract(testClass), + testClass -> createIssue(prefix, testClass, "must not be private")); + } + + private static Condition> isNotLocal(DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(testClass -> !testClass.isLocalClass(), + testClass -> createIssue("Test", testClass, "must not be a local class")); + } + + private static Condition> isInner(DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ReflectionUtils::isInnerClass, testClass -> { + if (testClass.getEnclosingClass() == null) { + return createIssue("Top-level", testClass, "must not be annotated with @Nested", + "It will be executed anyway for backward compatibility. " + + "You should remove the @Nested annotation to resolve this warning."); + } + return createIssue("@Nested", testClass, "must not be static", + "It will only be executed if discovered as a standalone test class. " + + "You should remove the annotation or make it non-static to resolve this warning."); + }); + } + + private static Condition> isNotInnerUnlessAbstract(DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(testClass -> !isInnerClass(testClass) || isAbstract(testClass), + testClass -> createIssue("Test", testClass, "must not be an inner class unless annotated with @Nested")); + } + + private static Condition> isNotAnonymous(DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(testClass -> !testClass.isAnonymousClass(), + testClass -> createIssue("Test", testClass, "must not be anonymous")); + } + + private static DiscoveryIssue createIssue(String prefix, Class testClass, String detailMessage) { + return createIssue(prefix, testClass, detailMessage, "It will not be executed."); + } + + private static DiscoveryIssue createIssue(String prefix, Class testClass, String detailMessage, String effect) { + String message = String.format("%s class '%s' %s. %s", prefix, testClass.getName(), detailMessage, effect); + return DiscoveryIssue.builder(DiscoveryIssue.Severity.WARNING, message) // + .source(ClassSource.from(testClass)) // + .build(); + } + + private static boolean isAnnotatedButNotComposed(Class candidate, Class annotationType) { + return !candidate.isAnnotation() && isAnnotated(candidate, annotationType); + } + + @API(status = INTERNAL, since = "5.13.3") + public enum NestedClassInvalidityReason { + NOT_INNER, OTHER + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/AfterEachMethodAdapter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/AfterEachMethodAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/AfterEachMethodAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/AfterEachMethodAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/BeforeEachMethodAdapter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/BeforeEachMethodAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/BeforeEachMethodAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/BeforeEachMethodAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluationException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluationException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluationException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluationException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluator.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluator.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConditionEvaluator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -72,7 +72,7 @@ private void logResult(Class conditionType, ConditionEvaluationResult result, ExtensionContext context) { logger.trace(() -> format("Evaluation of condition [%s] on [%s] resulted in: %s", conditionType.getName(), - context.getElement().get(), result)); + context.getElement().orElse(null), result)); } private ConditionEvaluationException evaluationException(Class conditionType, Exception ex) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConstructorInvocation.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConstructorInvocation.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConstructorInvocation.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ConstructorInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultExecutableInvoker.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultExecutableInvoker.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultExecutableInvoker.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultExecutableInvoker.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultParameterContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultParameterContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultParameterContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultParameterContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultTestInstances.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultTestInstances.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultTestInstances.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/DefaultTestInstances.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ExtensionContextSupplier.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.execution; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope.TEST_METHOD; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestInstantiationAwareExtension; +import org.junit.jupiter.engine.config.JupiterConfiguration; + +/** + * Container of two instances of {@link ExtensionContext} to simplify the legacy for + * #3445. + * + * @since 5.12 + * @see TestInstantiationAwareExtension + */ +@FunctionalInterface +@API(status = INTERNAL, since = "5.12") +public interface ExtensionContextSupplier { + + static ExtensionContextSupplier create(ExtensionContext currentExtensionContext, + ExtensionContext legacyExtensionContext, JupiterConfiguration configuration) { + if (currentExtensionContext == legacyExtensionContext + || configuration.getDefaultTestInstantiationExtensionContextScope() == TEST_METHOD) { + return __ -> currentExtensionContext; + } + return new ScopeBasedExtensionContextSupplier(currentExtensionContext, legacyExtensionContext); + } + + ExtensionContext get(TestInstantiationAwareExtension extension); + + class ScopeBasedExtensionContextSupplier implements ExtensionContextSupplier { + + private final ExtensionContext currentExtensionContext; + private final ExtensionContext legacyExtensionContext; + + private ScopeBasedExtensionContextSupplier(ExtensionContext currentExtensionContext, + ExtensionContext legacyExtensionContext) { + this.currentExtensionContext = currentExtensionContext; + this.legacyExtensionContext = legacyExtensionContext; + } + + public ExtensionContext get(TestInstantiationAwareExtension extension) { + return isTestScoped(extension) ? currentExtensionContext : legacyExtensionContext; + } + + private boolean isTestScoped(TestInstantiationAwareExtension extension) { + ExtensionContext rootContext = legacyExtensionContext.getRoot(); + return extension.getTestInstantiationExtensionContextScope(rootContext) == TEST_METHOD; + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvoker.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvoker.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvoker.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvoker.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -53,8 +53,9 @@ * invocation via all registered {@linkplain InvocationInterceptor * interceptors} */ - public T invoke(Constructor constructor, Optional outerInstance, ExtensionContext extensionContext, - ExtensionRegistry extensionRegistry, ReflectiveInterceptorCall, T> interceptorCall) { + public T invoke(Constructor constructor, Optional outerInstance, + ExtensionContextSupplier extensionContext, ExtensionRegistry extensionRegistry, + ReflectiveInterceptorCall, T> interceptorCall) { Object[] arguments = resolveParameters(constructor, Optional.empty(), outerInstance, extensionContext, extensionRegistry); @@ -93,6 +94,14 @@ wrappedInvocation) -> call.apply(interceptor, wrappedInvocation, invocationContext, extensionContext)); } + private T invoke(Invocation originalInvocation, + ReflectiveInvocationContext invocationContext, ExtensionContextSupplier extensionContext, + ExtensionRegistry extensionRegistry, ReflectiveInterceptorCall call) { + return interceptorChain.invoke(originalInvocation, extensionRegistry, + (interceptor, wrappedInvocation) -> call.apply(interceptor, wrappedInvocation, invocationContext, + extensionContext.get(interceptor))); + } + public interface ReflectiveInterceptorCall { T apply(InvocationInterceptor interceptor, Invocation invocation, diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InvocationInterceptorChain.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InvocationInterceptorChain.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InvocationInterceptorChain.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InvocationInterceptorChain.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -33,9 +33,9 @@ private boolean beforeAllCallbacksExecuted = false; private boolean beforeAllMethodsExecuted = false; - public JupiterEngineExecutionContext(EngineExecutionListener executionListener, - JupiterConfiguration configuration) { - this(new State(executionListener, configuration)); + public JupiterEngineExecutionContext(EngineExecutionListener executionListener, JupiterConfiguration configuration, + LauncherStoreFacade launcherStoreFacade) { + this(new State(executionListener, configuration, launcherStoreFacade)); } private JupiterEngineExecutionContext(State state) { @@ -62,6 +62,10 @@ return this.state.configuration; } + public LauncherStoreFacade getLauncherStoreFacade() { + return this.state.launcherStoreFacade; + } + public TestInstancesProvider getTestInstancesProvider() { return this.state.testInstancesProvider; } @@ -119,14 +123,17 @@ final EngineExecutionListener executionListener; final JupiterConfiguration configuration; + final LauncherStoreFacade launcherStoreFacade; TestInstancesProvider testInstancesProvider; MutableExtensionRegistry extensionRegistry; ExtensionContext extensionContext; ThrowableCollector throwableCollector; - State(EngineExecutionListener executionListener, JupiterConfiguration configuration) { + State(EngineExecutionListener executionListener, JupiterConfiguration configuration, + LauncherStoreFacade launcherStoreFacade) { this.executionListener = executionListener; this.configuration = configuration; + this.launcherStoreFacade = launcherStoreFacade; } @Override diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/LauncherStoreFacade.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/LauncherStoreFacade.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/LauncherStoreFacade.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/LauncherStoreFacade.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.execution; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; + +@API(status = INTERNAL, since = "5.14") +public class LauncherStoreFacade { + + private final NamespacedHierarchicalStore requestLevelStore; + private final NamespacedHierarchicalStore sessionLevelStore; + + public LauncherStoreFacade(NamespacedHierarchicalStore requestLevelStore) { + this.requestLevelStore = requestLevelStore; + this.sessionLevelStore = requestLevelStore.getParent().orElseThrow( + () -> new JUnitException("Request-level store must have a parent")); + } + + public NamespacedHierarchicalStore getRequestLevelStore() { + return this.requestLevelStore; + } + + public ExtensionContext.Store getRequestLevelStore(ExtensionContext.Namespace namespace) { + return getStoreAdapter(this.requestLevelStore, namespace); + } + + public ExtensionContext.Store getSessionLevelStore(ExtensionContext.Namespace namespace) { + return getStoreAdapter(this.sessionLevelStore, namespace); + } + + public NamespaceAwareStore getStoreAdapter(NamespacedHierarchicalStore valuesStore, + ExtensionContext.Namespace namespace) { + Preconditions.notNull(namespace, "Namespace must not be null"); + return new NamespaceAwareStore(valuesStore, convert(namespace)); + } + + private Namespace convert(ExtensionContext.Namespace namespace) { + return namespace.equals(ExtensionContext.Namespace.GLOBAL) // + ? Namespace.GLOBAL // + : Namespace.create(namespace.getParts()); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/MethodInvocation.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/MethodInvocation.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/MethodInvocation.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/MethodInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,7 +19,7 @@ import org.junit.jupiter.api.extension.InvocationInterceptor.Invocation; import org.junit.jupiter.api.extension.ReflectiveInvocationContext; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; class MethodInvocation implements Invocation, ReflectiveInvocationContext { @@ -57,7 +57,7 @@ @Override @SuppressWarnings("unchecked") public T proceed() { - return (T) ReflectionUtils.invokeMethod(this.method, this.target.orElse(null), this.arguments); + return (T) ReflectionSupport.invokeMethod(this.method, this.target.orElse(null), this.arguments); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/NamespaceAwareStore.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/NamespaceAwareStore.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/NamespaceAwareStore.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/NamespaceAwareStore.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,10 +16,10 @@ import java.util.function.Supplier; import org.apiguardian.api.API; -import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ExtensionContextException; import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.support.store.Namespace; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.engine.support.store.NamespacedHierarchicalStoreException; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ParameterResolutionUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ParameterResolutionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ParameterResolutionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ParameterResolutionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -83,6 +83,12 @@ */ public static Object[] resolveParameters(Executable executable, Optional target, Optional outerInstance, ExtensionContext extensionContext, ExtensionRegistry extensionRegistry) { + return resolveParameters(executable, target, outerInstance, __ -> extensionContext, extensionRegistry); + } + + public static Object[] resolveParameters(Executable executable, Optional target, + Optional outerInstance, ExtensionContextSupplier extensionContext, + ExtensionRegistry extensionRegistry) { Preconditions.notNull(target, "target must not be null"); @@ -106,12 +112,12 @@ } private static Object resolveParameter(ParameterContext parameterContext, Executable executable, - ExtensionContext extensionContext, ExtensionRegistry extensionRegistry) { + ExtensionContextSupplier extensionContext, ExtensionRegistry extensionRegistry) { try { // @formatter:off List matchingResolvers = extensionRegistry.stream(ParameterResolver.class) - .filter(resolver -> resolver.supportsParameter(parameterContext, extensionContext)) + .filter(resolver -> resolver.supportsParameter(parameterContext, extensionContext.get(resolver))) .collect(toList()); // @formatter:on @@ -133,12 +139,12 @@ } ParameterResolver resolver = matchingResolvers.get(0); - Object value = resolver.resolveParameter(parameterContext, extensionContext); + Object value = resolver.resolveParameter(parameterContext, extensionContext.get(resolver)); validateResolvedType(parameterContext.getParameter(), value, executable, resolver); logger.trace(() -> String.format( "ParameterResolver [%s] resolved a value of type [%s] for parameter [%s] in %s [%s].", - resolver.getClass().getName(), (value != null ? value.getClass().getName() : null), + resolver.getClass().getName(), (value != null ? value.getClass().getTypeName() : null), parameterContext.getParameter(), asLabel(executable), executable.toGenericString())); return value; @@ -179,8 +185,8 @@ message = String.format( "ParameterResolver [%s] resolved a value of type [%s] for parameter [%s] " + "in %s [%s], but a value assignment compatible with [%s] is required.", - resolver.getClass().getName(), (value != null ? value.getClass().getName() : null), parameter, - asLabel(executable), executable.toGenericString(), type.getName()); + resolver.getClass().getName(), (value != null ? value.getClass().getTypeName() : null), parameter, + asLabel(executable), executable.toGenericString(), type.getTypeName()); } throw new ParameterResolutionException(message); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/TestInstancesProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/TestInstancesProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/TestInstancesProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/TestInstancesProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,10 +14,7 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.extension.TestInstances; -import org.junit.jupiter.engine.extension.ExtensionRegistrar; import org.junit.jupiter.engine.extension.ExtensionRegistry; -import org.junit.jupiter.engine.extension.MutableExtensionRegistry; -import org.junit.platform.engine.support.hierarchical.ThrowableCollector; /** * @since 5.0 @@ -26,12 +23,10 @@ @API(status = INTERNAL, since = "5.0") public interface TestInstancesProvider { - default TestInstances getTestInstances(MutableExtensionRegistry extensionRegistry, - ThrowableCollector throwableCollector) { - return getTestInstances(extensionRegistry, extensionRegistry, throwableCollector); + default TestInstances getTestInstances(JupiterEngineExecutionContext context) { + return getTestInstances(context.getExtensionRegistry(), context); } - TestInstances getTestInstances(ExtensionRegistry extensionRegistry, ExtensionRegistrar extensionRegistrar, - ThrowableCollector throwableCollector); + TestInstances getTestInstances(ExtensionRegistry extensionRegistry, JupiterEngineExecutionContext executionContext); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/AutoCloseExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/AutoCloseExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/AutoCloseExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/AutoCloseExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.engine.extension; -import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; +import static org.junit.platform.commons.support.HierarchyTraversalMode.BOTTOM_UP; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -23,7 +23,9 @@ import org.junit.jupiter.api.extension.TestInstancePreDestroyCallback; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.AnnotationUtils; +import org.junit.platform.commons.support.AnnotationSupport; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; @@ -58,20 +60,20 @@ } private static void closeFields(Class testClass, Object testInstance, ThrowableCollector throwableCollector) { - Predicate predicate = (testInstance == null ? ReflectionUtils::isStatic : ReflectionUtils::isNotStatic); - AnnotationUtils.findAnnotatedFields(testClass, AutoClose.class, predicate, BOTTOM_UP).forEach( + Predicate predicate = (testInstance == null ? ModifierSupport::isStatic : ModifierSupport::isNotStatic); + AnnotationSupport.findAnnotatedFields(testClass, AutoClose.class, predicate, BOTTOM_UP).forEach( field -> throwableCollector.execute(() -> closeField(field, testInstance))); } private static void closeField(Field field, Object testInstance) throws Exception { - String methodName = AnnotationUtils.findAnnotation(field, AutoClose.class).get().value(); + String methodName = AnnotationSupport.findAnnotation(field, AutoClose.class).get().value(); Class fieldType = field.getType(); checkCondition(StringUtils.isNotBlank(methodName), "@AutoClose on field %s must specify a method name.", field); checkCondition(!fieldType.isPrimitive(), "@AutoClose is not supported on primitive field %s.", field); checkCondition(!fieldType.isArray(), "@AutoClose is not supported on array field %s.", field); - Object fieldValue = ReflectionUtils.tryToReadFieldValue(field, testInstance).get(); + Object fieldValue = ReflectionSupport.tryToReadFieldValue(field, testInstance).get(); if (fieldValue == null) { logger.warn(() -> String.format("Cannot @AutoClose field %s because it is null.", getQualifiedName(field))); } @@ -88,13 +90,13 @@ } Class targetType = target.getClass(); - Method closeMethod = ReflectionUtils.findMethod(targetType, methodName).orElseThrow( + Method closeMethod = ReflectionSupport.findMethod(targetType, methodName).orElseThrow( () -> new ExtensionConfigurationException( String.format("Cannot @AutoClose field %s because %s does not define method %s().", getQualifiedName(field), targetType.getName(), methodName))); closeMethod = ReflectionUtils.getInterfaceMethodIfPossible(closeMethod, targetType); - ReflectionUtils.invokeMethod(closeMethod, target); + ReflectionSupport.invokeMethod(closeMethod, target); } private static void checkCondition(boolean condition, String messageFormat, Field field) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultPreInterruptContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultPreInterruptContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultPreInterruptContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultPreInterruptContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import org.junit.jupiter.api.extension.PreInterruptContext; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ToStringBuilder; + +/** + * @since 5.12 + */ +class DefaultPreInterruptContext implements PreInterruptContext { + private final Thread threadToInterrupt; + + DefaultPreInterruptContext(Thread threadToInterrupt) { + Preconditions.notNull(threadToInterrupt, "threadToInterrupt must not be null"); + this.threadToInterrupt = threadToInterrupt; + } + + @Override + public Thread getThreadToInterrupt() { + return threadToInterrupt; + } + + @Override + public String toString() { + // @formatter:off + return new ToStringBuilder(this) + .append("threadToInterrupt", this.threadToInterrupt) + .toString(); + // @formatter:on + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultRepetitionInfo.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultRepetitionInfo.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultRepetitionInfo.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultRepetitionInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultTestReporter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultTestReporter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultTestReporter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DefaultTestReporter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import java.nio.file.Path; +import java.util.Map; + +import org.junit.jupiter.api.MediaType; +import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.function.ThrowingConsumer; + +/** + * @since 5.12 + */ +class DefaultTestReporter implements TestReporter { + + private final ExtensionContext extensionContext; + + DefaultTestReporter(ExtensionContext extensionContext) { + this.extensionContext = extensionContext; + } + + @Override + public void publishEntry(Map map) { + this.extensionContext.publishReportEntry(map); + } + + @Override + public void publishFile(String name, MediaType mediaType, ThrowingConsumer action) { + this.extensionContext.publishFile(name, mediaType, action); + } + + @Override + public void publishDirectory(String name, ThrowingConsumer action) { + this.extensionContext.publishDirectory(name, action); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DisabledCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DisabledCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DisabledCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DisabledCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.engine.extension; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.reflect.AnnotatedElement; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionContextInternal.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionContextInternal.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionContextInternal.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionContextInternal.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.List; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * {@code ExtensionContextInternal} extends the {@link ExtensionContext} with internal API. + * + * @since 5.12 + * @see ExtensionContext + */ +@API(status = INTERNAL, since = "5.12") +public interface ExtensionContextInternal extends ExtensionContext { + + /** + * Returns a list of registered extension at this context of the passed {@code extensionType}. + * + * @param the extension type + * @param extensionType the extension type + * @return the list of extensions + */ + List getExtensions(Class extensionType); +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistrar.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistrar.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistrar.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistrar.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistry.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistry.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/ExtensionRegistry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/MutableExtensionRegistry.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/MutableExtensionRegistry.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/MutableExtensionRegistry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/MutableExtensionRegistry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -28,6 +28,8 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.apiguardian.api.API; @@ -35,9 +37,10 @@ import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ClassLoaderUtils; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.util.ServiceLoaderUtils; /** * Default, mutable implementation of {@link ExtensionRegistry}. @@ -66,6 +69,11 @@ * auto-detected using Java's {@link ServiceLoader} mechanism and automatically * registered after the default extensions. * + *

If the + * {@value org.junit.jupiter.engine.Constants#EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME} + * configuration parameter has been set to {@code true}, the + * {@link PreInterruptThreadDumpPrinter} will be registered. + * * @param configuration configuration parameters used to retrieve the extension * auto-detection flag; never {@code null} * @return a new {@code ExtensionRegistry}; never {@code null} @@ -78,15 +86,47 @@ extensionRegistry.registerDefaultExtension(new TempDirectory(configuration)); if (configuration.isExtensionAutoDetectionEnabled()) { - registerAutoDetectedExtensions(extensionRegistry); + registerAutoDetectedExtensions(extensionRegistry, configuration); + } + + if (configuration.isThreadDumpOnTimeoutEnabled()) { + extensionRegistry.registerDefaultExtension(new PreInterruptThreadDumpPrinter()); } return extensionRegistry; } - private static void registerAutoDetectedExtensions(MutableExtensionRegistry extensionRegistry) { - ServiceLoader.load(Extension.class, ClassLoaderUtils.getDefaultClassLoader())// + private static void registerAutoDetectedExtensions(MutableExtensionRegistry extensionRegistry, + JupiterConfiguration configuration) { + + Predicate> filter = configuration.getFilterForAutoDetectedExtensions(); + List> excludedExtensions = new ArrayList<>(); + + ServiceLoader serviceLoader = ServiceLoader.load(Extension.class, + ClassLoaderUtils.getDefaultClassLoader()); + ServiceLoaderUtils.filter(serviceLoader, clazz -> { + boolean included = filter.test(clazz); + if (!included) { + excludedExtensions.add(clazz); + } + return included; + }) // .forEach(extensionRegistry::registerAutoDetectedExtension); + + logExcludedExtensions(excludedExtensions); + } + + private static void logExcludedExtensions(List> excludedExtensions) { + if (!excludedExtensions.isEmpty()) { + // @formatter:off + List excludeExtensionNames = excludedExtensions + .stream() + .map(Class::getName) + .collect(Collectors.toList()); + // @formatter:on + logger.config(() -> String.format( + "Excluded auto-detected extensions due to configured includes/excludes: %s", excludeExtensionNames)); + } } /** @@ -148,7 +188,7 @@ @Override public void registerExtension(Class extensionType) { if (!isAlreadyRegistered(extensionType)) { - registerLocalExtension(ReflectionUtils.newInstance(extensionType)); + registerLocalExtension(ReflectionSupport.newInstance(extensionType)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocation.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocation.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocation.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import java.util.function.Consumer; + +/** + * @since 5.12 + */ +@FunctionalInterface +interface PreInterruptCallbackInvocation { + PreInterruptCallbackInvocation NOOP = (t, e) -> { + }; + + void executePreInterruptCallback(Thread threadToInterrupt, Consumer errorHandler); +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocationFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocationFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocationFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptCallbackInvocationFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import java.util.List; + +import org.junit.jupiter.api.extension.PreInterruptCallback; +import org.junit.jupiter.api.extension.PreInterruptContext; +import org.junit.platform.commons.util.UnrecoverableExceptions; + +/** + * @since 5.12 + * @see PreInterruptCallbackInvocation + */ +final class PreInterruptCallbackInvocationFactory { + + private PreInterruptCallbackInvocationFactory() { + } + + static PreInterruptCallbackInvocation create(ExtensionContextInternal extensionContext) { + final List callbacks = extensionContext.getExtensions(PreInterruptCallback.class); + if (callbacks.isEmpty()) { + return PreInterruptCallbackInvocation.NOOP; + } + return (thread, errorHandler) -> { + PreInterruptContext preInterruptContext = new DefaultPreInterruptContext(thread); + for (PreInterruptCallback callback : callbacks) { + try { + callback.beforeThreadInterrupt(preInterruptContext, extensionContext); + } + catch (Throwable ex) { + UnrecoverableExceptions.rethrowIfUnrecoverable(ex); + errorHandler.accept(ex); + } + } + }; + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptThreadDumpPrinter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptThreadDumpPrinter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptThreadDumpPrinter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/PreInterruptThreadDumpPrinter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import java.util.Map; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.PreInterruptCallback; +import org.junit.jupiter.api.extension.PreInterruptContext; +import org.junit.jupiter.engine.Constants; + +/** + * The default implementation for {@link PreInterruptCallback}, + * which will print the stacks of all {@link Thread}s to {@code System.out}. + * + *

Note: This is disabled by default, and must be enabled with + * {@link Constants#EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME} + * + * @since 5.12 + */ +final class PreInterruptThreadDumpPrinter implements PreInterruptCallback { + private static final String NL = "\n"; + + @Override + public void beforeThreadInterrupt(PreInterruptContext preInterruptContext, ExtensionContext extensionContext) { + + Map stackTraces = Thread.getAllStackTraces(); + + StringBuilder sb = new StringBuilder(); + sb.append("Thread "); + appendThreadName(sb, preInterruptContext.getThreadToInterrupt()); + sb.append(" will be interrupted."); + sb.append(NL); + + for (Map.Entry entry : stackTraces.entrySet()) { + Thread thread = entry.getKey(); + StackTraceElement[] stack = entry.getValue(); + if (stack.length > 0) { + sb.append(NL); + appendThreadName(sb, thread); + for (StackTraceElement stackTraceElement : stack) { + sb.append(NL); + //Do the same prefix as java.lang.Throwable.printStackTrace(java.lang.Throwable.PrintStreamOrWriter) + sb.append("\tat "); + sb.append(stackTraceElement.toString()); + + } + sb.append(NL); + } + } + + System.out.println(sb); + } + + /** + * Appends the {@link Thread} name and ID in a similar fashion as {@code jstack}. + * @param sb the buffer + * @param th the thread to append + */ + private void appendThreadName(StringBuilder sb, Thread th) { + // Use same format as java.lang.management.ThreadInfo.toString + sb.append("\""); + sb.append(th.getName()); + sb.append("\""); + if (th.isDaemon()) { + sb.append(" daemon"); + } + sb.append(" prio="); + sb.append(th.getPriority()); + sb.append(" Id="); + sb.append(th.getId()); + sb.append(" "); + sb.append(th.getState()); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestDisplayNameFormatter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestDisplayNameFormatter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestDisplayNameFormatter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestDisplayNameFormatter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,8 @@ package org.junit.jupiter.engine.extension; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicInteger; @@ -21,7 +22,6 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; -import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.Preconditions; /** @@ -41,7 +41,7 @@ public Stream provideTestTemplateInvocationContexts(ExtensionContext context) { Method testMethod = context.getRequiredTestMethod(); String displayName = context.getDisplayName(); - RepeatedTest repeatedTest = AnnotationUtils.findAnnotation(testMethod, RepeatedTest.class).get(); + RepeatedTest repeatedTest = findAnnotation(testMethod, RepeatedTest.class).get(); int totalRepetitions = totalRepetitions(repeatedTest, testMethod); AtomicInteger failureCount = new AtomicInteger(); int failureThreshold = failureThreshold(repeatedTest, testMethod); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestInvocationContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepeatedTestInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepetitionExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepetitionExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepetitionExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepetitionExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -46,6 +46,11 @@ } @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { return (parameterContext.getParameter().getType() == RepetitionInfo.class); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocation.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocation.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocation.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,8 @@ package org.junit.jupiter.engine.extension; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.function.Supplier; @@ -26,18 +28,20 @@ private final TimeoutDuration timeout; private final ScheduledExecutorService executor; private final Supplier descriptionSupplier; + private final PreInterruptCallbackInvocation preInterruptCallback; SameThreadTimeoutInvocation(Invocation delegate, TimeoutDuration timeout, ScheduledExecutorService executor, - Supplier descriptionSupplier) { + Supplier descriptionSupplier, PreInterruptCallbackInvocation preInterruptCallback) { this.delegate = delegate; this.timeout = timeout; this.executor = executor; this.descriptionSupplier = descriptionSupplier; + this.preInterruptCallback = preInterruptCallback; } @Override public T proceed() throws Throwable { - InterruptTask interruptTask = new InterruptTask(Thread.currentThread()); + InterruptTask interruptTask = new InterruptTask(Thread.currentThread(), preInterruptCallback); ScheduledFuture future = executor.schedule(interruptTask, timeout.getValue(), timeout.getUnit()); Throwable failure = null; T result = null; @@ -56,6 +60,7 @@ if (interruptTask.executed) { Thread.interrupted(); failure = TimeoutExceptionFactory.create(descriptionSupplier.get(), timeout, failure); + interruptTask.attachSuppressedExceptions(failure); } } if (failure != null) { @@ -65,20 +70,28 @@ } static class InterruptTask implements Runnable { - + private final PreInterruptCallbackInvocation preInterruptCallback; + private final List exceptionsDuringInterruption = new CopyOnWriteArrayList<>(); private final Thread thread; private volatile boolean executed; - InterruptTask(Thread thread) { + InterruptTask(Thread thread, PreInterruptCallbackInvocation preInterruptCallback) { this.thread = thread; + this.preInterruptCallback = preInterruptCallback; } @Override public void run() { executed = true; + preInterruptCallback.executePreInterruptCallback(thread, exceptionsDuringInterruption::add); thread.interrupt(); } + void attachSuppressedExceptions(Throwable outerException) { + for (Throwable throwable : exceptionsDuringInterruption) { + outerException.addSuppressed(throwable); + } + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocation.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocation.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocation.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -25,19 +25,22 @@ private final Invocation delegate; private final TimeoutDuration timeout; private final Supplier descriptionSupplier; + private final PreInterruptCallbackInvocation preInterruptCallback; SeparateThreadTimeoutInvocation(Invocation delegate, TimeoutDuration timeout, - Supplier descriptionSupplier) { + Supplier descriptionSupplier, PreInterruptCallbackInvocation preInterruptCallback) { this.delegate = delegate; this.timeout = timeout; this.descriptionSupplier = descriptionSupplier; + this.preInterruptCallback = preInterruptCallback; } @Override public T proceed() throws Throwable { return assertTimeoutPreemptively(timeout.toDuration(), delegate::proceed, descriptionSupplier, - (__, messageSupplier, cause) -> { + (__, messageSupplier, cause, testThread) -> { TimeoutException exception = TimeoutExceptionFactory.create(messageSupplier.get(), timeout, null); + preInterruptCallback.executePreInterruptCallback(testThread, exception::addSuppressed); exception.initCause(cause); return exception; }); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,24 +11,29 @@ package org.junit.jupiter.engine.extension; import static java.nio.file.FileVisitResult.CONTINUE; +import static java.nio.file.FileVisitResult.SKIP_SUBTREE; import static java.util.stream.Collectors.joining; +import static org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope.TEST_METHOD; import static org.junit.jupiter.api.io.CleanupMode.DEFAULT; import static org.junit.jupiter.api.io.CleanupMode.NEVER; import static org.junit.jupiter.api.io.CleanupMode.ON_SUCCESS; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; -import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedFields; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible; +import static org.junit.platform.commons.util.ReflectionUtils.isRecordObject; import java.io.File; import java.io.IOException; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Parameter; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; @@ -48,9 +53,8 @@ import org.junit.jupiter.api.extension.ExtensionConfigurationException; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; -import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; +import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; @@ -61,38 +65,46 @@ import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.ToStringBuilder; /** * {@code TempDirectory} is a JUnit Jupiter extension that creates and cleans - * up temporary directories if field in a test class or a parameter in a - * lifecycle method or test method is annotated with {@code @TempDir}. + * up temporary directories if a field in a test class or a parameter in a + * test class constructor, lifecycle method, or test method is annotated with + * {@code @TempDir}. * *

Consult the Javadoc for {@link TempDir} for details on the contract. * * @since 5.4 - * @see TempDir + * @see TempDir @TempDir * @see Files#createTempDirectory */ class TempDirectory implements BeforeAllCallback, BeforeEachCallback, ParameterResolver { + // package-private for testing purposes static final Namespace NAMESPACE = Namespace.create(TempDirectory.class); + static final String FILE_OPERATIONS_KEY = "file.operations"; + private static final String KEY = "temp.dir"; private static final String FAILURE_TRACKER = "failure.tracker"; private static final String CHILD_FAILED = "child.failed"; - // for testing purposes - static final String FILE_OPERATIONS_KEY = "file.operations"; - private final JupiterConfiguration configuration; public TempDirectory(JupiterConfiguration configuration) { this.configuration = configuration; } + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } + /** * Perform field injection for non-private, {@code static} fields (i.e., * class fields) of type {@link Path} or {@link File} that are annotated with @@ -117,20 +129,23 @@ } private static void installFailureTracker(ExtensionContext context) { - context.getStore(NAMESPACE).put(FAILURE_TRACKER, (CloseableResource) () -> context.getParent() // - .ifPresent(it -> { - if (selfOrChildFailed(context)) { - it.getStore(NAMESPACE).put(CHILD_FAILED, true); - } - })); + context.getParent() // + .filter(parentContext -> !context.getRoot().equals(parentContext)) // + .ifPresent(parentContext -> installFailureTracker(context, parentContext)); + } + + private static void installFailureTracker(ExtensionContext context, ExtensionContext parentContext) { + context.getStore(NAMESPACE).put(FAILURE_TRACKER, new FailureTracker(context, parentContext)); } private void injectStaticFields(ExtensionContext context, Class testClass) { - injectFields(context, null, testClass, ReflectionUtils::isStatic); + injectFields(context, null, testClass, ModifierSupport::isStatic); } private void injectInstanceFields(ExtensionContext context, Object instance) { - injectFields(context, instance, instance.getClass(), ReflectionUtils::isNotStatic); + if (!isRecordObject(instance)) { + injectFields(context, instance, instance.getClass(), ModifierSupport::isNotStatic); + } } private void injectFields(ExtensionContext context, Object testInstance, Class testClass, @@ -160,12 +175,7 @@ */ @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - boolean annotated = parameterContext.isAnnotated(TempDir.class); - if (annotated && parameterContext.getDeclaringExecutable() instanceof Constructor) { - throw new ParameterResolutionException( - "@TempDir is not supported on constructor parameters. Please use field injection instead."); - } - return annotated; + return parameterContext.isAnnotated(TempDir.class); } /** @@ -233,24 +243,25 @@ return factory == TempDirFactory.class // ? this.configuration.getDefaultTempDirFactorySupplier().get() - : ReflectionUtils.newInstance(factory); + : ReflectionSupport.newInstance(factory); } - private void assertNonFinalField(Field field) { - if (ReflectionUtils.isFinal(field)) { + private static void assertNonFinalField(Field field) { + if (ModifierSupport.isFinal(field)) { throw new ExtensionConfigurationException("@TempDir field [" + field + "] must not be declared as final."); } } - private void assertSupportedType(String target, Class type) { + private static void assertSupportedType(String target, Class type) { if (type != Path.class && type != File.class) { throw new ExtensionConfigurationException("Can only resolve @TempDir " + target + " of type " + Path.class.getName() + " or " + File.class.getName() + " but was: " + type.getName()); } } - private Object getPathOrFile(Class elementType, AnnotatedElementContext elementContext, TempDirFactory factory, - CleanupMode cleanupMode, Scope scope, ExtensionContext extensionContext) { + private static Object getPathOrFile(Class elementType, AnnotatedElementContext elementContext, + TempDirFactory factory, CleanupMode cleanupMode, Scope scope, ExtensionContext extensionContext) { + Namespace namespace = scope == Scope.PER_DECLARATION // ? NAMESPACE.append(elementContext) // : NAMESPACE; @@ -265,6 +276,7 @@ static CloseablePath createTempDir(TempDirFactory factory, CleanupMode cleanupMode, Class elementType, AnnotatedElementContext elementContext, ExtensionContext extensionContext) { + try { return new CloseablePath(factory, cleanupMode, elementType, elementContext, extensionContext); } @@ -275,16 +287,22 @@ private static boolean selfOrChildFailed(ExtensionContext context) { return context.getExecutionException().isPresent() // - || context.getStore(NAMESPACE).getOrDefault(CHILD_FAILED, Boolean.class, false); + || getContextSpecificStore(context).getOrDefault(CHILD_FAILED, Boolean.class, false); + } + + private static ExtensionContext.Store getContextSpecificStore(ExtensionContext context) { + return context.getStore(NAMESPACE.append(context)); } - static class CloseablePath implements CloseableResource { + @SuppressWarnings("deprecation") + static class CloseablePath implements Store.CloseableResource, AutoCloseable { - private static final Logger logger = LoggerFactory.getLogger(CloseablePath.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CloseablePath.class); private final Path dir; private final TempDirFactory factory; private final CleanupMode cleanupMode; + private final AnnotatedElement annotatedElement; private final ExtensionContext extensionContext; private CloseablePath(TempDirFactory factory, CleanupMode cleanupMode, Class elementType, @@ -292,14 +310,15 @@ this.dir = factory.createTempDirectory(elementContext, extensionContext); this.factory = factory; this.cleanupMode = cleanupMode; + this.annotatedElement = elementContext.getAnnotatedElement(); this.extensionContext = extensionContext; - if (dir == null || !Files.isDirectory(dir)) { + if (this.dir == null || !Files.isDirectory(this.dir)) { close(); throw new PreconditionViolationException("temp directory must be a directory"); } - if (elementType == File.class && !dir.getFileSystem().equals(FileSystems.getDefault())) { + if (elementType == File.class && !this.dir.getFileSystem().equals(FileSystems.getDefault())) { close(); throw new PreconditionViolationException( "temp directory with non-default file system cannot be injected into " + File.class.getName() @@ -308,44 +327,95 @@ } Path get() { - return dir; + return this.dir; } @Override public void close() throws IOException { try { - if (cleanupMode == NEVER || (cleanupMode == ON_SUCCESS && selfOrChildFailed(extensionContext))) { - logger.info(() -> "Skipping cleanup of temp dir " + dir + " due to cleanup mode configuration."); + if (this.cleanupMode == NEVER + || (this.cleanupMode == ON_SUCCESS && selfOrChildFailed(this.extensionContext))) { + LOGGER.info(() -> String.format("Skipping cleanup of temp dir %s for %s due to CleanupMode.%s.", + this.dir, descriptionFor(this.annotatedElement), this.cleanupMode.name())); return; } - FileOperations fileOperations = extensionContext.getStore(NAMESPACE) // + FileOperations fileOperations = this.extensionContext.getStore(NAMESPACE) // .getOrDefault(FILE_OPERATIONS_KEY, FileOperations.class, FileOperations.DEFAULT); + FileOperations loggingFileOperations = file -> { + LOGGER.trace(() -> "Attempting to delete " + file); + try { + fileOperations.delete(file); + LOGGER.trace(() -> "Successfully deleted " + file); + } + catch (IOException e) { + LOGGER.trace(e, () -> "Failed to delete " + file); + throw e; + } + }; - SortedMap failures = deleteAllFilesAndDirectories(fileOperations); + LOGGER.trace(() -> "Cleaning up temp dir " + this.dir); + SortedMap failures = deleteAllFilesAndDirectories(loggingFileOperations); if (!failures.isEmpty()) { throw createIOExceptionWithAttachedFailures(failures); } } finally { - factory.close(); + this.factory.close(); } } + /** + * @since 5.12 + */ + private static String descriptionFor(AnnotatedElement annotatedElement) { + if (annotatedElement instanceof Field) { + Field field = (Field) annotatedElement; + return "field " + field.getDeclaringClass().getSimpleName() + "." + field.getName(); + } + if (annotatedElement instanceof Parameter) { + Parameter parameter = (Parameter) annotatedElement; + Executable executable = parameter.getDeclaringExecutable(); + return "parameter '" + parameter.getName() + "' in " + descriptionFor(executable); + } + throw new IllegalStateException("Unsupported AnnotatedElement type for @TempDir: " + annotatedElement); + } + + /** + * @since 5.12 + */ + private static String descriptionFor(Executable executable) { + boolean isConstructor = executable instanceof Constructor; + String type = isConstructor ? "constructor" : "method"; + String name = isConstructor ? executable.getDeclaringClass().getSimpleName() : executable.getName(); + return String.format("%s %s(%s)", type, name, + ClassUtils.nullSafeToString(Class::getSimpleName, executable.getParameterTypes())); + } + private SortedMap deleteAllFilesAndDirectories(FileOperations fileOperations) throws IOException { - if (dir == null || Files.notExists(dir)) { + + Path rootDir = this.dir; + if (rootDir == null || Files.notExists(rootDir)) { return Collections.emptySortedMap(); } SortedMap failures = new TreeMap<>(); Set retriedPaths = new HashSet<>(); - tryToResetPermissions(dir); - Files.walkFileTree(dir, new SimpleFileVisitor() { + Path rootRealPath = rootDir.toRealPath(); + + tryToResetPermissions(rootDir); + Files.walkFileTree(rootDir, new SimpleFileVisitor() { @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - if (!dir.equals(CloseablePath.this.dir)) { + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + LOGGER.trace(() -> "preVisitDirectory: " + dir); + if (isLinkWithTargetOutsideTempDir(dir)) { + warnAboutLinkWithTargetOutsideTempDir("link", dir); + delete(dir); + return SKIP_SUBTREE; + } + if (!dir.equals(rootDir)) { tryToResetPermissions(dir); } return CONTINUE; @@ -353,7 +423,8 @@ @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { - if (exc instanceof NoSuchFileException) { + LOGGER.trace(exc, () -> "visitFileFailed: " + file); + if (exc instanceof NoSuchFileException && !Files.exists(file, LinkOption.NOFOLLOW_LINKS)) { return CONTINUE; } // IOException includes `AccessDeniedException` thrown by non-readable or non-executable flags @@ -362,16 +433,44 @@ } @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) { - return deleteAndContinue(file); + public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException { + LOGGER.trace(() -> "visitFile: " + file); + if (Files.isSymbolicLink(file) && isLinkWithTargetOutsideTempDir(file)) { + warnAboutLinkWithTargetOutsideTempDir("symbolic link", file); + } + delete(file); + return CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { - return deleteAndContinue(dir); + LOGGER.trace(exc, () -> "postVisitDirectory: " + dir); + delete(dir); + return CONTINUE; + } + + private boolean isLinkWithTargetOutsideTempDir(Path path) { + // While `Files.walkFileTree` does not follow symbolic links, it may follow other links + // such as "junctions" on Windows + try { + return !path.toRealPath().startsWith(rootRealPath); + } + catch (IOException e) { + LOGGER.trace(e, + () -> "Failed to determine real path for " + path + "; assuming it is not a link"); + return false; + } + } + + private void warnAboutLinkWithTargetOutsideTempDir(String linkType, Path file) throws IOException { + Path realPath = file.toRealPath(); + LOGGER.warn(() -> String.format( + "Deleting %s from location inside of temp dir (%s) " + + "to location outside of temp dir (%s) but not the target file/directory", + linkType, file, realPath)); } - private FileVisitResult deleteAndContinue(Path path) { + private void delete(Path path) { try { fileOperations.delete(path); } @@ -385,7 +484,6 @@ // IOException includes `AccessDeniedException` thrown by non-readable or non-executable flags resetPermissionsAndTryToDeleteAgain(path, exception); } - return CONTINUE; } private void resetPermissionsAndTryToDeleteAgain(Path path, IOException exception) { @@ -446,7 +544,7 @@ .map(this::relativizeSafely) // .map(path -> emptyPath.equals(path) ? "" : path.toString()) // .collect(joining(", ")); - IOException exception = new IOException("Failed to delete temp directory " + dir.toAbsolutePath() + IOException exception = new IOException("Failed to delete temp directory " + this.dir.toAbsolutePath() + ". The following paths could not be deleted (see suppressed exceptions for details): " + joinedPaths); failures.values().forEach(exception::addSuppressed); @@ -464,7 +562,7 @@ private Path relativizeSafely(Path path) { try { - return dir.relativize(path); + return this.dir.relativize(path); } catch (IllegalArgumentException e) { return path; @@ -512,4 +610,23 @@ } + @SuppressWarnings("deprecation") + private static class FailureTracker implements Store.CloseableResource, AutoCloseable { + + private final ExtensionContext context; + private final ExtensionContext parentContext; + + private FailureTracker(ExtensionContext context, ExtensionContext parentContext) { + this.context = context; + this.parentContext = parentContext; + } + + @Override + public void close() { + if (selfOrChildFailed(context)) { + getContextSpecificStore(parentContext).put(CHILD_FAILED, true); + } + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestInfoParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestInfoParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestInfoParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestInfoParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -29,6 +29,11 @@ class TestInfoParameterResolver implements ParameterResolver { @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { return (parameterContext.getParameter().getType() == TestInfo.class); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestReporterParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestReporterParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestReporterParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestReporterParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -23,13 +23,18 @@ class TestReporterParameterResolver implements ParameterResolver { @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { return (parameterContext.getParameter().getType() == TestReporter.class); } @Override public TestReporter resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - return extensionContext::publishReportEntry; + return new DefaultTestReporter(extensionContext); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutConfiguration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutConfiguration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutConfiguration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutConfiguration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDuration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDuration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDuration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDuration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDurationParser.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDurationParser.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDurationParser.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutDurationParser.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -46,6 +46,11 @@ private static final String DISABLED_ON_DEBUG_MODE_VALUE = "disabled_on_debug"; @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override public void beforeAll(ExtensionContext context) { readAndStoreTimeoutSoChildrenInheritIt(context); } @@ -177,8 +182,8 @@ ThreadMode threadMode = resolveTimeoutThreadMode(extensionContext); return new TimeoutInvocationFactory(extensionContext.getRoot().getStore(NAMESPACE)).create(threadMode, - new TimeoutInvocationParameters<>(invocation, timeout, - () -> describe(invocationContext, extensionContext))); + new TimeoutInvocationParameters<>(invocation, timeout, () -> describe(invocationContext, extensionContext), + PreInterruptCallbackInvocationFactory.create((ExtensionContextInternal) extensionContext))); } private ThreadMode resolveTimeoutThreadMode(ExtensionContext extensionContext) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,7 +17,6 @@ import org.junit.jupiter.api.Timeout.ThreadMode; import org.junit.jupiter.api.extension.ExtensionContext.Store; -import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; import org.junit.jupiter.api.extension.InvocationInterceptor.Invocation; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.util.Preconditions; @@ -39,18 +38,21 @@ Preconditions.notNull(timeoutInvocationParameters, "timeout invocation parameters must not be null"); if (threadMode == ThreadMode.SEPARATE_THREAD) { return new SeparateThreadTimeoutInvocation<>(timeoutInvocationParameters.getInvocation(), - timeoutInvocationParameters.getTimeoutDuration(), timeoutInvocationParameters.getDescriptionSupplier()); + timeoutInvocationParameters.getTimeoutDuration(), timeoutInvocationParameters.getDescriptionSupplier(), + timeoutInvocationParameters.getPreInterruptCallback()); } return new SameThreadTimeoutInvocation<>(timeoutInvocationParameters.getInvocation(), timeoutInvocationParameters.getTimeoutDuration(), getThreadExecutorForSameThreadInvocation(), - timeoutInvocationParameters.getDescriptionSupplier()); + timeoutInvocationParameters.getDescriptionSupplier(), + timeoutInvocationParameters.getPreInterruptCallback()); } private ScheduledExecutorService getThreadExecutorForSameThreadInvocation() { return store.getOrComputeIfAbsent(SingleThreadExecutorResource.class).get(); } - private static abstract class ExecutorResource implements CloseableResource { + @SuppressWarnings({ "deprecation", "try" }) + private static abstract class ExecutorResource implements Store.CloseableResource, AutoCloseable { protected final ScheduledExecutorService executor; @@ -63,7 +65,7 @@ } @Override - public void close() throws Throwable { + public void close() throws Exception { executor.shutdown(); boolean terminated = executor.awaitTermination(5, TimeUnit.SECONDS); if (!terminated) { @@ -73,6 +75,7 @@ } } + @SuppressWarnings("try") static class SingleThreadExecutorResource extends ExecutorResource { @SuppressWarnings("unused") @@ -90,13 +93,16 @@ private final Invocation invocation; private final TimeoutDuration timeout; private final Supplier descriptionSupplier; + private final PreInterruptCallbackInvocation preInterruptCallback; TimeoutInvocationParameters(Invocation invocation, TimeoutDuration timeout, - Supplier descriptionSupplier) { + Supplier descriptionSupplier, PreInterruptCallbackInvocation preInterruptCallback) { this.invocation = Preconditions.notNull(invocation, "invocation must not be null"); this.timeout = Preconditions.notNull(timeout, "timeout must not be null"); this.descriptionSupplier = Preconditions.notNull(descriptionSupplier, "description supplier must not be null"); + this.preInterruptCallback = Preconditions.notNull(preInterruptCallback, + "preInterruptCallback must not be null"); } public Invocation getInvocation() { @@ -110,5 +116,9 @@ public Supplier getDescriptionSupplier() { return descriptionSupplier; } + + public PreInterruptCallbackInvocation getPreInterruptCallback() { + return preInterruptCallback; + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/JupiterThrowableCollectorFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/JupiterThrowableCollectorFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/JupiterThrowableCollectorFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/JupiterThrowableCollectorFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollector.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollector.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,7 +15,7 @@ import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.UnrecoverableExceptions; import org.junit.platform.engine.support.hierarchical.ThrowableCollector; import org.opentest4j.TestAbortedException; @@ -49,7 +49,7 @@ // Additionally support JUnit 4's AssumptionViolatedException? try { - Class clazz = ReflectionUtils.tryToLoadClass(ASSUMPTION_VIOLATED_EXCEPTION).get(); + Class clazz = ReflectionSupport.tryToLoadClass(ASSUMPTION_VIOLATED_EXCEPTION).get(); if (clazz != null) { return otaPredicate.or(clazz::isInstance); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,14 +8,15 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** - * Provides the JUnit Jupiter {@linkplain org.junit.platform.engine.TestEngine} + * Provides the JUnit Jupiter {@link org.junit.platform.engine.TestEngine} * implementation. * * @since 5.0 * @uses org.junit.jupiter.api.extension.Extension * @provides org.junit.platform.engine.TestEngine The {@code JupiterTestEngine} - * runs Jupiter based tests on the platform. + * runs Jupiter based tests on the platform. */ module org.junit.jupiter.engine { requires static org.apiguardian.api; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/testFixtures/java/org/junit/jupiter/engine/discovery/JupiterUniqueIdBuilder.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/testFixtures/java/org/junit/jupiter/engine/discovery/JupiterUniqueIdBuilder.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-engine/src/testFixtures/java/org/junit/jupiter/engine/discovery/JupiterUniqueIdBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-engine/src/testFixtures/java/org/junit/jupiter/engine/discovery/JupiterUniqueIdBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,9 @@ import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; +import org.junit.jupiter.api.ClassTemplate; +import org.junit.jupiter.engine.descriptor.ClassTemplateInvocationTestDescriptor; +import org.junit.jupiter.engine.descriptor.ClassTemplateTestDescriptor; import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; import org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor; @@ -19,6 +22,8 @@ import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; import org.junit.jupiter.engine.descriptor.TestTemplateInvocationTestDescriptor; import org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor; +import org.junit.platform.commons.support.AnnotationSupport; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.engine.UniqueId; /** @@ -31,16 +36,29 @@ public class JupiterUniqueIdBuilder { public static UniqueId uniqueIdForClass(Class clazz) { - UniqueId containerId = engineId(); if (isInnerClass(clazz)) { - containerId = uniqueIdForClass(clazz.getEnclosingClass()); - return containerId.append(NestedClassTestDescriptor.SEGMENT_TYPE, clazz.getSimpleName()); + var segmentType = classSegmentType(clazz, NestedClassTestDescriptor.SEGMENT_TYPE, + ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE); + return uniqueIdForClass(clazz.getEnclosingClass()).append(segmentType, clazz.getSimpleName()); } - return containerId.append(ClassTestDescriptor.SEGMENT_TYPE, clazz.getName()); + return uniqueIdForStaticClass(clazz.getName()); } - public static UniqueId uniqueIdForTopLevelClass(String className) { - return engineId().append(ClassTestDescriptor.SEGMENT_TYPE, className); + public static UniqueId uniqueIdForStaticClass(String className) { + return engineId().append(staticClassSegmentType(className), className); + } + + private static String staticClassSegmentType(String className) { + return ReflectionSupport.tryToLoadClass(className).toOptional() // + .map(it -> classSegmentType(it, ClassTestDescriptor.SEGMENT_TYPE, + ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE)) // + .orElse(ClassTestDescriptor.SEGMENT_TYPE); + } + + private static String classSegmentType(Class clazz, String regularSegmentType, String classTemplateSegmentType) { + return AnnotationSupport.isAnnotated(clazz, ClassTemplate.class) // + ? classTemplateSegmentType // + : regularSegmentType; } public static UniqueId uniqueIdForMethod(Class clazz, String methodPart) { @@ -59,6 +77,10 @@ return parentId.append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#" + index); } + public static UniqueId appendClassTemplateInvocationSegment(UniqueId parentId, int index) { + return parentId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#" + index); + } + public static UniqueId engineId() { return UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/EnableJUnit4MigrationSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/EnableJUnit4MigrationSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/EnableJUnit4MigrationSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/EnableJUnit4MigrationSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/conditions/IgnoreCondition.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/conditions/IgnoreCondition.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/conditions/IgnoreCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/conditions/IgnoreCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.jupiter.migrationsupport.conditions; import static org.apiguardian.api.API.Status.STABLE; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.reflect.AnnotatedElement; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/TestRuleSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/TestRuleSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/TestRuleSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/TestRuleSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,9 +11,10 @@ package org.junit.jupiter.migrationsupport.rules; import static java.util.Collections.unmodifiableList; -import static org.junit.platform.commons.util.AnnotationUtils.findPublicAnnotatedFields; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; +import static org.junit.platform.commons.support.AnnotationSupport.findPublicAnnotatedFields; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; +import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN; +import static org.junit.platform.commons.support.ReflectionSupport.findMethods; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -81,7 +82,7 @@ Predicate isRuleMethod = method -> isAnnotated(method, Rule.class); Predicate hasCorrectReturnType = method -> TestRule.class.isAssignableFrom(method.getReturnType()); - return findMethods(testInstance.getClass(), isRuleMethod.and(hasCorrectReturnType)); + return findMethods(testInstance.getClass(), isRuleMethod.and(hasCorrectReturnType), TOP_DOWN); } private List findAnnotatedFields(Object testInstance) { @@ -100,7 +101,7 @@ // If no appropriate @Rule annotated members were discovered, we then // have to rethrow the exception in order not to silently swallow it. - // Fixes bug: https://github.com/junit-team/junit5/issues/1069 + // Fixes bug: https://github.com/junit-team/junit-framework/issues/1069 if (numRuleAnnotatedMembers == 0) { throw throwable; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/VerifierSupport.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/VerifierSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/VerifierSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/VerifierSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/AbstractTestRuleAdapter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/AbstractTestRuleAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/AbstractTestRuleAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/AbstractTestRuleAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,8 +11,8 @@ package org.junit.jupiter.migrationsupport.rules.adapter; import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.ReflectionUtils.findMethod; -import static org.junit.platform.commons.util.ReflectionUtils.invokeMethod; +import static org.junit.platform.commons.support.ReflectionSupport.findMethod; +import static org.junit.platform.commons.support.ReflectionSupport.invokeMethod; import java.lang.reflect.Method; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExpectedExceptionAdapter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExpectedExceptionAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExpectedExceptionAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExpectedExceptionAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExternalResourceAdapter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExternalResourceAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExternalResourceAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/ExternalResourceAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/GenericBeforeAndAfterAdvice.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/GenericBeforeAndAfterAdvice.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/GenericBeforeAndAfterAdvice.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/GenericBeforeAndAfterAdvice.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/VerifierAdapter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/VerifierAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/VerifierAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/adapter/VerifierAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/AbstractTestRuleAnnotatedMember.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/AbstractTestRuleAnnotatedMember.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/AbstractTestRuleAnnotatedMember.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/AbstractTestRuleAnnotatedMember.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.jupiter.migrationsupport.rules.member; import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible; +import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible; import java.lang.reflect.Field; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMember.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMember.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMember.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMember.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMethod.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,7 +15,7 @@ import java.lang.reflect.Method; import org.apiguardian.api.API; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.rules.TestRule; /** @@ -25,7 +25,7 @@ public final class TestRuleAnnotatedMethod extends AbstractTestRuleAnnotatedMember { public TestRuleAnnotatedMethod(Object testInstance, Method method) { - super((TestRule) ReflectionUtils.invokeMethod(method, testInstance)); + super((TestRule) ReflectionSupport.invokeMethod(method, testInstance)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/module/org.junit.jupiter.migrationsupport/module-info.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/module/org.junit.jupiter.migrationsupport/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-migrationsupport/src/module/org.junit.jupiter.migrationsupport/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-migrationsupport/src/module/org.junit.jupiter.migrationsupport/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Support for migrating from JUnit 4 to JUnit Jupiter. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/junit-jupiter-params.gradle.kts jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/junit-jupiter-params.gradle.kts --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/junit-jupiter-params.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/junit-jupiter-params.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,7 +1,10 @@ +import junitbuild.extensions.javaModuleName + plugins { id("junitbuild.kotlin-library-conventions") id("junitbuild.shadow-conventions") id("junitbuild.jmh-conventions") + `java-test-fixtures` } description = "JUnit Jupiter Params" diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterBenchmarks.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterBenchmarks.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterBenchmarks.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterBenchmarks.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.junit.jupiter.params.ParameterizedInvocationConstants.DEFAULT_DISPLAY_NAME; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.DISPLAY_NAME_PLACEHOLDER; + +import java.util.List; +import java.util.stream.IntStream; + +import org.junit.jupiter.params.provider.Arguments; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@Fork(1) +@Warmup(iterations = 1, time = 2) +@Measurement(iterations = 3, time = 2) +public class ParameterizedInvocationNameFormatterBenchmarks { + + @Param({ "1", "2", "4", "10", "100", "1000" }) + private int numberOfParameters; + + List argumentsList; + + @Setup + public void setUp() { + argumentsList = IntStream.range(0, numberOfParameters) // + .mapToObj(i -> Arguments.argumentSet(String.valueOf(i), i)) // + .toList(); + } + + @Benchmark + public void formatTestNames(Blackhole blackhole) throws Exception { + var method = TestCase.class.getDeclaredMethod("parameterizedTest", int.class); + var formatter = new ParameterizedInvocationNameFormatter( + DISPLAY_NAME_PLACEHOLDER + " " + DEFAULT_DISPLAY_NAME + " ({0})", "displayName", + new ParameterizedTestContext(TestCase.class, method, method.getAnnotation(ParameterizedTest.class)), 512); + for (int i = 0; i < argumentsList.size(); i++) { + Arguments arguments = argumentsList.get(i); + blackhole.consume(formatter.format(i, EvaluatedArgumentSet.allOf(arguments))); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class TestCase { + @SuppressWarnings("unused") + @ParameterizedTest + void parameterizedTest(int param) { + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params; - -import java.util.List; -import java.util.stream.IntStream; - -import org.junit.jupiter.params.provider.Arguments; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Param; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; -import org.openjdk.jmh.infra.Blackhole; - -@State(Scope.Benchmark) -@Fork(1) -@Warmup(iterations = 1, time = 2) -@Measurement(iterations = 3, time = 2) -public class ParameterizedTestNameFormatterBenchmarks { - - @Param({ "1", "2", "4", "10", "100", "1000" }) - private int numberOfParameters; - - List argumentsList; - - @Setup - public void setUp() { - argumentsList = IntStream.range(0, numberOfParameters) // - .mapToObj(i -> Arguments.argumentSet(String.valueOf(i), i)) // - .toList(); - } - - @Benchmark - public void formatTestNames(Blackhole blackhole) throws Exception { - var formatter = new ParameterizedTestNameFormatter( - ParameterizedTest.DISPLAY_NAME_PLACEHOLDER + " " + ParameterizedTest.DEFAULT_DISPLAY_NAME + " ({0})", - "displayName", - new ParameterizedTestMethodContext(TestCase.class.getDeclaredMethod("parameterizedTest", int.class)), 512); - for (int i = 0; i < argumentsList.size(); i++) { - Arguments arguments = argumentsList.get(i); - blackhole.consume(formatter.format(i, arguments, arguments.get())); - } - } - - static class TestCase { - @SuppressWarnings("unused") - void parameterizedTest(int param) { - } - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AbstractParameterizedClassInvocationLifecycleMethodInvoker.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AbstractParameterizedClassInvocationLifecycleMethodInvoker.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AbstractParameterizedClassInvocationLifecycleMethodInvoker.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AbstractParameterizedClassInvocationLifecycleMethodInvoker.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import org.junit.jupiter.api.extension.ExecutableInvoker; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +/** + * @since 5.13 + */ +abstract class AbstractParameterizedClassInvocationLifecycleMethodInvoker implements ParameterResolver { + + private final ParameterizedClassContext declarationContext; + private final EvaluatedArgumentSet arguments; + private final int invocationIndex; + private final ResolutionCache resolutionCache; + private final ArgumentSetLifecycleMethod lifecycleMethod; + + AbstractParameterizedClassInvocationLifecycleMethodInvoker(ParameterizedClassContext declarationContext, + EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache, + ArgumentSetLifecycleMethod lifecycleMethod) { + this.declarationContext = declarationContext; + this.arguments = arguments; + this.invocationIndex = invocationIndex; + this.resolutionCache = resolutionCache; + this.lifecycleMethod = lifecycleMethod; + } + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return parameterContext.getDeclaringExecutable().equals(this.lifecycleMethod.method) // + && this.lifecycleMethod.parameterResolver.supports(parameterContext); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return this.lifecycleMethod.parameterResolver // + .resolve(parameterContext, extensionContext, this.arguments, this.invocationIndex, + this.resolutionCache); + } + + protected void invoke(ExtensionContext context) { + if (isCorrectTestClass(context)) { + ExecutableInvoker executableInvoker = context.getExecutableInvoker(); + Object testInstance = context.getTestInstance().orElse(null); + executableInvoker.invoke(this.lifecycleMethod.method, testInstance); + } + } + + private boolean isCorrectTestClass(ExtensionContext context) { + return this.declarationContext.getAnnotatedElement().equals(context.getTestClass().orElse(null)); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocation.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocation.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocation.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,170 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.ClassTemplateInvocationLifecycleMethod; +import org.junit.jupiter.params.aggregator.AggregateWith; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; + +/** + * {@code @AfterParameterizedClassInvocation} is used to signal that the + * annotated method should be executed before each + * invocation of the current {@link ParameterizedClass @ParameterizedClass}. + * + *

Declaring {@code @AfterParameterizedClassInvocation} methods in a regular, + * non-parameterized test class has no effect and will be ignored. + * + *

Method Signatures

+ * + *

{@code @AfterParameterizedClassInvocation} methods must have a + * {@code void} return type, must not be private, and must be {@code static} by + * default. Consequently, {@code @AfterParameterizedClassInvocation} methods are + * not supported in {@link org.junit.jupiter.api.Nested @Nested} test classes or + * as interface default methods unless the test class is annotated with + * {@link org.junit.jupiter.api.TestInstance @TestInstance(Lifecycle.PER_CLASS)}. + * However, beginning with Java 16 {@code @AfterParameterizedClassInvocation} + * methods may be declared as {@code static} in + * {@link org.junit.jupiter.api.Nested @Nested} test classes, in which case the + * {@code Lifecycle.PER_CLASS} restriction no longer applies. + * + *

Method Arguments

+ * + *

{@code @AfterParameterizedClassInvocation} methods may optionally declare + * parameters that are resolved depending on the setting of the + * {@link #injectArguments()} attribute. + * + *

If {@link #injectArguments()} is set to {@code false}, the parameters must + * be resolved by other registered + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers}. + * + *

If {@link #injectArguments()} is set to {@code true} (the default), the + * method must declare the same parameters, in the same order, as the + * indexed parameters (see + * {@link ParameterizedClass @ParameterizedClass}) of the parameterized test + * class. It may declare a subset of the indexed parameters starting from the + * first argument. Additionally, the method may declare custom aggregator + * parameters (see {@link ParameterizedClass @ParameterizedClass}) at the + * end of its parameter list. If the method declares additional parameters after + * these aggregator parameters, or more parameters than the class has indexed + * parameters, they may be resolved by other + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers}. + * + *

For example, given a {@link ParameterizedClass @ParameterizedClass} with + * indexed parameters of type {@code int} and {@code String}, the + * following method signatures are valid: + * + *

{@code
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation() { ... }
+ *
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation(int number) { ... }
+ *
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation(int number, String text) { ... }
+ *
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation(int number, String text, TestInfo testInfo) { ... }
+ *
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation(ArgumentsAccessor accessor) { ... }
+ *
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation(ArgumentsAccessor accessor, TestInfo testInfo) { ... }
+ *
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation(int number, String text, ArgumentsAccessor accessor) { ... }
+ *
+ * @AfterParameterizedClassInvocation
+ * void afterInvocation(int number, String text, ArgumentsAccessor accessor, TestInfo testInfo) { ... }
+ * }
+ * + *

In the snippet above,{@link ArgumentsAccessor} is used as an example of an + * aggregator parameter but the same applies to any parameter annotated with + * {@link AggregateWith @AggregateWith}. The parameter of type + * {@link org.junit.jupiter.api.TestInfo TestInfo} is used as an example of a + * parameter that is resolved by another + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolver}. + * + *

Inheritance and Execution Order

+ * + *

{@code @AfterParameterizedClassInvocation} methods are inherited from + * superclasses as long as they are not overridden according to the + * visibility rules of the Java language. Furthermore, + * {@code @AfterParameterizedClassInvocation} methods from superclasses will be + * executed before {@code @AfterParameterizedClassInvocation} methods in + * subclasses. + * + *

Similarly, {@code @AfterParameterizedClassInvocation} methods declared in + * an interface are inherited as long as they are not overridden, and + * {@code @AfterParameterizedClassInvocation} methods from an interface will be + * executed before {@code @AfterParameterizedClassInvocation} methods in the + * class that implements the interface. + * + *

JUnit Jupiter does not guarantee the execution order of multiple + * {@code @AfterParameterizedClassInvocation} methods that are declared within a + * single parameterized test class or test interface. While it may at times + * appear that these methods are invoked in alphabetical order, they are in fact + * sorted using an algorithm that is deterministic but intentionally + * non-obvious. + * + *

In addition, {@code @AfterParameterizedClassInvocation} methods are in no + * way linked to {@code @BeforeParameterizedClassInvocation} methods. + * Consequently, there are no guarantees with regard to their wrapping + * behavior. For example, given two {@code @AfterParameterizedClassInvocation} + * methods {@code createA()} and {@code createB()} as well as two + * {@code @BeforeParameterizedClassInvocation} methods {@code destroyA()} and + * {@code destroyB()}, the order in which the + * {@code @AfterParameterizedClassInvocation} methods are executed (e.g. + * {@code createA()} before {@code createB()}) does not imply any order for the + * seemingly corresponding {@code @BeforeParameterizedClassInvocation} methods. + * In other words, {@code destroyA()} might be called before or after + * {@code destroyB()}. The JUnit Team therefore recommends that developers + * declare at most one {@code @AfterParameterizedClassInvocation} method and at + * most one {@code @BeforeParameterizedClassInvocation} method per test class or + * test interface unless there are no dependencies between the + * {@code @AfterParameterizedClassInvocation} methods or between the + * {@code @BeforeParameterizedClassInvocation} methods. + * + *

Composition

+ * + *

{@code @AfterParameterizedClassInvocation} may be used as a + * meta-annotation in order to create a custom composed annotation that + * inherits the semantics of {@code @AfterParameterizedClassInvocation}. + * + * @since 5.13 + * @see ParameterizedClass + * @see BeforeParameterizedClassInvocation + * @see org.junit.jupiter.api.TestInstance + */ +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@API(status = MAINTAINED, since = "5.13.3") +@ClassTemplateInvocationLifecycleMethod(classTemplateAnnotation = ParameterizedClass.class, lifecycleMethodAnnotation = AfterParameterizedClassInvocation.class) +public @interface AfterParameterizedClassInvocation { + + /** + * Whether the arguments of the parameterized test class should be injected + * into the annotated method (defaults to {@code true}). + */ + boolean injectArguments() default true; + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocationMethodInvoker.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocationMethodInvoker.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocationMethodInvoker.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/AfterParameterizedClassInvocationMethodInvoker.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * @since 5.13 + */ +class AfterParameterizedClassInvocationMethodInvoker extends AbstractParameterizedClassInvocationLifecycleMethodInvoker + implements AfterClassTemplateInvocationCallback { + + AfterParameterizedClassInvocationMethodInvoker(ParameterizedClassContext declarationContext, + EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache, + ArgumentSetLifecycleMethod lifecycleMethod) { + super(declarationContext, arguments, invocationIndex, resolutionCache, lifecycleMethod); + } + + @Override + public void afterClassTemplateInvocation(ExtensionContext context) { + invoke(context); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidationMode.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidationMode.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidationMode.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidationMode.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; +import org.junit.jupiter.params.provider.ArgumentsSource; + +/** + * Enumeration of argument count validation modes for + * {@link ParameterizedClass @ParameterizedClass} and + * {@link ParameterizedTest @ParameterizedTest}. + * + *

When an {@link ArgumentsSource} provides more arguments than declared by + * the parameterized class or method, there might be a bug in the class/method + * or the {@link ArgumentsSource}. By default, the additional arguments are + * ignored. {@link ArgumentCountValidationMode} allows you to control how + * additional arguments are handled. + * + * @since 5.12 + * @see ParameterizedClass#argumentCountValidation() + * @see ParameterizedTest#argumentCountValidation() + */ +@API(status = MAINTAINED, since = "5.13.3") +public enum ArgumentCountValidationMode { + + /** + * Use the default validation mode. + * + *

The default validation mode may be changed via the + * {@value ArgumentCountValidator#ARGUMENT_COUNT_VALIDATION_KEY} + * configuration parameter (see the User Guide for details on configuration + * parameters). + */ + DEFAULT, + + /** + * Use the "none" argument count validation mode. + * + *

When there are more arguments provided than declared by the + * parameterized class or method, these additional arguments are ignored. + */ + NONE, + + /** + * Use the strict argument count validation mode. + * + *

When there are more arguments provided than declared by the + * parameterized class or method, this raises an error. + */ + STRICT, +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidator.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidator.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentCountValidator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,130 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.util.Arrays; +import java.util.Optional; + +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.params.ResolverFacade.RequiredParameterCount; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.util.Preconditions; + +class ArgumentCountValidator { + + private static final Logger logger = LoggerFactory.getLogger(ArgumentCountValidator.class); + + static final String ARGUMENT_COUNT_VALIDATION_KEY = "junit.jupiter.params.argumentCountValidation"; + private static final Namespace NAMESPACE = Namespace.create(ArgumentCountValidator.class); + + private final ParameterizedDeclarationContext declarationContext; + private final EvaluatedArgumentSet arguments; + + ArgumentCountValidator(ParameterizedDeclarationContext declarationContext, EvaluatedArgumentSet arguments) { + this.declarationContext = declarationContext; + this.arguments = arguments; + } + + void validate(ExtensionContext extensionContext) { + validateRequiredArgumentsArePresent(); + ArgumentCountValidationMode argumentCountValidationMode = getArgumentCountValidationMode(extensionContext); + switch (argumentCountValidationMode) { + case DEFAULT: + case NONE: + return; + case STRICT: + int consumedCount = this.declarationContext.getResolverFacade().determineConsumedArgumentCount( + this.arguments); + int totalCount = this.arguments.getTotalLength(); + Preconditions.condition(consumedCount == totalCount, + () -> wrongNumberOfArgumentsMessages("consumes", consumedCount, null, null)); + break; + default: + throw new ExtensionConfigurationException( + "Unsupported argument count validation mode: " + argumentCountValidationMode); + } + } + + private void validateRequiredArgumentsArePresent() { + RequiredParameterCount requiredParameterCount = this.declarationContext.getResolverFacade().getRequiredParameterCount(); + if (requiredParameterCount != null) { + int totalCount = this.arguments.getTotalLength(); + Preconditions.condition(requiredParameterCount.value() <= totalCount, + () -> wrongNumberOfArgumentsMessages("has", requiredParameterCount.value(), "required", + requiredParameterCount.reason())); + } + } + + private String wrongNumberOfArgumentsMessages(String verb, int actualCount, String parameterAdjective, + String reason) { + int totalCount = this.arguments.getTotalLength(); + return String.format( + "Configuration error: @%s %s %s %s%s%s but there %s %s %s provided.%nNote: the provided arguments were %s", + this.declarationContext.getAnnotationName(), verb, actualCount, + parameterAdjective == null ? "" : parameterAdjective + " ", + pluralize(actualCount, "parameter", "parameters"), + reason == null ? "" : String.format(" (due to %s)", reason), pluralize(totalCount, "was", "were"), + totalCount, pluralize(totalCount, "argument", "arguments"), + Arrays.toString(this.arguments.getAllPayloads())); + } + + private ArgumentCountValidationMode getArgumentCountValidationMode(ExtensionContext extensionContext) { + ArgumentCountValidationMode mode = declarationContext.getArgumentCountValidationMode(); + if (mode != ArgumentCountValidationMode.DEFAULT) { + return mode; + } + else { + return getArgumentCountValidationModeConfiguration(extensionContext); + } + } + + private ArgumentCountValidationMode getArgumentCountValidationModeConfiguration(ExtensionContext extensionContext) { + String key = ARGUMENT_COUNT_VALIDATION_KEY; + ArgumentCountValidationMode fallback = ArgumentCountValidationMode.NONE; + ExtensionContext.Store store = getStore(extensionContext); + return store.getOrComputeIfAbsent(key, __ -> { + Optional optionalConfigValue = extensionContext.getConfigurationParameter(key); + if (optionalConfigValue.isPresent()) { + String configValue = optionalConfigValue.get(); + Optional enumValue = Arrays.stream( + ArgumentCountValidationMode.values()).filter( + mode -> mode.name().equalsIgnoreCase(configValue)).findFirst(); + if (enumValue.isPresent()) { + logger.config(() -> String.format( + "Using ArgumentCountValidationMode '%s' set via the '%s' configuration parameter.", + enumValue.get().name(), key)); + return enumValue.get(); + } + else { + logger.warn(() -> String.format( + "Invalid ArgumentCountValidationMode '%s' set via the '%s' configuration parameter. " + + "Falling back to the %s default value.", + configValue, key, fallback.name())); + return fallback; + } + } + else { + return fallback; + } + }, ArgumentCountValidationMode.class); + } + + private static String pluralize(int count, String singular, String plural) { + return count == 1 ? singular : plural; + } + + private ExtensionContext.Store getStore(ExtensionContext context) { + return context.getRoot().getStore(NAMESPACE); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentSetLifecycleMethod.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentSetLifecycleMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentSetLifecycleMethod.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ArgumentSetLifecycleMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.lang.reflect.Method; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.util.Preconditions; + +/** + * @since 5.13 + */ +class ArgumentSetLifecycleMethod { + + final Method method; + final ParameterResolver parameterResolver; + + ArgumentSetLifecycleMethod(Method method) { + this(method, ParameterResolver.DISABLED); + } + + ArgumentSetLifecycleMethod(Method method, ParameterResolver parameterResolver) { + this.method = Preconditions.notNull(method, "method must not be null"); + this.parameterResolver = Preconditions.notNull(parameterResolver, "parameterResolver must not be null"); + } + + interface ParameterResolver { + + ParameterResolver DISABLED = new ParameterResolver() { + @Override + public boolean supports(ParameterContext parameterContext) { + return false; + } + + @Override + public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache) { + throw new JUnitException("Parameter resolution is disabled"); + } + }; + + boolean supports(ParameterContext parameterContext); + + Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache); + + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeClassTemplateInvocationFieldInjector.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeClassTemplateInvocationFieldInjector.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeClassTemplateInvocationFieldInjector.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeClassTemplateInvocationFieldInjector.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +class BeforeClassTemplateInvocationFieldInjector implements BeforeClassTemplateInvocationCallback { + + private final ResolverFacade resolverFacade; + private final EvaluatedArgumentSet arguments; + private final int invocationIndex; + private final ResolutionCache resolutionCache; + + BeforeClassTemplateInvocationFieldInjector(ResolverFacade resolverFacade, EvaluatedArgumentSet arguments, + int invocationIndex, ResolutionCache resolutionCache) { + this.resolverFacade = resolverFacade; + this.arguments = arguments; + this.invocationIndex = invocationIndex; + this.resolutionCache = resolutionCache; + } + + @Override + public void beforeClassTemplateInvocation(ExtensionContext extensionContext) { + extensionContext.getTestInstance() // + .ifPresent(testInstance -> this.resolverFacade // + .resolveAndInjectFields(testInstance, extensionContext, this.arguments, this.invocationIndex, + this.resolutionCache)); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocation.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocation.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocation.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,171 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.ClassTemplateInvocationLifecycleMethod; +import org.junit.jupiter.params.aggregator.AggregateWith; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; + +/** + * {@code @BeforeParameterizedClassInvocation} is used to signal that the + * annotated method should be executed before each + * invocation of the current {@link ParameterizedClass @ParameterizedClass}. + * + *

Declaring {@code @BeforeParameterizedClassInvocation} methods in a + * regular, non-parameterized test class has no effect and will be ignored. + * + *

Method Signatures

+ * + *

{@code @BeforeParameterizedClassInvocation} methods must have a + * {@code void} return type, must not be private, and must be {@code static} by + * default. Consequently, {@code @BeforeParameterizedClassInvocation} methods + * are not supported in {@link org.junit.jupiter.api.Nested @Nested} test + * classes or as interface default methods unless the test class is + * annotated with + * {@link org.junit.jupiter.api.TestInstance @TestInstance(Lifecycle.PER_CLASS)}. + * However, beginning with Java 16 {@code @BeforeParameterizedClassInvocation} + * methods may be declared as {@code static} in + * {@link org.junit.jupiter.api.Nested @Nested} test classes, in which case the + * {@code Lifecycle.PER_CLASS} restriction no longer applies. + * + *

Method Arguments

+ * + *

{@code @BeforeParameterizedClassInvocation} methods may optionally declare + * parameters that are resolved depending on the setting of the + * {@link #injectArguments()} attribute. + * + *

If {@link #injectArguments()} is set to {@code false}, the parameters must + * be resolved by other registered + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers}. + * + *

If {@link #injectArguments()} is set to {@code true} (the default), the + * method must declare the same parameters, in the same order, as the + * indexed parameters (see + * {@link ParameterizedClass @ParameterizedClass}) of the parameterized test + * class. It may declare a subset of the indexed parameters starting from the + * first argument. Additionally, the method may declare custom aggregator + * parameters (see {@link ParameterizedClass @ParameterizedClass}) at the + * end of its parameter list. If the method declares additional parameters after + * these aggregator parameters, or more parameters than the class has indexed + * parameters, they may be resolved by other + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers}. + * + *

For example, given a {@link ParameterizedClass @ParameterizedClass} with + * indexed parameters of type {@code int} and {@code String}, the + * following method signatures are valid: + * + *

{@code
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation() { ... }
+ *
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation(int number) { ... }
+ *
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation(int number, String text) { ... }
+ *
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation(int number, String text, TestInfo testInfo) { ... }
+ *
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation(ArgumentsAccessor accessor) { ... }
+ *
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation(ArgumentsAccessor accessor, TestInfo testInfo) { ... }
+ *
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation(int number, String text, ArgumentsAccessor accessor) { ... }
+ *
+ * @BeforeParameterizedClassInvocation
+ * void beforeInvocation(int number, String text, ArgumentsAccessor accessor, TestInfo testInfo) { ... }
+ * }
+ * + *

In the snippet above,{@link ArgumentsAccessor} is used as an example of an + * aggregator parameter but the same applies to any parameter annotated with + * {@link AggregateWith @AggregateWith}. The parameter of type + * {@link org.junit.jupiter.api.TestInfo TestInfo} is used as an example of a + * parameter that is resolved by another + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolver}. + * + *

Inheritance and Execution Order

+ * + *

{@code @BeforeParameterizedClassInvocation} methods are inherited from + * superclasses as long as they are not overridden according to the + * visibility rules of the Java language. Furthermore, + * {@code @BeforeParameterizedClassInvocation} methods from superclasses will be + * executed before {@code @BeforeParameterizedClassInvocation} methods in + * subclasses. + * + *

Similarly, {@code @BeforeParameterizedClassInvocation} methods declared in + * an interface are inherited as long as they are not overridden, and + * {@code @BeforeParameterizedClassInvocation} methods from an interface will be + * executed before {@code @BeforeParameterizedClassInvocation} methods in the + * class that implements the interface. + * + *

JUnit Jupiter does not guarantee the execution order of multiple + * {@code @BeforeParameterizedClassInvocation} methods that are declared within + * a single parameterized test class or test interface. While it may at times + * appear that these methods are invoked in alphabetical order, they are in fact + * sorted using an algorithm that is deterministic but intentionally + * non-obvious. + * + *

In addition, {@code @BeforeParameterizedClassInvocation} methods are in no + * way linked to {@code @AfterParameterizedClassInvocation} methods. + * Consequently, there are no guarantees with regard to their wrapping + * behavior. For example, given two {@code @BeforeParameterizedClassInvocation} + * methods {@code createA()} and {@code createB()} as well as two + * {@code @AfterParameterizedClassInvocation} methods {@code destroyA()} and + * {@code destroyB()}, the order in which the + * {@code @BeforeParameterizedClassInvocation} methods are executed (e.g. + * {@code createA()} before {@code createB()}) does not imply any order for the + * seemingly corresponding {@code @AfterParameterizedClassInvocation} methods. + * In other words, {@code destroyA()} might be called before or after + * {@code destroyB()}. The JUnit Team therefore recommends that developers + * declare at most one {@code @BeforeParameterizedClassInvocation} method and at + * most one {@code @AfterParameterizedClassInvocation} method per test class or + * test interface unless there are no dependencies between the + * {@code @BeforeParameterizedClassInvocation} methods or between the + * {@code @AfterParameterizedClassInvocation} methods. + * + *

Composition

+ * + *

{@code @BeforeParameterizedClassInvocation} may be used as a + * meta-annotation in order to create a custom composed annotation that + * inherits the semantics of {@code @BeforeParameterizedClassInvocation}. + * + * @since 5.13 + * @see ParameterizedClass + * @see AfterParameterizedClassInvocation + * @see org.junit.jupiter.api.TestInstance + */ +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@API(status = MAINTAINED, since = "5.13.3") +@ClassTemplateInvocationLifecycleMethod(classTemplateAnnotation = ParameterizedClass.class, lifecycleMethodAnnotation = BeforeParameterizedClassInvocation.class) +public @interface BeforeParameterizedClassInvocation { + + /** + * Whether the arguments of the parameterized test class should be injected + * into the annotated method (defaults to {@code true}). + */ + boolean injectArguments() default true; + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocationMethodInvoker.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocationMethodInvoker.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocationMethodInvoker.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/BeforeParameterizedClassInvocationMethodInvoker.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * @since 5.13 + */ +class BeforeParameterizedClassInvocationMethodInvoker extends AbstractParameterizedClassInvocationLifecycleMethodInvoker + implements BeforeClassTemplateInvocationCallback { + + BeforeParameterizedClassInvocationMethodInvoker(ParameterizedClassContext declarationContext, + EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache, + ArgumentSetLifecycleMethod lifecycleMethod) { + super(declarationContext, arguments, invocationIndex, resolutionCache, lifecycleMethod); + } + + @Override + public void beforeClassTemplateInvocation(ExtensionContext context) { + invoke(context); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ClassTemplateConstructorParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ClassTemplateConstructorParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ClassTemplateConstructorParameterResolver.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ClassTemplateConstructorParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; + +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * @since 5.13 + */ +class ClassTemplateConstructorParameterResolver extends ParameterizedInvocationParameterResolver { + + private final Class classTemplateClass; + + ClassTemplateConstructorParameterResolver(ParameterizedClassContext classContext, EvaluatedArgumentSet arguments, + int invocationIndex, ResolutionCache resolutionCache) { + super(classContext.getResolverFacade(), arguments, invocationIndex, resolutionCache); + this.classTemplateClass = classContext.getAnnotatedElement(); + } + + @Override + protected boolean isSupportedOnConstructorOrMethod(Executable declaringExecutable, + ExtensionContext extensionContext) { + return declaringExecutable instanceof Constructor // + && this.classTemplateClass.equals(declaringExecutable.getDeclaringClass()); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/DefaultParameterInfo.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/DefaultParameterInfo.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/DefaultParameterInfo.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/DefaultParameterInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.support.ParameterDeclarations; + +/** + * @since 5.13 + */ +@SuppressWarnings("deprecation") +class DefaultParameterInfo implements org.junit.jupiter.params.support.ParameterInfo { + + private final ParameterDeclarations declarations; + private final ArgumentsAccessor arguments; + + DefaultParameterInfo(ParameterDeclarations declarations, ArgumentsAccessor arguments) { + this.declarations = declarations; + this.arguments = arguments; + } + + @Override + public ParameterDeclarations getDeclarations() { + return this.declarations; + } + + @Override + public ArgumentsAccessor getArguments() { + return this.arguments; + } + + void store(ExtensionContext context) { + context.getStore(org.junit.jupiter.params.ParameterInfo.NAMESPACE) // + .put(org.junit.jupiter.params.ParameterInfo.KEY, this); + context.getStore(org.junit.jupiter.params.support.ParameterInfo.NAMESPACE) // + .put(org.junit.jupiter.params.support.ParameterInfo.KEY, this); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/EvaluatedArgumentSet.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/EvaluatedArgumentSet.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/EvaluatedArgumentSet.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/EvaluatedArgumentSet.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.util.Arrays; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.IntUnaryOperator; + +import org.junit.jupiter.api.Named; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.Arguments.ArgumentSet; +import org.junit.platform.commons.util.Preconditions; + +/** + * Encapsulates the evaluation of an {@link Arguments} instance (so it happens + * only once) and access to the resulting argument values. + * + *

The provided accessor methods are focused on the different use cases and + * make it less error-prone to access the argument values. + * + * @since 5.13 + */ +class EvaluatedArgumentSet { + + static EvaluatedArgumentSet allOf(Arguments arguments) { + Object[] all = arguments.get(); + return create(all, all, arguments); + } + + static EvaluatedArgumentSet of(Arguments arguments, IntUnaryOperator consumedLengthComputer) { + Object[] all = arguments.get(); + Object[] consumed = dropSurplus(all, consumedLengthComputer.applyAsInt(all.length)); + return create(all, consumed, arguments); + } + + private static EvaluatedArgumentSet create(Object[] all, Object[] consumed, Arguments arguments) { + return new EvaluatedArgumentSet(all, consumed, determineName(arguments)); + } + + private final Object[] all; + private final Object[] consumed; + private final Optional name; + + private EvaluatedArgumentSet(Object[] all, Object[] consumed, Optional name) { + this.all = all; + this.consumed = consumed; + this.name = name; + } + + int getTotalLength() { + return this.all.length; + } + + Object[] getAllPayloads() { + return extractFromNamed(this.all, Named::getPayload); + } + + int getConsumedLength() { + return this.consumed.length; + } + + Object[] getConsumedNames() { + return extractFromNamed(this.consumed, Named::getName); + } + + Object[] getConsumedPayloads() { + return extractFromNamed(this.consumed, Named::getPayload); + } + + Object getConsumedPayload(int index) { + return extractFromNamed(this.consumed[index], Named::getPayload); + } + + Optional getName() { + return this.name; + } + + private static Object[] dropSurplus(Object[] arguments, int newLength) { + Preconditions.condition(newLength <= arguments.length, + () -> String.format("New length %d must be less than or equal to the total length %d", newLength, + arguments.length)); + return arguments.length > newLength ? Arrays.copyOf(arguments, newLength) : arguments; + } + + private static Optional determineName(Arguments arguments) { + if (arguments instanceof ArgumentSet) { + return Optional.of(((ArgumentSet) arguments).getName()); + } + return Optional.empty(); + } + + private static Object[] extractFromNamed(Object[] arguments, Function, Object> mapper) { + return Arrays.stream(arguments) // + .map(argument -> extractFromNamed(argument, mapper)) // + .toArray(); + } + + private static Object extractFromNamed(Object argument, Function, Object> mapper) { + return argument instanceof Named ? mapper.apply((Named) argument) : argument; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/InstancePostProcessingClassTemplateFieldInjector.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/InstancePostProcessingClassTemplateFieldInjector.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/InstancePostProcessingClassTemplateFieldInjector.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/InstancePostProcessingClassTemplateFieldInjector.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; + +class InstancePostProcessingClassTemplateFieldInjector implements TestInstancePostProcessor { + + private final ResolverFacade resolverFacade; + private final EvaluatedArgumentSet arguments; + private final int invocationIndex; + private final ResolutionCache resolutionCache; + + InstancePostProcessingClassTemplateFieldInjector(ResolverFacade resolverFacade, EvaluatedArgumentSet arguments, + int invocationIndex, ResolutionCache resolutionCache) { + this.resolverFacade = resolverFacade; + this.arguments = arguments; + this.invocationIndex = invocationIndex; + this.resolutionCache = resolutionCache; + } + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext extensionContext) { + this.resolverFacade.resolveAndInjectFields(testInstance, extensionContext, this.arguments, this.invocationIndex, + this.resolutionCache); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/Parameter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/Parameter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/Parameter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/Parameter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,65 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; +import org.junit.jupiter.params.aggregator.AggregateWith; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; + +/** + * {@code @Parameter} is used to signal that a field in a + * {@code @ParameterizedClass} constitutes a parameter and marks it for + * field injection. + * + *

{@code @Parameter} may also be used as a meta-annotation in order to + * create a custom composed annotation that inherits the semantics of + * {@code @Parameter}. + * + * @since 5.13 + * @see ParameterizedClass + * @see ArgumentsAccessor + * @see AggregateWith + * @see org.junit.jupiter.params.converter.ArgumentConverter + * @see org.junit.jupiter.params.converter.ConvertWith + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD }) +@Documented +@API(status = MAINTAINED, since = "5.13.3") +public @interface Parameter { + + /** + * Constant that indicates that the index of the parameter is unset. + */ + int UNSET_INDEX = -1; + + /** + * {@return the index of the parameter in the list of parameters} + * + *

Must be {@value #UNSET_INDEX} (the default) for aggregators, + * that is any field of type {@link ArgumentsAccessor} or any field + * annotated with {@link AggregateWith @AggregateWith}. + * + *

May be omitted if there's a single indexed parameter. + * Otherwise, must be unique among all indexed parameters of the + * parameterized class and its superclasses. + */ + int value() default UNSET_INDEX; + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterInfo.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterInfo.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterInfo.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.support.ParameterDeclarations; + +/** + * {@code ParameterInfo} is used to provide information about the current + * invocation of a parameterized class or test. + * + *

Registered {@link Extension} implementations may retrieve the current + * {@code ParameterInfo} instance by calling + * {@link ExtensionContext#getStore(Namespace)} with {@link #NAMESPACE} and + * {@link ExtensionContext.Store#get(Object, Class) Store.get(...)} with + * {@link #KEY}. Alternatively, the {@link #get(ExtensionContext)} method may + * be used to retrieve the {@code ParameterInfo} instance for the supplied + * {@code ExtensionContext}. Extensions must not modify any entries in the + * {@link ExtensionContext.Store Store} for {@link #NAMESPACE}. + * + *

When a {@link ParameterizedTest @ParameterizedTest} method is declared + * inside a {@link ParameterizedClass @ParameterizedClass} or a + * {@link Nested @Nested} {@link ParameterizedClass @ParameterizedClass} is + * declared inside an enclosing {@link ParameterizedClass @ParameterizedClass}, + * there will be multiple {@code ParameterInfo} instances available on different + * levels of the {@link ExtensionContext} hierarchy. In such cases, please use + * {@link ExtensionContext#getParent()} to navigate to the right level before + * retrieving the {@code ParameterInfo} instance from the + * {@link ExtensionContext.Store Store}. + * + * @since 5.14 + * @see ParameterizedClass + * @see ParameterizedTest + */ +@API(status = EXPERIMENTAL, since = "5.14") +public interface ParameterInfo { + + /** + * The {@link Namespace} for accessing the + * {@link ExtensionContext.Store Store} for {@code ParameterInfo}. + */ + Namespace NAMESPACE = Namespace.create(ParameterInfo.class); + + /** + * The key for retrieving the {@code ParameterInfo} instance from the + * {@link ExtensionContext.Store Store}. + */ + Object KEY = ParameterInfo.class; + + /** + * {@return the closest {@code ParameterInfo} instance for the supplied + * {@code ExtensionContext}; potentially {@code null}} + */ + static ParameterInfo get(ExtensionContext context) { + return context.getStore(NAMESPACE).get(KEY, ParameterInfo.class); + } + + /** + * {@return the declarations of all indexed parameters} + */ + ParameterDeclarations getDeclarations(); + + /** + * {@return the accessor to the arguments of the current invocation} + */ + ArgumentsAccessor getArguments(); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClass.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClass.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClass.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,252 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.ClassTemplate; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.provider.ArgumentsSource; + +/** + * {@code @ParameterizedClass} is used to signal that the annotated class is + * a parameterized test class. + * + *

Arguments Providers and Sources

+ * + *

A {@code @ParameterizedClass} must specify at least one + * {@link org.junit.jupiter.params.provider.ArgumentsProvider ArgumentsProvider} + * via {@link org.junit.jupiter.params.provider.ArgumentsSource @ArgumentsSource} + * or a corresponding composed annotation (e.g., {@code @ValueSource}, + * {@code @CsvSource}, etc.). The provider is responsible for providing a + * {@link java.util.stream.Stream Stream} of + * {@link org.junit.jupiter.params.provider.Arguments Arguments} that will be + * used to invoke the parameterized class. + * + *

Field or Constructor Injection

+ * + *

The provided arguments can either be injected into fields annotated with + * {@link Parameter @Parameter} or passed to the unique constructor of the + * parameterized class. If a {@code @Parameter}-annotated field is declared in + * the parameterized class or one of its superclasses, field injection will be + * used. Otherwise, constructor injection will be used. + * + *

Constructor Injection

+ * + *

A {@code @ParameterizedClass} constructor may declare additional + * parameters at the end of its parameter list to be resolved by other + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers} + * (e.g., {@code TestInfo}, {@code TestReporter}, etc.). Specifically, such a + * constructor must declare formal parameters according to the following rules. + * + *

    + *
  1. Zero or more indexed parameters must be declared first.
  2. + *
  3. Zero or more aggregators must be declared next.
  4. + *
  5. Zero or more parameters supplied by other {@code ParameterResolver} + * implementations must be declared last.
  6. + *
+ * + *

In this context, an indexed parameter is an argument for a given + * index in the {@code Arguments} provided by an {@code ArgumentsProvider} that + * is passed as an argument to the parameterized class at the same index in + * the constructor's formal parameter list. An aggregator is any + * parameter of type + * {@link org.junit.jupiter.params.aggregator.ArgumentsAccessor ArgumentsAccessor} + * or any parameter annotated with + * {@link org.junit.jupiter.params.aggregator.AggregateWith @AggregateWith}. + * + *

Field injection

+ * + *

Fields annotated with {@code @Parameter} must be declared according to the + * following rules. + * + *

    + *
  1. Zero or more indexed parameters may be declared; each must have + * a unique index specified in its {@code @Parameter(index)} annotation. The + * index may be omitted if there is only one indexed parameter. If there are at + * least two indexed parameter declarations, there must be declarations for all + * indexes from 0 to the largest declared index.
  2. + *
  3. Zero or more aggregators may be declared; each without + * specifying an index in its {@code @Parameter} annotation.
  4. + *
  5. Zero or more other fields may be declared as usual as long as they're not + * annotated with {@code @Parameter}.
  6. + *
+ * + *

In this context, an indexed parameter is an argument for a given + * index in the {@code Arguments} provided by an {@code ArgumentsProvider} that + * is injected into a field annotated with {@code @Parameter(index)}. An + * aggregator is any {@code @Parameter}-annotated field of type + * {@link org.junit.jupiter.params.aggregator.ArgumentsAccessor ArgumentsAccessor} + * or any field annotated with + * {@link org.junit.jupiter.params.aggregator.AggregateWith @AggregateWith}. + * + *

Argument Conversion

+ * + *

{@code @Parameter}-annotated fields or constructor parameters may be + * annotated with + * {@link org.junit.jupiter.params.converter.ConvertWith @ConvertWith} + * or a corresponding composed annotation to specify an explicit + * {@link org.junit.jupiter.params.converter.ArgumentConverter ArgumentConverter}. + * Otherwise, JUnit Jupiter will attempt to perform an implicit + * conversion to the target type automatically (see the User Guide for further + * details). + * + *

Lifecycle Methods

+ * + *

If you wish to execute custom code before or after each invocation of the + * parameterized class, you may declare methods annotated with + * {@link BeforeParameterizedClassInvocation @BeforeParameterizedClassInvocation} + * or + * {@link AfterParameterizedClassInvocation @AfterParameterizedClassInvocation}. + * This can, for example, be useful to initialize the arguments before they are + * used. + * + *

Composed Annotations

+ * + *

{@code @ParameterizedClass} may also be used as a meta-annotation in + * order to create a custom composed annotation that inherits the + * semantics of {@code @ParameterizedClass}. + * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * + * @since 5.13 + * @see Parameter + * @see BeforeParameterizedClassInvocation + * @see AfterParameterizedClassInvocation + * @see ParameterizedTest + * @see org.junit.jupiter.params.provider.Arguments + * @see org.junit.jupiter.params.provider.ArgumentsProvider + * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.provider.CsvFileSource + * @see org.junit.jupiter.params.provider.CsvSource + * @see org.junit.jupiter.params.provider.EnumSource + * @see org.junit.jupiter.params.provider.MethodSource + * @see org.junit.jupiter.params.provider.ValueSource + * @see org.junit.jupiter.params.aggregator.ArgumentsAccessor + * @see org.junit.jupiter.params.aggregator.AggregateWith + * @see org.junit.jupiter.params.converter.ArgumentConverter + * @see org.junit.jupiter.params.converter.ConvertWith + */ +@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@API(status = MAINTAINED, since = "5.13.3") +@ClassTemplate +@ExtendWith(ParameterizedClassExtension.class) +@SuppressWarnings("exports") +public @interface ParameterizedClass { + + /** + * The display name to be used for individual invocations of the + * parameterized class; never blank or consisting solely of whitespace. + * + *

Defaults to + * {@value ParameterizedInvocationNameFormatter#DEFAULT_DISPLAY_NAME}. + * + *

If the default display name flag + * ({@value ParameterizedInvocationNameFormatter#DEFAULT_DISPLAY_NAME}) + * is not overridden, JUnit will: + *

    + *
  • Look up the {@value ParameterizedInvocationNameFormatter#DISPLAY_NAME_PATTERN_KEY} + * configuration parameter and use it if available. The configuration + * parameter can be supplied via the {@code Launcher} API, build tools (e.g., + * Gradle and Maven), a JVM system property, or the JUnit Platform configuration + * file (i.e., a file named {@code junit-platform.properties} in the root of + * the class path). Consult the User Guide for further information.
  • + *
  • Otherwise, + * {@value ParameterizedInvocationConstants#DEFAULT_DISPLAY_NAME} + * will be used.
  • + *
+ * + *

Supported placeholders

+ *
    + *
  • {@value ParameterizedInvocationConstants#DISPLAY_NAME_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#INDEX_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENT_SET_NAME_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENTS_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENTS_WITH_NAMES_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER}
  • + *
  • "{0}", "{1}", etc.: an individual argument (0-based)
  • + *
+ * + *

For the latter, you may use {@link java.text.MessageFormat} patterns + * to customize formatting (for example, {@code {0,number,#.###}}). Please + * note that the original arguments are passed when formatting, regardless + * of any implicit or explicit argument conversions. + * + *

Note that + * {@value ParameterizedInvocationNameFormatter#DEFAULT_DISPLAY_NAME} is + * a flag rather than a placeholder. + * + * @see java.text.MessageFormat + */ + String name() default ParameterizedInvocationNameFormatter.DEFAULT_DISPLAY_NAME; + + /** + * Configure whether all arguments of the parameterized class that implement + * {@link AutoCloseable} will be closed after their corresponding + * invocation. + * + *

Defaults to {@code true}. + * + *

WARNING: if an argument that implements + * {@code AutoCloseable} is reused for multiple invocations of the same + * parameterized class, you must set {@code autoCloseArguments} to + * {@code false} to ensure that the argument is not closed between + * invocations. + * + * @see java.lang.AutoCloseable + */ + boolean autoCloseArguments() default true; + + /** + * Configure whether zero invocations are allowed for this + * parameterized class. + * + *

Set this attribute to {@code true} if the absence of invocations is + * expected in some cases and should not cause a test failure. + * + *

Defaults to {@code false}. + */ + boolean allowZeroInvocations() default false; + + /** + * Configure how the number of arguments provided by an + * {@link ArgumentsSource} are validated. + * + *

Defaults to {@link ArgumentCountValidationMode#DEFAULT}. + * + *

When an {@link ArgumentsSource} provides more arguments than declared + * by the parameterized class constructor or {@link Parameter}-annotated + * fields, there might be a bug in the parameterized class or the + * {@link ArgumentsSource}. By default, the additional arguments are + * ignored. {@code argumentCountValidation} allows you to control how + * additional arguments are handled. The default can be configured via the + * {@value ArgumentCountValidator#ARGUMENT_COUNT_VALIDATION_KEY} + * configuration parameter (see the User Guide for details on configuration + * parameters). + * + * @see ArgumentCountValidationMode + */ + ArgumentCountValidationMode argumentCountValidation() default ArgumentCountValidationMode.DEFAULT; + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static java.util.Collections.emptyList; +import static java.util.Collections.reverse; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedMethods; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; +import static org.junit.platform.commons.support.HierarchyTraversalMode.BOTTOM_UP; +import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN; +import static org.junit.platform.commons.support.ReflectionSupport.findFields; +import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; +import static org.junit.platform.commons.util.ReflectionUtils.isRecordClass; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.util.ReflectionUtils; + +class ParameterizedClassContext implements ParameterizedDeclarationContext { + + private final Class testClass; + private final ParameterizedClass annotation; + private final TestInstance.Lifecycle testInstanceLifecycle; + private final ResolverFacade resolverFacade; + private final InjectionType injectionType; + private final List beforeMethods; + private final List afterMethods; + + ParameterizedClassContext(Class testClass, ParameterizedClass annotation, + TestInstance.Lifecycle testInstanceLifecycle) { + this.testClass = testClass; + this.annotation = annotation; + this.testInstanceLifecycle = testInstanceLifecycle; + + List fields = findParameterAnnotatedFields(testClass); + if (fields.isEmpty()) { + this.resolverFacade = ResolverFacade.create(ReflectionUtils.getDeclaredConstructor(testClass), annotation); + this.injectionType = InjectionType.CONSTRUCTOR; + } + else { + this.resolverFacade = ResolverFacade.create(testClass, fields); + this.injectionType = InjectionType.FIELDS; + } + + this.beforeMethods = findLifecycleMethodsAndAssertStaticAndNonPrivate(testClass, testInstanceLifecycle, + TOP_DOWN, BeforeParameterizedClassInvocation.class, BeforeParameterizedClassInvocation::injectArguments, + this.resolverFacade); + + // Make a local copy since findAnnotatedMethods() returns an immutable list. + this.afterMethods = new ArrayList<>(findLifecycleMethodsAndAssertStaticAndNonPrivate(testClass, + testInstanceLifecycle, BOTTOM_UP, AfterParameterizedClassInvocation.class, + AfterParameterizedClassInvocation::injectArguments, this.resolverFacade)); + + // Since the bottom-up ordering of afterMethods will later be reversed when the + // AfterParameterizedClassInvocationMethodInvoker extensions are executed within + // ClassTemplateInvocationTestDescriptor, we have to reverse them to put them + // in top-down order before we register them as extensions. + reverse(afterMethods); + } + + private static List findParameterAnnotatedFields(Class clazz) { + if (isRecordClass(clazz)) { + return emptyList(); + } + return findFields(clazz, it -> isAnnotated(it, Parameter.class), BOTTOM_UP); + } + + @Override + public Class getTestClass() { + return this.testClass; + } + + @Override + public ParameterizedClass getAnnotation() { + return this.annotation; + } + + @Override + public Class getAnnotatedElement() { + return this.testClass; + } + + @Override + public String getDisplayNamePattern() { + return this.annotation.name(); + } + + @Override + public boolean isAutoClosingArguments() { + return this.annotation.autoCloseArguments(); + } + + @Override + public boolean isAllowingZeroInvocations() { + return this.annotation.allowZeroInvocations(); + } + + @Override + public ArgumentCountValidationMode getArgumentCountValidationMode() { + return this.annotation.argumentCountValidation(); + } + + @Override + public ResolverFacade getResolverFacade() { + return this.resolverFacade; + } + + @Override + public ClassTemplateInvocationContext createInvocationContext(ParameterizedInvocationNameFormatter formatter, + Arguments arguments, int invocationIndex) { + + return new ParameterizedClassInvocationContext(this, formatter, arguments, invocationIndex); + } + + TestInstance.Lifecycle getTestInstanceLifecycle() { + return testInstanceLifecycle; + } + + InjectionType getInjectionType() { + return injectionType; + } + + List getBeforeMethods() { + return beforeMethods; + } + + List getAfterMethods() { + return afterMethods; + } + + private static List findLifecycleMethodsAndAssertStaticAndNonPrivate( + Class testClass, TestInstance.Lifecycle testInstanceLifecycle, HierarchyTraversalMode traversalMode, + Class annotationType, Predicate injectArgumentsPredicate, ResolverFacade resolverFacade) { + + List methods = findAnnotatedMethods(testClass, annotationType, traversalMode); + + return methods.stream() // + .filter(ModifierSupport::isNotPrivate) // + .filter(testInstanceLifecycle == PER_METHOD ? ModifierSupport::isStatic : __ -> true) // + .filter(ReflectionUtils::returnsPrimitiveVoid) // + .map(method -> { + A annotation = getAnnotation(method, annotationType); + if (injectArgumentsPredicate.test(annotation)) { + return new ArgumentSetLifecycleMethod(method, + resolverFacade.createLifecycleMethodParameterResolver(method, annotation)); + } + return new ArgumentSetLifecycleMethod(method); + }) // + .collect(toUnmodifiableList()); + } + + private static A getAnnotation(Method method, Class annotationType) { + return findAnnotation(method, annotationType) // + .orElseThrow(() -> new JUnitException("Method not annotated with @" + annotationType.getSimpleName())); + } + + enum InjectionType { + CONSTRUCTOR, FIELDS + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassExtension.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,135 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.junit.jupiter.params.ParameterizedClassContext.InjectionType.CONSTRUCTOR; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.util.Optional; +import java.util.stream.Stream; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContextProvider; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.PreconditionViolationException; + +/** + * @since 5.13 + */ +class ParameterizedClassExtension extends ParameterizedInvocationContextProvider + implements ClassTemplateInvocationContextProvider, ParameterResolver { + + private static final String DECLARATION_CONTEXT_KEY = "context"; + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + + // This method always returns `false` because it is not intended to be used as a parameter resolver. + // Instead, it is used to provide a better error message when `TestInstance.Lifecycle.PER_CLASS` is + // attempted to be combined with constructor injection of parameters. + + if (isDeclaredOnTestClassConstructor(parameterContext, extensionContext)) { + validateAndStoreClassContext(extensionContext); + } + + return false; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + + // Should never be called (see comment above). + + throw new JUnitException("Unexpected call to resolveParameter"); + } + + @Override + public boolean supportsClassTemplate(ExtensionContext extensionContext) { + return validateAndStoreClassContext(extensionContext); + } + + @Override + public Stream provideClassTemplateInvocationContexts( + ExtensionContext extensionContext) { + + return provideInvocationContexts(extensionContext, getDeclarationContext(extensionContext)); + } + + @Override + public boolean mayReturnZeroClassTemplateInvocationContexts(ExtensionContext extensionContext) { + return getDeclarationContext(extensionContext).isAllowingZeroInvocations(); + } + + private static boolean isDeclaredOnTestClassConstructor(ParameterContext parameterContext, + ExtensionContext extensionContext) { + + Executable declaringExecutable = parameterContext.getDeclaringExecutable(); + return declaringExecutable instanceof Constructor // + && declaringExecutable.getDeclaringClass().equals(extensionContext.getTestClass().orElse(null)); + } + + private boolean validateAndStoreClassContext(ExtensionContext extensionContext) { + + Store store = getStore(extensionContext); + if (store.get(DECLARATION_CONTEXT_KEY) != null) { + return true; + } + + Optional annotation = findAnnotation(extensionContext.getTestClass(), + ParameterizedClass.class); + if (!annotation.isPresent()) { + return false; + } + + store.put(DECLARATION_CONTEXT_KEY, + createClassContext(extensionContext, extensionContext.getRequiredTestClass(), annotation.get())); + + return true; + } + + private static ParameterizedClassContext createClassContext(ExtensionContext extensionContext, Class testClass, + ParameterizedClass annotation) { + + TestInstance.Lifecycle lifecycle = extensionContext.getTestInstanceLifecycle() // + .orElseThrow(() -> new PreconditionViolationException("TestInstance.Lifecycle not present")); + + ParameterizedClassContext classContext = new ParameterizedClassContext(testClass, annotation, lifecycle); + + if (lifecycle == PER_CLASS && classContext.getInjectionType() == CONSTRUCTOR) { + throw new PreconditionViolationException( + "Constructor injection is not supported for @ParameterizedClass classes with @TestInstance(Lifecycle.PER_CLASS)"); + } + + return classContext; + } + + private ParameterizedClassContext getDeclarationContext(ExtensionContext extensionContext) { + return getStore(extensionContext)// + .get(DECLARATION_CONTEXT_KEY, ParameterizedClassContext.class); + } + + private Store getStore(ExtensionContext context) { + return context.getStore(Namespace.create(ParameterizedClassExtension.class, context.getRequiredTestClass())); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassInvocationContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static java.util.stream.Collectors.toList; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD; + +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedClassContext.InjectionType; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.util.Preconditions; + +class ParameterizedClassInvocationContext extends ParameterizedInvocationContext + implements ClassTemplateInvocationContext { + + private final ResolutionCache resolutionCache = ResolutionCache.enabled(); + + ParameterizedClassInvocationContext(ParameterizedClassContext classContext, + ParameterizedInvocationNameFormatter formatter, Arguments arguments, int invocationIndex) { + super(classContext, formatter, arguments, invocationIndex); + } + + @Override + public String getDisplayName(int invocationIndex) { + return super.getDisplayName(invocationIndex); + } + + @Override + public List getAdditionalExtensions() { + return Stream.concat(Stream.of(createParameterInjector()), createLifecycleMethodInvokers()) // + .collect(toList()); + } + + @Override + public void prepareInvocation(ExtensionContext context) { + super.prepareInvocation(context); + } + + private Extension createParameterInjector() { + InjectionType injectionType = this.declarationContext.getInjectionType(); + switch (injectionType) { + case CONSTRUCTOR: + return createExtensionForConstructorInjection(); + case FIELDS: + return createExtensionForFieldInjection(); + } + throw new JUnitException("Unsupported injection type: " + injectionType); + } + + private ClassTemplateConstructorParameterResolver createExtensionForConstructorInjection() { + Preconditions.condition(this.declarationContext.getTestInstanceLifecycle() == PER_METHOD, + "Constructor injection is only supported for lifecycle PER_METHOD"); + return new ClassTemplateConstructorParameterResolver(this.declarationContext, this.arguments, + this.invocationIndex, this.resolutionCache); + } + + private Extension createExtensionForFieldInjection() { + ResolverFacade resolverFacade = this.declarationContext.getResolverFacade(); + TestInstance.Lifecycle lifecycle = this.declarationContext.getTestInstanceLifecycle(); + switch (lifecycle) { + case PER_CLASS: + return new BeforeClassTemplateInvocationFieldInjector(resolverFacade, this.arguments, + this.invocationIndex, this.resolutionCache); + case PER_METHOD: + return new InstancePostProcessingClassTemplateFieldInjector(resolverFacade, this.arguments, + this.invocationIndex, this.resolutionCache); + } + throw new JUnitException("Unsupported lifecycle: " + lifecycle); + } + + private Stream createLifecycleMethodInvokers() { + return Stream.concat( // + this.declarationContext.getBeforeMethods().stream().map( + this::createBeforeParameterizedClassInvocationMethodInvoker), // + this.declarationContext.getAfterMethods().stream().map( + this::createAfterParameterizedClassInvocationMethodInvoker) // + ); + } + + private BeforeParameterizedClassInvocationMethodInvoker createBeforeParameterizedClassInvocationMethodInvoker( + ArgumentSetLifecycleMethod method) { + return new BeforeParameterizedClassInvocationMethodInvoker(this.declarationContext, this.arguments, + this.invocationIndex, this.resolutionCache, method); + } + + private AfterParameterizedClassInvocationMethodInvoker createAfterParameterizedClassInvocationMethodInvoker( + ArgumentSetLifecycleMethod method) { + return new AfterParameterizedClassInvocationMethodInvoker(this.declarationContext, this.arguments, + this.invocationIndex, this.resolutionCache, method); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedDeclarationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedDeclarationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedDeclarationContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedDeclarationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.junit.jupiter.params.provider.Arguments; + +/** + * @since 5.13 + */ +interface ParameterizedDeclarationContext { + + Class getTestClass(); + + Annotation getAnnotation(); + + AnnotatedElement getAnnotatedElement(); + + String getDisplayNamePattern(); + + boolean isAutoClosingArguments(); + + boolean isAllowingZeroInvocations(); + + ArgumentCountValidationMode getArgumentCountValidationMode(); + + default String getAnnotationName() { + return getAnnotation().annotationType().getSimpleName(); + } + + ResolverFacade getResolverFacade(); + + C createInvocationContext(ParameterizedInvocationNameFormatter formatter, Arguments arguments, int invocationIndex); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationConstants.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationConstants.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationConstants.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationConstants.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,130 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; + +/** + * Constants for the use with the + * {@link ParameterizedClass @ParameterizedClass} and + * {@link ParameterizedTest @ParameterizedTest} annotations. + * + * @since 5.13 + */ +@API(status = MAINTAINED, since = "5.13") +public class ParameterizedInvocationConstants { + + /** + * Placeholder for the {@linkplain org.junit.jupiter.api.TestInfo#getDisplayName + * display name} of a {@code @ParameterizedTest} method: {displayName} + * + * @since 5.3 + * @see ParameterizedClass#name() + * @see ParameterizedTest#name() + */ + public static final String DISPLAY_NAME_PLACEHOLDER = "{displayName}"; + + /** + * Placeholder for the current invocation index of a {@code @ParameterizedTest} + * method (1-based): {index} + * + * @since 5.3 + * @see ParameterizedClass#name() + * @see ParameterizedTest#name() + * @see #DEFAULT_DISPLAY_NAME + */ + public static final String INDEX_PLACEHOLDER = "{index}"; + + /** + * Placeholder for the complete, comma-separated arguments list of the + * current invocation of a {@code @ParameterizedTest} method: + * {arguments} + * + * @since 5.3 + * @see ParameterizedClass#name() + * @see ParameterizedTest#name() + */ + public static final String ARGUMENTS_PLACEHOLDER = "{arguments}"; + + /** + * Placeholder for the complete, comma-separated named arguments list + * of the current invocation of a {@code @ParameterizedTest} method: + * {argumentsWithNames} + * + *

Argument names will be retrieved via the {@link java.lang.reflect.Parameter#getName()} + * API if the byte code contains parameter names — for example, if + * the code was compiled with the {@code -parameters} command line argument + * for {@code javac}. + * + * @since 5.6 + * @see ParameterizedClass#name() + * @see ParameterizedTest#name() + * @see #ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + */ + public static final String ARGUMENTS_WITH_NAMES_PLACEHOLDER = "{argumentsWithNames}"; + + /** + * Placeholder for the name of the argument set for the current invocation + * of a {@code @ParameterizedTest} method: {argumentSetName}. + * + *

This placeholder can be used when the current set of arguments was created via + * {@link org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) + * argumentSet()}. + * + * @since 5.11 + * @see ParameterizedClass#name() + * @see ParameterizedTest#name() + * @see #ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @see org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String ARGUMENT_SET_NAME_PLACEHOLDER = "{argumentSetName}"; + + /** + * Placeholder for either {@link #ARGUMENT_SET_NAME_PLACEHOLDER} or + * {@link #ARGUMENTS_WITH_NAMES_PLACEHOLDER}, depending on whether the + * current set of arguments was created via + * {@link org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) + * argumentSet()}: {argumentSetNameOrArgumentsWithNames}. + * + * @since 5.11 + * @see ParameterizedClass#name() + * @see ParameterizedTest#name() + * @see #ARGUMENT_SET_NAME_PLACEHOLDER + * @see #ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @see #DEFAULT_DISPLAY_NAME + * @see org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER = "{argumentSetNameOrArgumentsWithNames}"; + + /** + * Default display name pattern for the current invocation of a + * {@code @ParameterizedTest} method: {@value} + * + *

Note that the default pattern does not include the + * {@linkplain #DISPLAY_NAME_PLACEHOLDER display name} of the + * {@code @ParameterizedTest} method. + * + * @since 5.3 + * @see ParameterizedClass#name() + * @see ParameterizedTest#name() + * @see #DISPLAY_NAME_PLACEHOLDER + * @see #INDEX_PLACEHOLDER + * @see #ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + */ + public static final String DEFAULT_DISPLAY_NAME = ParameterizedInvocationNameFormatter.DEFAULT_DISPLAY_NAME_PATTERN; + + private ParameterizedInvocationConstants() { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.junit.platform.commons.util.ClassLoaderUtils.getClassLoader; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.aggregator.DefaultArgumentsAccessor; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.support.ParameterDeclarations; + +class ParameterizedInvocationContext> { + + private static final Namespace NAMESPACE = Namespace.create(ParameterizedTestInvocationContext.class); + + protected final T declarationContext; + private final ParameterizedInvocationNameFormatter formatter; + protected final EvaluatedArgumentSet arguments; + protected final int invocationIndex; + + ParameterizedInvocationContext(T declarationContext, ParameterizedInvocationNameFormatter formatter, + Arguments arguments, int invocationIndex) { + + this.declarationContext = declarationContext; + this.formatter = formatter; + ResolverFacade resolverFacade = this.declarationContext.getResolverFacade(); + this.arguments = EvaluatedArgumentSet.of(arguments, resolverFacade::determineConsumedArgumentLength); + this.invocationIndex = invocationIndex; + } + + public String getDisplayName(int invocationIndex) { + return this.formatter.format(invocationIndex, this.arguments); + } + + public void prepareInvocation(ExtensionContext context) { + if (this.declarationContext.isAutoClosingArguments()) { + registerAutoCloseableArgumentsInStoreForClosing(context); + } + validateArgumentCount(context); + storeParameterInfo(context); + } + + private void registerAutoCloseableArgumentsInStoreForClosing(ExtensionContext context) { + ExtensionContext.Store store = context.getStore(NAMESPACE); + AtomicInteger argumentIndex = new AtomicInteger(); + + Arrays.stream(this.arguments.getAllPayloads()) // + .filter(AutoCloseable.class::isInstance) // + .map(AutoCloseable.class::cast) // + .map(CloseableArgument::new) // + .forEach(closeable -> store.put(argumentIndex.incrementAndGet(), closeable)); + } + + private void validateArgumentCount(ExtensionContext context) { + new ArgumentCountValidator(this.declarationContext, this.arguments).validate(context); + } + + private void storeParameterInfo(ExtensionContext context) { + ParameterDeclarations declarations = this.declarationContext.getResolverFacade().getIndexedParameterDeclarations(); + ClassLoader classLoader = getClassLoader(this.declarationContext.getTestClass()); + Object[] arguments = this.arguments.getConsumedPayloads(); + ArgumentsAccessor accessor = DefaultArgumentsAccessor.create(context, invocationIndex, classLoader, arguments); + new DefaultParameterInfo(declarations, accessor).store(context); + } + + @SuppressWarnings({ "deprecation", "try" }) + private static class CloseableArgument implements ExtensionContext.Store.CloseableResource, AutoCloseable { + + private final AutoCloseable autoCloseable; + + CloseableArgument(AutoCloseable autoCloseable) { + this.autoCloseable = autoCloseable; + } + + @Override + public void close() throws Exception { + this.autoCloseable.close(); + } + + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContextProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContextProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContextProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationContextProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; + +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TemplateInvocationValidationException; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.params.support.AnnotationConsumerInitializer; +import org.junit.jupiter.params.support.ParameterDeclarations; +import org.junit.platform.commons.util.ExceptionUtils; +import org.junit.platform.commons.util.Preconditions; + +class ParameterizedInvocationContextProvider { + + protected Stream provideInvocationContexts(ExtensionContext extensionContext, + ParameterizedDeclarationContext declarationContext) { + + List argumentsSources = collectArgumentSources(declarationContext); + ParameterDeclarations parameters = declarationContext.getResolverFacade().getIndexedParameterDeclarations(); + ParameterizedInvocationNameFormatter formatter = ParameterizedInvocationNameFormatter.create(extensionContext, + declarationContext); + AtomicLong invocationCount = new AtomicLong(0); + + // @formatter:off + return argumentsSources + .stream() + .map(ArgumentsSource::value) + .map(clazz -> ParameterizedTestSpiInstantiator.instantiate(ArgumentsProvider.class, clazz, extensionContext)) + .map(provider -> AnnotationConsumerInitializer.initialize(declarationContext.getAnnotatedElement(), provider)) + .flatMap(provider -> arguments(provider, parameters, extensionContext)) + .map(arguments -> { + invocationCount.incrementAndGet(); + return declarationContext.createInvocationContext(formatter, arguments, invocationCount.intValue()); + }) + .onClose(() -> validateInvokedAtLeastOnce(invocationCount.get(),declarationContext )); + // @formatter:on + } + + private static void validateInvokedAtLeastOnce(long invocationCount, + ParameterizedDeclarationContext declarationContext) { + if (invocationCount == 0 && !declarationContext.isAllowingZeroInvocations()) { + String message = String.format( + "Configuration error: You must configure at least one set of arguments for this @%s", + declarationContext.getAnnotationName()); + throw new TemplateInvocationValidationException(message); + } + } + + private static List collectArgumentSources(ParameterizedDeclarationContext declarationContext) { + List argumentsSources = findRepeatableAnnotations(declarationContext.getAnnotatedElement(), + ArgumentsSource.class); + + Preconditions.notEmpty(argumentsSources, + () -> String.format("Configuration error: You must configure at least one arguments source for this @%s", + declarationContext.getAnnotationName())); + + return argumentsSources; + } + + protected static Stream arguments(ArgumentsProvider provider, ParameterDeclarations parameters, + ExtensionContext context) { + try { + return provider.provideArguments(parameters, context); + } + catch (Exception e) { + throw ExceptionUtils.throwAsUncheckedException(e); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,327 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static java.util.stream.Collectors.joining; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENTS_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENTS_WITH_NAMES_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENT_SET_NAME_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.DISPLAY_NAME_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.INDEX_PLACEHOLDER; +import static org.junit.platform.commons.util.StringUtils.isNotBlank; + +import java.text.FieldPosition; +import java.text.Format; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; +import java.util.stream.IntStream; + +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.StringUtils; + +/** + * @since 5.0 + */ +class ParameterizedInvocationNameFormatter { + + static final String DEFAULT_DISPLAY_NAME = "{default_display_name}"; + static final String DEFAULT_DISPLAY_NAME_PATTERN = "[" + INDEX_PLACEHOLDER + "] " + + ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER; + static final String DISPLAY_NAME_PATTERN_KEY = "junit.jupiter.params.displayname.default"; + static final String ARGUMENT_MAX_LENGTH_KEY = "junit.jupiter.params.displayname.argument.maxlength"; + + static ParameterizedInvocationNameFormatter create(ExtensionContext extensionContext, + ParameterizedDeclarationContext declarationContext) { + + String name = declarationContext.getDisplayNamePattern(); + String pattern = name.equals(DEFAULT_DISPLAY_NAME) + ? extensionContext.getConfigurationParameter(DISPLAY_NAME_PATTERN_KEY) // + .orElse(DEFAULT_DISPLAY_NAME_PATTERN) + : name; + pattern = Preconditions.notBlank(pattern.trim(), () -> String.format( + "Configuration error: @%s on %s must be declared with a non-empty name.", + declarationContext.getAnnotationName(), + declarationContext.getResolverFacade().getIndexedParameterDeclarations().getSourceElementDescription())); + + int argumentMaxLength = extensionContext.getConfigurationParameter(ARGUMENT_MAX_LENGTH_KEY, Integer::parseInt) // + .orElse(512); + + return new ParameterizedInvocationNameFormatter(pattern, extensionContext.getDisplayName(), declarationContext, + argumentMaxLength); + } + + private final PartialFormatter[] partialFormatters; + + ParameterizedInvocationNameFormatter(String pattern, String displayName, + ParameterizedDeclarationContext declarationContext, int argumentMaxLength) { + try { + this.partialFormatters = parse(pattern, displayName, declarationContext, argumentMaxLength); + } + catch (Exception ex) { + String message = "The display name pattern defined for the parameterized test is invalid. " + + "See nested exception for further details."; + throw new JUnitException(message, ex); + } + } + + String format(int invocationIndex, EvaluatedArgumentSet arguments) { + try { + return formatSafely(invocationIndex, arguments); + } + catch (Exception ex) { + String message = "Failed to format display name for parameterized test. " + + "See nested exception for further details."; + throw new JUnitException(message, ex); + } + } + + private String formatSafely(int invocationIndex, EvaluatedArgumentSet arguments) { + ArgumentsContext context = new ArgumentsContext(invocationIndex, arguments.getConsumedNames(), + arguments.getName()); + StringBuffer result = new StringBuffer(); // used instead of StringBuilder so MessageFormat can append directly + for (PartialFormatter partialFormatter : this.partialFormatters) { + partialFormatter.append(context, result); + } + return result.toString(); + } + + private PartialFormatter[] parse(String pattern, String displayName, + ParameterizedDeclarationContext declarationContext, int argumentMaxLength) { + + List result = new ArrayList<>(); + PartialFormatters formatters = createPartialFormatters(displayName, declarationContext, argumentMaxLength); + String unparsedSegment = pattern; + + while (isNotBlank(unparsedSegment)) { + PlaceholderPosition position = findFirstPlaceholder(formatters, unparsedSegment); + if (position == null) { + result.add(determineNonPlaceholderFormatter(unparsedSegment, argumentMaxLength)); + break; + } + if (position.index > 0) { + String before = unparsedSegment.substring(0, position.index); + result.add(determineNonPlaceholderFormatter(before, argumentMaxLength)); + } + result.add(formatters.get(position.placeholder)); + unparsedSegment = unparsedSegment.substring(position.index + position.placeholder.length()); + } + + return result.toArray(new PartialFormatter[0]); + } + + private static PlaceholderPosition findFirstPlaceholder(PartialFormatters formatters, String segment) { + if (segment.length() < formatters.minimumPlaceholderLength) { + return null; + } + PlaceholderPosition minimum = null; + for (String placeholder : formatters.placeholders()) { + int index = segment.indexOf(placeholder); + if (index >= 0) { + if (index < formatters.minimumPlaceholderLength) { + return new PlaceholderPosition(index, placeholder); + } + else if (minimum == null || index < minimum.index) { + minimum = new PlaceholderPosition(index, placeholder); + } + } + } + return minimum; + } + + private static PartialFormatter determineNonPlaceholderFormatter(String segment, int argumentMaxLength) { + return segment.contains("{") // + ? new MessageFormatPartialFormatter(segment, argumentMaxLength) // + : (context, result) -> result.append(segment); + } + + private PartialFormatters createPartialFormatters(String displayName, + ParameterizedDeclarationContext declarationContext, int argumentMaxLength) { + + PartialFormatter argumentsWithNamesFormatter = new CachingByArgumentsLengthPartialFormatter( + length -> new MessageFormatPartialFormatter(argumentsWithNamesPattern(length, declarationContext), + argumentMaxLength)); + + PartialFormatter argumentSetNameFormatter = new ArgumentSetNameFormatter( + declarationContext.getAnnotationName()); + + PartialFormatters formatters = new PartialFormatters(); + formatters.put(INDEX_PLACEHOLDER, PartialFormatter.INDEX); + formatters.put(DISPLAY_NAME_PLACEHOLDER, (context, result) -> result.append(displayName)); + formatters.put(ARGUMENT_SET_NAME_PLACEHOLDER, argumentSetNameFormatter); + formatters.put(ARGUMENTS_WITH_NAMES_PLACEHOLDER, argumentsWithNamesFormatter); + formatters.put(ARGUMENTS_PLACEHOLDER, new CachingByArgumentsLengthPartialFormatter( + length -> new MessageFormatPartialFormatter(argumentsPattern(length), argumentMaxLength))); + formatters.put(ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER, (context, result) -> { + PartialFormatter formatterToUse = context.argumentSetName.isPresent() // + ? argumentSetNameFormatter // + : argumentsWithNamesFormatter; + formatterToUse.append(context, result); + }); + return formatters; + } + + private static String argumentsWithNamesPattern(int length, ParameterizedDeclarationContext declarationContext) { + ResolverFacade resolverFacade = declarationContext.getResolverFacade(); + return IntStream.range(0, length) // + .mapToObj(index -> resolverFacade.getParameterName(index).map(name -> name + "=").orElse("") + "{" + + index + "}") // + .collect(joining(", ")); + } + + private static String argumentsPattern(int length) { + return IntStream.range(0, length) // + .mapToObj(index -> "{" + index + "}") // + .collect(joining(", ")); + } + + private static class PlaceholderPosition { + + final int index; + final String placeholder; + + PlaceholderPosition(int index, String placeholder) { + this.index = index; + this.placeholder = placeholder; + } + + } + + private static class ArgumentsContext { + + private final int invocationIndex; + private final Object[] consumedArguments; + private final Optional argumentSetName; + + ArgumentsContext(int invocationIndex, Object[] consumedArguments, Optional argumentSetName) { + this.invocationIndex = invocationIndex; + this.consumedArguments = consumedArguments; + this.argumentSetName = argumentSetName; + } + } + + @FunctionalInterface + private interface PartialFormatter { + + PartialFormatter INDEX = (context, result) -> result.append(context.invocationIndex); + + void append(ArgumentsContext context, StringBuffer result); + + } + + private static class ArgumentSetNameFormatter implements PartialFormatter { + + private final String annotationName; + + ArgumentSetNameFormatter(String annotationName) { + this.annotationName = annotationName; + } + + @Override + public void append(ArgumentsContext context, StringBuffer result) { + if (context.argumentSetName.isPresent()) { + result.append(context.argumentSetName.get()); + return; + } + throw new ExtensionConfigurationException(String.format( + "When the display name pattern for a @%s contains %s, the arguments must be supplied as an ArgumentSet.", + this.annotationName, ARGUMENT_SET_NAME_PLACEHOLDER)); + } + } + + private static class MessageFormatPartialFormatter implements PartialFormatter { + + @SuppressWarnings("UnnecessaryUnicodeEscape") + private static final char ELLIPSIS = '\u2026'; + + private final MessageFormat messageFormat; + private final int argumentMaxLength; + + MessageFormatPartialFormatter(String pattern, int argumentMaxLength) { + this.messageFormat = new MessageFormat(pattern); + this.argumentMaxLength = argumentMaxLength; + } + + // synchronized because MessageFormat is not thread-safe + @Override + public synchronized void append(ArgumentsContext context, StringBuffer result) { + this.messageFormat.format(makeReadable(context.consumedArguments), result, new FieldPosition(0)); + } + + private Object[] makeReadable(Object[] arguments) { + Format[] formats = messageFormat.getFormatsByArgumentIndex(); + Object[] result = Arrays.copyOf(arguments, Math.min(arguments.length, formats.length), Object[].class); + for (int i = 0; i < result.length; i++) { + if (formats[i] == null) { + result[i] = truncateIfExceedsMaxLength(StringUtils.nullSafeToString(arguments[i])); + } + } + return result; + } + + private String truncateIfExceedsMaxLength(String argument) { + if (argument != null && argument.length() > this.argumentMaxLength) { + return argument.substring(0, this.argumentMaxLength - 1) + ELLIPSIS; + } + return argument; + } + } + + private static class CachingByArgumentsLengthPartialFormatter implements PartialFormatter { + + private final ConcurrentMap cache = new ConcurrentHashMap<>(1); + private final Function factory; + + CachingByArgumentsLengthPartialFormatter(Function factory) { + this.factory = factory; + } + + @Override + public void append(ArgumentsContext context, StringBuffer result) { + cache.computeIfAbsent(context.consumedArguments.length, factory).append(context, result); + } + } + + private static class PartialFormatters { + + private final Map formattersByPlaceholder = new LinkedHashMap<>(); + private int minimumPlaceholderLength = Integer.MAX_VALUE; + + void put(String placeholder, PartialFormatter formatter) { + formattersByPlaceholder.put(placeholder, formatter); + int newPlaceholderLength = placeholder.length(); + if (newPlaceholderLength < minimumPlaceholderLength) { + minimumPlaceholderLength = newPlaceholderLength; + } + } + + PartialFormatter get(String placeholder) { + return formattersByPlaceholder.get(placeholder); + } + + Set placeholders() { + return formattersByPlaceholder.keySet(); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationParameterResolver.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.lang.reflect.Executable; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +/** + * @since 5.13 + */ +abstract class ParameterizedInvocationParameterResolver implements ParameterResolver { + + private final ResolverFacade resolverFacade; + private final EvaluatedArgumentSet arguments; + private final int invocationIndex; + private final ResolutionCache resolutionCache; + + ParameterizedInvocationParameterResolver(ResolverFacade resolverFacade, EvaluatedArgumentSet arguments, + int invocationIndex, ResolutionCache resolutionCache) { + + this.resolverFacade = resolverFacade; + this.arguments = arguments; + this.invocationIndex = invocationIndex; + this.resolutionCache = resolutionCache; + } + + @Override + public final ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override + public final boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + + return isSupportedOnConstructorOrMethod(parameterContext.getDeclaringExecutable(), extensionContext) // + && this.resolverFacade.isSupportedParameter(parameterContext, this.arguments); + + } + + @Override + public final Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + + return this.resolverFacade.resolve(parameterContext, extensionContext, this.arguments, this.invocationIndex, + this.resolutionCache); + } + + protected abstract boolean isSupportedOnConstructorOrMethod(Executable declaringExecutable, + ExtensionContext extensionContext); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,8 @@ package org.junit.jupiter.params; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -22,6 +23,7 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.provider.ArgumentsSource; /** * {@code @ParameterizedTest} is used to signal that the annotated method is a @@ -45,18 +47,18 @@ *

A {@code @ParameterizedTest} method may declare additional parameters at * the end of the method's parameter list to be resolved by other * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers} - * (e.g., {@code TestInfo}, {@code TestReporter}, etc). Specifically, a + * (e.g., {@code TestInfo}, {@code TestReporter}, etc.). Specifically, a * parameterized test method must declare formal parameters according to the * following rules. * *

    - *
  1. Zero or more indexed arguments must be declared first.
  2. + *
  3. Zero or more indexed parameters must be declared first.
  4. *
  5. Zero or more aggregators must be declared next.
  6. - *
  7. Zero or more arguments supplied by other {@code ParameterResolver} + *
  8. Zero or more parameters supplied by other {@code ParameterResolver} * implementations must be declared last.
  9. *
* - *

In this context, an indexed argument is an argument for a given + *

In this context, an indexed parameter is an argument for a given * index in the {@code Arguments} provided by an {@code ArgumentsProvider} that * is passed as an argument to the parameterized method at the same index in the * method's formal parameter list. An aggregator is any parameter of type @@ -112,6 +114,7 @@ * implementation. * * @since 5.0 + * @see ParameterizedClass * @see org.junit.jupiter.params.provider.Arguments * @see org.junit.jupiter.params.provider.ArgumentsProvider * @see org.junit.jupiter.params.provider.ArgumentsSource @@ -135,127 +138,135 @@ public @interface ParameterizedTest { /** - * Placeholder for the {@linkplain org.junit.jupiter.api.TestInfo#getDisplayName - * display name} of a {@code @ParameterizedTest} method: {displayName} + * See {@link ParameterizedInvocationConstants#DISPLAY_NAME_PLACEHOLDER}. * * @since 5.3 * @see #name + * @deprecated Please reference + * {@link ParameterizedInvocationConstants#DISPLAY_NAME_PLACEHOLDER} + * instead. */ - String DISPLAY_NAME_PLACEHOLDER = "{displayName}"; + @API(status = DEPRECATED, since = "5.13") + @Deprecated + String DISPLAY_NAME_PLACEHOLDER = ParameterizedInvocationConstants.DISPLAY_NAME_PLACEHOLDER; /** - * Placeholder for the current invocation index of a {@code @ParameterizedTest} - * method (1-based): {index} + * See {@link ParameterizedInvocationConstants#INDEX_PLACEHOLDER}. * * @since 5.3 * @see #name - * @see #DEFAULT_DISPLAY_NAME + * @see ParameterizedInvocationConstants#DEFAULT_DISPLAY_NAME + * @deprecated Please reference + * {@link ParameterizedInvocationConstants#INDEX_PLACEHOLDER} instead. */ + @API(status = DEPRECATED, since = "5.13") + @Deprecated String INDEX_PLACEHOLDER = "{index}"; /** - * Placeholder for the complete, comma-separated arguments list of the - * current invocation of a {@code @ParameterizedTest} method: - * {arguments} + * See {@link ParameterizedInvocationConstants#ARGUMENTS_PLACEHOLDER}. * * @since 5.3 * @see #name + * @deprecated Please reference + * {@link ParameterizedInvocationConstants#ARGUMENTS_PLACEHOLDER} instead. */ + @API(status = DEPRECATED, since = "5.13") + @Deprecated String ARGUMENTS_PLACEHOLDER = "{arguments}"; /** - * Placeholder for the complete, comma-separated named arguments list - * of the current invocation of a {@code @ParameterizedTest} method: - * {argumentsWithNames} - * - *

Argument names will be retrieved via the {@link java.lang.reflect.Parameter#getName()} - * API if the byte code contains parameter names — for example, if - * the code was compiled with the {@code -parameters} command line argument - * for {@code javac}. + * See + * {@link ParameterizedInvocationConstants#ARGUMENTS_WITH_NAMES_PLACEHOLDER}. * * @since 5.6 * @see #name - * @see #ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @see ParameterizedInvocationConstants#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @deprecated Please reference + * {@link ParameterizedInvocationConstants#ARGUMENTS_WITH_NAMES_PLACEHOLDER} + * instead. */ + @API(status = DEPRECATED, since = "5.13") + @Deprecated String ARGUMENTS_WITH_NAMES_PLACEHOLDER = "{argumentsWithNames}"; /** - * Placeholder for the name of the argument set for the current invocation - * of a {@code @ParameterizedTest} method: {argumentSetName}. - * - *

This placeholder can be used when the current set of arguments was created via - * {@link org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) - * argumentSet()}. + * See + * {@link ParameterizedInvocationConstants#ARGUMENT_SET_NAME_PLACEHOLDER}. * * @since 5.11 * @see #name - * @see #ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @see ParameterizedInvocationConstants#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER * @see org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) + * @deprecated Please reference + * {@link ParameterizedInvocationConstants#ARGUMENT_SET_NAME_PLACEHOLDER} + * instead. */ - @API(status = EXPERIMENTAL, since = "5.11") + @API(status = DEPRECATED, since = "5.13") + @Deprecated String ARGUMENT_SET_NAME_PLACEHOLDER = "{argumentSetName}"; /** - * Placeholder for either {@link #ARGUMENT_SET_NAME_PLACEHOLDER} or - * {@link #ARGUMENTS_WITH_NAMES_PLACEHOLDER}, depending on whether the - * current set of arguments was created via - * {@link org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) - * argumentSet()}: {argumentSetNameOrArgumentsWithNames}. + * See + * {@link ParameterizedInvocationConstants#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER}. * * @since 5.11 * @see #name - * @see #ARGUMENT_SET_NAME_PLACEHOLDER - * @see #ARGUMENTS_WITH_NAMES_PLACEHOLDER - * @see #DEFAULT_DISPLAY_NAME + * @see ParameterizedInvocationConstants#ARGUMENT_SET_NAME_PLACEHOLDER + * @see ParameterizedInvocationConstants#ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @see ParameterizedInvocationConstants#DEFAULT_DISPLAY_NAME * @see org.junit.jupiter.params.provider.Arguments#argumentSet(String, Object...) + * @deprecated Please reference + * {@link ParameterizedInvocationConstants#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER} + * instead. */ - @API(status = EXPERIMENTAL, since = "5.11") + @API(status = DEPRECATED, since = "5.13") + @Deprecated String ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER = "{argumentSetNameOrArgumentsWithNames}"; /** - * Default display name pattern for the current invocation of a - * {@code @ParameterizedTest} method: {@value} - * - *

Note that the default pattern does not include the - * {@linkplain #DISPLAY_NAME_PLACEHOLDER display name} of the - * {@code @ParameterizedTest} method. + * See + * {@link ParameterizedInvocationConstants#DEFAULT_DISPLAY_NAME}. * * @since 5.3 * @see #name - * @see #DISPLAY_NAME_PLACEHOLDER - * @see #INDEX_PLACEHOLDER - * @see #ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @see ParameterizedInvocationConstants#DISPLAY_NAME_PLACEHOLDER + * @see ParameterizedInvocationConstants#INDEX_PLACEHOLDER + * @see ParameterizedInvocationConstants#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER + * @deprecated Please reference + * {@link ParameterizedInvocationConstants#DEFAULT_DISPLAY_NAME} instead. */ - String DEFAULT_DISPLAY_NAME = "[" + INDEX_PLACEHOLDER + "] " - + ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER; + @API(status = DEPRECATED, since = "5.13") + @Deprecated + String DEFAULT_DISPLAY_NAME = ParameterizedInvocationConstants.DEFAULT_DISPLAY_NAME; /** * The display name to be used for individual invocations of the * parameterized test; never blank or consisting solely of whitespace. * - *

Defaults to {@value ParameterizedTestExtension#DEFAULT_DISPLAY_NAME}. + *

Defaults to {@value ParameterizedInvocationNameFormatter#DEFAULT_DISPLAY_NAME}. * *

If the default display name flag - * ({@value ParameterizedTestExtension#DEFAULT_DISPLAY_NAME}) + * ({@value ParameterizedInvocationNameFormatter#DEFAULT_DISPLAY_NAME}) * is not overridden, JUnit will: *

    - *
  • Look up the {@value ParameterizedTestExtension#DISPLAY_NAME_PATTERN_KEY} + *
  • Look up the {@value ParameterizedInvocationNameFormatter#DISPLAY_NAME_PATTERN_KEY} * configuration parameter and use it if available. The configuration * parameter can be supplied via the {@code Launcher} API, build tools (e.g., * Gradle and Maven), a JVM system property, or the JUnit Platform configuration * file (i.e., a file named {@code junit-platform.properties} in the root of * the class path). Consult the User Guide for further information.
  • - *
  • Otherwise, {@value #DEFAULT_DISPLAY_NAME} will be used.
  • + *
  • Otherwise, {@value ParameterizedInvocationConstants#DEFAULT_DISPLAY_NAME} will be used.
  • *
* *

Supported placeholders

*
    - *
  • {@value #DISPLAY_NAME_PLACEHOLDER}
  • - *
  • {@value #INDEX_PLACEHOLDER}
  • - *
  • {@value #ARGUMENT_SET_NAME_PLACEHOLDER}
  • - *
  • {@value #ARGUMENTS_PLACEHOLDER}
  • - *
  • {@value #ARGUMENTS_WITH_NAMES_PLACEHOLDER}
  • - *
  • {@value #ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#DISPLAY_NAME_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#INDEX_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENT_SET_NAME_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENTS_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENTS_WITH_NAMES_PLACEHOLDER}
  • + *
  • {@value ParameterizedInvocationConstants#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER}
  • *
  • "{0}", "{1}", etc.: an individual argument (0-based)
  • *
* @@ -265,25 +276,25 @@ * of any implicit or explicit argument conversions. * *

Note that - * {@value ParameterizedTestExtension#DEFAULT_DISPLAY_NAME} is + * {@value ParameterizedInvocationNameFormatter#DEFAULT_DISPLAY_NAME} is * a flag rather than a placeholder. * * @see java.text.MessageFormat */ - String name() default ParameterizedTestExtension.DEFAULT_DISPLAY_NAME; + String name() default ParameterizedInvocationNameFormatter.DEFAULT_DISPLAY_NAME; /** - * Configure whether all arguments of the parameterized test that implement {@link AutoCloseable} - * will be closed after {@link org.junit.jupiter.api.AfterEach @AfterEach} methods - * and {@link org.junit.jupiter.api.extension.AfterEachCallback AfterEachCallback} - * extensions have been called for the current parameterized test invocation. + * Configure whether all arguments of the parameterized test that implement + * {@link AutoCloseable} will be closed after their corresponding + * invocation. * *

Defaults to {@code true}. * - *

WARNING: if an argument that implements {@code AutoCloseable} - * is reused for multiple invocations of the same parameterized test method, - * you must set {@code autoCloseArguments} to {@code false} to ensure that - * the argument is not closed between invocations. + *

WARNING: if an argument that implements + * {@code AutoCloseable} is reused for multiple invocations of the same + * parameterized test method, you must set {@code autoCloseArguments} to + * {@code false} to ensure that the argument is not closed between + * invocations. * * @since 5.8 * @see java.lang.AutoCloseable @@ -291,4 +302,39 @@ @API(status = STABLE, since = "5.10") boolean autoCloseArguments() default true; + /** + * Configure whether zero invocations are allowed for this + * parameterized test. + * + *

Set this attribute to {@code true} if the absence of invocations is + * expected in some cases and should not cause a test failure. + * + *

Defaults to {@code false}. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + boolean allowZeroInvocations() default false; + + /** + * Configure how the number of arguments provided by an + * {@link ArgumentsSource} are validated. + * + *

Defaults to {@link ArgumentCountValidationMode#DEFAULT}. + * + *

When an {@link ArgumentsSource} provides more arguments than declared + * by the parameterized test method, there might be a bug in the method or + * the {@link ArgumentsSource}. By default, the additional arguments are + * ignored. {@code argumentCountValidation} allows you to control how + * additional arguments are handled. The default can be configured via the + * {@value ArgumentCountValidator#ARGUMENT_COUNT_VALIDATION_KEY} + * configuration parameter (see the User Guide for details on configuration + * parameters). + * + * @since 5.12 + * @see ArgumentCountValidationMode + */ + @API(status = MAINTAINED, since = "5.13.3") + ArgumentCountValidationMode argumentCountValidation() default ArgumentCountValidationMode.DEFAULT; + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.lang.reflect.Method; + +import org.junit.jupiter.api.extension.TestTemplateInvocationContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.platform.commons.util.Preconditions; + +/** + * Encapsulates access to the parameters of a parameterized test method and + * caches the converters and aggregators used to resolve them. + * + * @since 5.3 + */ +class ParameterizedTestContext implements ParameterizedDeclarationContext { + + private final Class testClass; + private final Method method; + private final ParameterizedTest annotation; + private final ResolverFacade resolverFacade; + + ParameterizedTestContext(Class testClass, Method method, ParameterizedTest annotation) { + this.testClass = testClass; + this.method = Preconditions.notNull(method, "method must not be null"); + this.annotation = Preconditions.notNull(annotation, "annotation must not be null"); + this.resolverFacade = ResolverFacade.create(method, annotation); + } + + @Override + public Class getTestClass() { + return this.testClass; + } + + @Override + public ParameterizedTest getAnnotation() { + return this.annotation; + } + + @Override + public Method getAnnotatedElement() { + return this.method; + } + + @Override + public String getDisplayNamePattern() { + return this.annotation.name(); + } + + @Override + public boolean isAutoClosingArguments() { + return this.annotation.autoCloseArguments(); + } + + @Override + public boolean isAllowingZeroInvocations() { + return this.annotation.allowZeroInvocations(); + } + + @Override + public ArgumentCountValidationMode getArgumentCountValidationMode() { + return this.annotation.argumentCountValidation(); + } + + @Override + public ResolverFacade getResolverFacade() { + return this.resolverFacade; + } + + @Override + public TestTemplateInvocationContext createInvocationContext(ParameterizedInvocationNameFormatter formatter, + Arguments arguments, int invocationIndex) { + return new ParameterizedTestInvocationContext(this, formatter, arguments, invocationIndex); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,58 +10,35 @@ package org.junit.jupiter.params; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; -import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; -import java.lang.reflect.Method; -import java.util.concurrent.atomic.AtomicLong; +import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; -import org.junit.jupiter.params.support.AnnotationConsumerInitializer; -import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.util.ExceptionUtils; -import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; /** * @since 5.0 */ -class ParameterizedTestExtension implements TestTemplateInvocationContextProvider { +class ParameterizedTestExtension extends ParameterizedInvocationContextProvider + implements TestTemplateInvocationContextProvider { - private static final String METHOD_CONTEXT_KEY = "context"; - static final String ARGUMENT_MAX_LENGTH_KEY = "junit.jupiter.params.displayname.argument.maxlength"; - static final String DEFAULT_DISPLAY_NAME = "{default_display_name}"; - static final String DISPLAY_NAME_PATTERN_KEY = "junit.jupiter.params.displayname.default"; + static final String DECLARATION_CONTEXT_KEY = "context"; @Override public boolean supportsTestTemplate(ExtensionContext context) { - if (!context.getTestMethod().isPresent()) { + Optional annotation = findAnnotation(context.getTestMethod(), ParameterizedTest.class); + if (!annotation.isPresent()) { return false; } - Method testMethod = context.getTestMethod().get(); - if (!isAnnotated(testMethod, ParameterizedTest.class)) { - return false; - } - - ParameterizedTestMethodContext methodContext = new ParameterizedTestMethodContext(testMethod); + ParameterizedTestContext methodContext = new ParameterizedTestContext(context.getRequiredTestClass(), + context.getRequiredTestMethod(), annotation.get()); - Preconditions.condition(methodContext.hasPotentiallyValidSignature(), - () -> String.format( - "@ParameterizedTest method [%s] declares formal parameters in an invalid order: " - + "argument aggregators must be declared after any indexed arguments " - + "and before any arguments resolved by another ParameterResolver.", - testMethod.toGenericString())); - - getStore(context).put(METHOD_CONTEXT_KEY, methodContext); + getStore(context).put(DECLARATION_CONTEXT_KEY, methodContext); return true; } @@ -70,82 +47,21 @@ public Stream provideTestTemplateInvocationContexts( ExtensionContext extensionContext) { - Method templateMethod = extensionContext.getRequiredTestMethod(); - String displayName = extensionContext.getDisplayName(); - ParameterizedTestMethodContext methodContext = getStore(extensionContext)// - .get(METHOD_CONTEXT_KEY, ParameterizedTestMethodContext.class); - int argumentMaxLength = extensionContext.getConfigurationParameter(ARGUMENT_MAX_LENGTH_KEY, - Integer::parseInt).orElse(512); - ParameterizedTestNameFormatter formatter = createNameFormatter(extensionContext, templateMethod, methodContext, - displayName, argumentMaxLength); - AtomicLong invocationCount = new AtomicLong(0); - - // @formatter:off - return findRepeatableAnnotations(templateMethod, ArgumentsSource.class) - .stream() - .map(ArgumentsSource::value) - .map(this::instantiateArgumentsProvider) - .map(provider -> AnnotationConsumerInitializer.initialize(templateMethod, provider)) - .flatMap(provider -> arguments(provider, extensionContext)) - .map(arguments -> { - invocationCount.incrementAndGet(); - return createInvocationContext(formatter, methodContext, arguments, invocationCount.intValue()); - }) - .onClose(() -> - Preconditions.condition(invocationCount.get() > 0, - "Configuration error: You must configure at least one set of arguments for this @ParameterizedTest")); - // @formatter:on - } - - @SuppressWarnings("ConstantConditions") - private ArgumentsProvider instantiateArgumentsProvider(Class clazz) { - try { - return ReflectionUtils.newInstance(clazz); - } - catch (Exception ex) { - if (ex instanceof NoSuchMethodException) { - String message = String.format("Failed to find a no-argument constructor for ArgumentsProvider [%s]. " - + "Please ensure that a no-argument constructor exists and " - + "that the class is either a top-level class or a static nested class", - clazz.getName()); - throw new JUnitException(message, ex); - } - throw ex; - } + return provideInvocationContexts(extensionContext, getDeclarationContext(extensionContext)); } - private ExtensionContext.Store getStore(ExtensionContext context) { - return context.getStore(Namespace.create(ParameterizedTestExtension.class, context.getRequiredTestMethod())); - } - - private TestTemplateInvocationContext createInvocationContext(ParameterizedTestNameFormatter formatter, - ParameterizedTestMethodContext methodContext, Arguments arguments, int invocationIndex) { - - return new ParameterizedTestInvocationContext(formatter, methodContext, arguments, invocationIndex); + @Override + public boolean mayReturnZeroTestTemplateInvocationContexts(ExtensionContext extensionContext) { + return getDeclarationContext(extensionContext).isAllowingZeroInvocations(); } - private ParameterizedTestNameFormatter createNameFormatter(ExtensionContext extensionContext, Method templateMethod, - ParameterizedTestMethodContext methodContext, String displayName, int argumentMaxLength) { - - ParameterizedTest parameterizedTest = findAnnotation(templateMethod, ParameterizedTest.class).get(); - String pattern = parameterizedTest.name().equals(DEFAULT_DISPLAY_NAME) - ? extensionContext.getConfigurationParameter(DISPLAY_NAME_PATTERN_KEY).orElse( - ParameterizedTest.DEFAULT_DISPLAY_NAME) - : parameterizedTest.name(); - pattern = Preconditions.notBlank(pattern.trim(), - () -> String.format( - "Configuration error: @ParameterizedTest on method [%s] must be declared with a non-empty name.", - templateMethod)); - return new ParameterizedTestNameFormatter(pattern, displayName, methodContext, argumentMaxLength); + private ParameterizedTestContext getDeclarationContext(ExtensionContext extensionContext) { + return getStore(extensionContext)// + .get(DECLARATION_CONTEXT_KEY, ParameterizedTestContext.class); } - protected static Stream arguments(ArgumentsProvider provider, ExtensionContext context) { - try { - return provider.provideArguments(context); - } - catch (Exception e) { - throw ExceptionUtils.throwAsUncheckedException(e); - } + private ExtensionContext.Store getStore(ExtensionContext context) { + return context.getStore(Namespace.create(ParameterizedTestExtension.class, context.getRequiredTestMethod())); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestInvocationContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestInvocationContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestInvocationContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestInvocationContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,51 +12,39 @@ import static java.util.Collections.singletonList; -import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.params.provider.Arguments; /** * @since 5.0 */ -class ParameterizedTestInvocationContext implements TestTemplateInvocationContext { +class ParameterizedTestInvocationContext extends ParameterizedInvocationContext + implements TestTemplateInvocationContext { - private final ParameterizedTestNameFormatter formatter; - private final ParameterizedTestMethodContext methodContext; - private final Arguments arguments; - private final Object[] consumedArguments; - private final int invocationIndex; - - ParameterizedTestInvocationContext(ParameterizedTestNameFormatter formatter, - ParameterizedTestMethodContext methodContext, Arguments arguments, int invocationIndex) { - - this.formatter = formatter; - this.methodContext = methodContext; - this.arguments = arguments; - this.consumedArguments = consumedArguments(methodContext, arguments.get()); - this.invocationIndex = invocationIndex; + ParameterizedTestInvocationContext(ParameterizedTestContext methodContext, + ParameterizedInvocationNameFormatter formatter, Arguments arguments, int invocationIndex) { + super(methodContext, formatter, arguments, invocationIndex); } @Override public String getDisplayName(int invocationIndex) { - return this.formatter.format(invocationIndex, this.arguments, this.consumedArguments); + return super.getDisplayName(invocationIndex); } @Override public List getAdditionalExtensions() { - return singletonList( - new ParameterizedTestParameterResolver(this.methodContext, this.consumedArguments, this.invocationIndex)); + return singletonList( // + new ParameterizedTestMethodParameterResolver(this.declarationContext, this.arguments, this.invocationIndex) // + ); } - private static Object[] consumedArguments(ParameterizedTestMethodContext methodContext, Object[] arguments) { - if (methodContext.hasAggregator()) { - return arguments; - } - int parameterCount = methodContext.getParameterCount(); - return arguments.length > parameterCount ? Arrays.copyOf(arguments, parameterCount) : arguments; + @Override + public void prepareInvocation(ExtensionContext context) { + super.prepareInvocation(context); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,276 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params; - -import static org.junit.jupiter.params.ParameterizedTestMethodContext.ResolverType.AGGREGATOR; -import static org.junit.jupiter.params.ParameterizedTestMethodContext.ResolverType.CONVERTER; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; - -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.params.aggregator.AggregateWith; -import org.junit.jupiter.params.aggregator.ArgumentsAccessor; -import org.junit.jupiter.params.aggregator.ArgumentsAggregator; -import org.junit.jupiter.params.aggregator.DefaultArgumentsAccessor; -import org.junit.jupiter.params.converter.ArgumentConverter; -import org.junit.jupiter.params.converter.ConvertWith; -import org.junit.jupiter.params.converter.DefaultArgumentConverter; -import org.junit.jupiter.params.support.AnnotationConsumerInitializer; -import org.junit.platform.commons.support.ReflectionSupport; -import org.junit.platform.commons.util.AnnotationUtils; -import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.commons.util.StringUtils; - -/** - * Encapsulates access to the parameters of a parameterized test method and - * caches the converters and aggregators used to resolve them. - * - * @since 5.3 - */ -class ParameterizedTestMethodContext { - - private final Parameter[] parameters; - private final Resolver[] resolvers; - private final List resolverTypes; - - ParameterizedTestMethodContext(Method testMethod) { - this.parameters = testMethod.getParameters(); - this.resolvers = new Resolver[this.parameters.length]; - this.resolverTypes = new ArrayList<>(this.parameters.length); - for (Parameter parameter : this.parameters) { - this.resolverTypes.add(isAggregator(parameter) ? AGGREGATOR : CONVERTER); - } - } - - /** - * Determine if the supplied {@link Parameter} is an aggregator (i.e., of - * type {@link ArgumentsAccessor} or annotated with {@link AggregateWith}). - * - * @return {@code true} if the parameter is an aggregator - */ - private static boolean isAggregator(Parameter parameter) { - return ArgumentsAccessor.class.isAssignableFrom(parameter.getType()) - || isAnnotated(parameter, AggregateWith.class); - } - - /** - * Determine if the {@link Method} represented by this context has a - * potentially valid signature (i.e., formal parameter - * declarations) with regard to aggregators. - * - *

This method takes a best-effort approach at enforcing the following - * policy for parameterized test methods that accept aggregators as arguments. - * - *

    - *
  1. zero or more indexed arguments come first.
  2. - *
  3. zero or more aggregators come next.
  4. - *
  5. zero or more arguments supplied by other {@code ParameterResolver} - * implementations come last.
  6. - *
- * - * @return {@code true} if the method has a potentially valid signature - */ - boolean hasPotentiallyValidSignature() { - int indexOfPreviousAggregator = -1; - for (int i = 0; i < getParameterCount(); i++) { - if (isAggregator(i)) { - if ((indexOfPreviousAggregator != -1) && (i != indexOfPreviousAggregator + 1)) { - return false; - } - indexOfPreviousAggregator = i; - } - } - return true; - } - - /** - * Get the number of parameters of the {@link Method} represented by this - * context. - */ - int getParameterCount() { - return parameters.length; - } - - /** - * Get the name of the {@link Parameter} with the supplied index, if - * it is present and declared before the aggregators. - * - * @return an {@code Optional} containing the name of the parameter - */ - Optional getParameterName(int parameterIndex) { - if (parameterIndex >= getParameterCount()) { - return Optional.empty(); - } - Parameter parameter = this.parameters[parameterIndex]; - if (!parameter.isNamePresent()) { - return Optional.empty(); - } - if (hasAggregator() && parameterIndex >= indexOfFirstAggregator()) { - return Optional.empty(); - } - return Optional.of(parameter.getName()); - } - - /** - * Determine if the {@link Method} represented by this context declares at - * least one {@link Parameter} that is an - * {@linkplain #isAggregator aggregator}. - * - * @return {@code true} if the method has an aggregator - */ - boolean hasAggregator() { - return resolverTypes.contains(AGGREGATOR); - } - - /** - * Determine if the {@link Parameter} with the supplied index is an - * aggregator (i.e., of type {@link ArgumentsAccessor} or annotated with - * {@link AggregateWith}). - * - * @return {@code true} if the parameter is an aggregator - */ - boolean isAggregator(int parameterIndex) { - return resolverTypes.get(parameterIndex) == AGGREGATOR; - } - - /** - * Find the index of the first {@linkplain #isAggregator aggregator} - * {@link Parameter} in the {@link Method} represented by this context. - * - * @return the index of the first aggregator, or {@code -1} if not found - */ - int indexOfFirstAggregator() { - return resolverTypes.indexOf(AGGREGATOR); - } - - /** - * Resolve the parameter for the supplied context using the supplied - * arguments. - */ - Object resolve(ParameterContext parameterContext, Object[] arguments, int invocationIndex) { - return getResolver(parameterContext).resolve(parameterContext, arguments, invocationIndex); - } - - private Resolver getResolver(ParameterContext parameterContext) { - int index = parameterContext.getIndex(); - if (resolvers[index] == null) { - resolvers[index] = resolverTypes.get(index).createResolver(parameterContext); - } - return resolvers[index]; - } - - enum ResolverType { - - CONVERTER { - @Override - Resolver createResolver(ParameterContext parameterContext) { - try { // @formatter:off - return AnnotationUtils.findAnnotation(parameterContext.getParameter(), ConvertWith.class) - .map(ConvertWith::value) - .map(clazz -> (ArgumentConverter) ReflectionUtils.newInstance(clazz)) - .map(converter -> AnnotationConsumerInitializer.initialize(parameterContext.getParameter(), converter)) - .map(Converter::new) - .orElse(Converter.DEFAULT); - } // @formatter:on - catch (Exception ex) { - throw parameterResolutionException("Error creating ArgumentConverter", ex, parameterContext); - } - } - }, - - AGGREGATOR { - @Override - Resolver createResolver(ParameterContext parameterContext) { - try { // @formatter:off - return AnnotationUtils.findAnnotation(parameterContext.getParameter(), AggregateWith.class) - .map(AggregateWith::value) - .map(clazz -> (ArgumentsAggregator) ReflectionSupport.newInstance(clazz)) - .map(Aggregator::new) - .orElse(Aggregator.DEFAULT); - } // @formatter:on - catch (Exception ex) { - throw parameterResolutionException("Error creating ArgumentsAggregator", ex, parameterContext); - } - } - }; - - abstract Resolver createResolver(ParameterContext parameterContext); - - } - - interface Resolver { - - Object resolve(ParameterContext parameterContext, Object[] arguments, int invocationIndex); - - } - - static class Converter implements Resolver { - - private static final Converter DEFAULT = new Converter(DefaultArgumentConverter.INSTANCE); - - private final ArgumentConverter argumentConverter; - - Converter(ArgumentConverter argumentConverter) { - this.argumentConverter = argumentConverter; - } - - @Override - public Object resolve(ParameterContext parameterContext, Object[] arguments, int invocationIndex) { - Object argument = arguments[parameterContext.getIndex()]; - try { - return this.argumentConverter.convert(argument, parameterContext); - } - catch (Exception ex) { - throw parameterResolutionException("Error converting parameter", ex, parameterContext); - } - } - - } - - static class Aggregator implements Resolver { - - private static final Aggregator DEFAULT = new Aggregator((accessor, context) -> accessor); - - private final ArgumentsAggregator argumentsAggregator; - - Aggregator(ArgumentsAggregator argumentsAggregator) { - this.argumentsAggregator = argumentsAggregator; - } - - @Override - public Object resolve(ParameterContext parameterContext, Object[] arguments, int invocationIndex) { - ArgumentsAccessor accessor = new DefaultArgumentsAccessor(parameterContext, invocationIndex, arguments); - try { - return this.argumentsAggregator.aggregateArguments(accessor, parameterContext); - } - catch (Exception ex) { - throw parameterResolutionException("Error aggregating arguments for parameter", ex, parameterContext); - } - } - - } - - private static ParameterResolutionException parameterResolutionException(String message, Exception cause, - ParameterContext parameterContext) { - String fullMessage = message + " at index " + parameterContext.getIndex(); - if (StringUtils.isNotBlank(cause.getMessage())) { - fullMessage += ": " + cause.getMessage(); - } - return new ParameterResolutionException(fullMessage, cause); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodParameterResolver.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; + +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * @since 5.0 + */ +class ParameterizedTestMethodParameterResolver extends ParameterizedInvocationParameterResolver { + + private final Method testTemplateMethod; + + ParameterizedTestMethodParameterResolver(ParameterizedTestContext methodContext, EvaluatedArgumentSet arguments, + int invocationIndex) { + super(methodContext.getResolverFacade(), arguments, invocationIndex, ResolutionCache.DISABLED); + this.testTemplateMethod = methodContext.getAnnotatedElement(); + } + + @Override + protected boolean isSupportedOnConstructorOrMethod(Executable declaringExecutable, + ExtensionContext extensionContext) { + return this.testTemplateMethod.equals(declaringExecutable); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,292 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params; - -import static java.util.stream.Collectors.joining; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENTS_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENTS_WITH_NAMES_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENT_SET_NAME_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.DISPLAY_NAME_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.INDEX_PLACEHOLDER; -import static org.junit.platform.commons.util.StringUtils.isNotBlank; - -import java.text.FieldPosition; -import java.text.Format; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; -import java.util.stream.IntStream; - -import org.junit.jupiter.api.Named; -import org.junit.jupiter.api.extension.ExtensionConfigurationException; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.Arguments.ArgumentSet; -import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.util.StringUtils; - -/** - * @since 5.0 - */ -class ParameterizedTestNameFormatter { - - private final PartialFormatter[] partialFormatters; - - ParameterizedTestNameFormatter(String pattern, String displayName, ParameterizedTestMethodContext methodContext, - int argumentMaxLength) { - try { - this.partialFormatters = parse(pattern, displayName, methodContext, argumentMaxLength); - } - catch (Exception ex) { - String message = "The display name pattern defined for the parameterized test is invalid. " - + "See nested exception for further details."; - throw new JUnitException(message, ex); - } - } - - String format(int invocationIndex, Arguments arguments, Object[] consumedArguments) { - try { - return formatSafely(invocationIndex, arguments, consumedArguments); - } - catch (Exception ex) { - String message = "Failed to format display name for parameterized test. " - + "See nested exception for further details."; - throw new JUnitException(message, ex); - } - } - - private String formatSafely(int invocationIndex, Arguments arguments, Object[] consumedArguments) { - ArgumentsContext context = new ArgumentsContext(invocationIndex, arguments, - extractNamedArguments(consumedArguments)); - StringBuffer result = new StringBuffer(); // used instead of StringBuilder so MessageFormat can append directly - for (PartialFormatter partialFormatter : this.partialFormatters) { - partialFormatter.append(context, result); - } - return result.toString(); - } - - private Object[] extractNamedArguments(Object[] arguments) { - return Arrays.stream(arguments) // - .map(argument -> argument instanceof Named ? ((Named) argument).getName() : argument) // - .toArray(); - } - - private PartialFormatter[] parse(String pattern, String displayName, ParameterizedTestMethodContext methodContext, - int argumentMaxLength) { - - List result = new ArrayList<>(); - PartialFormatters formatters = createPartialFormatters(displayName, methodContext, argumentMaxLength); - String unparsedSegment = pattern; - - while (isNotBlank(unparsedSegment)) { - PlaceholderPosition position = findFirstPlaceholder(formatters, unparsedSegment); - if (position == null) { - result.add(determineNonPlaceholderFormatter(unparsedSegment, argumentMaxLength)); - break; - } - if (position.index > 0) { - String before = unparsedSegment.substring(0, position.index); - result.add(determineNonPlaceholderFormatter(before, argumentMaxLength)); - } - result.add(formatters.get(position.placeholder)); - unparsedSegment = unparsedSegment.substring(position.index + position.placeholder.length()); - } - - return result.toArray(new PartialFormatter[0]); - } - - private static PlaceholderPosition findFirstPlaceholder(PartialFormatters formatters, String segment) { - if (segment.length() < formatters.minimumPlaceholderLength) { - return null; - } - PlaceholderPosition minimum = null; - for (String placeholder : formatters.placeholders()) { - int index = segment.indexOf(placeholder); - if (index >= 0) { - if (index < formatters.minimumPlaceholderLength) { - return new PlaceholderPosition(index, placeholder); - } - else if (minimum == null || index < minimum.index) { - minimum = new PlaceholderPosition(index, placeholder); - } - } - } - return minimum; - } - - private static PartialFormatter determineNonPlaceholderFormatter(String segment, int argumentMaxLength) { - return segment.contains("{") // - ? new MessageFormatPartialFormatter(segment, argumentMaxLength) // - : (context, result) -> result.append(segment); - } - - private PartialFormatters createPartialFormatters(String displayName, ParameterizedTestMethodContext methodContext, - int argumentMaxLength) { - - PartialFormatter argumentsWithNamesFormatter = new CachingByArgumentsLengthPartialFormatter( - length -> new MessageFormatPartialFormatter(argumentsWithNamesPattern(length, methodContext), - argumentMaxLength)); - - PartialFormatters formatters = new PartialFormatters(); - formatters.put(INDEX_PLACEHOLDER, PartialFormatter.INDEX); - formatters.put(DISPLAY_NAME_PLACEHOLDER, (context, result) -> result.append(displayName)); - formatters.put(ARGUMENT_SET_NAME_PLACEHOLDER, PartialFormatter.ARGUMENT_SET_NAME); - formatters.put(ARGUMENTS_WITH_NAMES_PLACEHOLDER, argumentsWithNamesFormatter); - formatters.put(ARGUMENTS_PLACEHOLDER, new CachingByArgumentsLengthPartialFormatter( - length -> new MessageFormatPartialFormatter(argumentsPattern(length), argumentMaxLength))); - formatters.put(ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER, (context, result) -> { - PartialFormatter formatterToUse = context.arguments instanceof ArgumentSet // - ? PartialFormatter.ARGUMENT_SET_NAME // - : argumentsWithNamesFormatter; - formatterToUse.append(context, result); - }); - return formatters; - } - - private static String argumentsWithNamesPattern(int length, ParameterizedTestMethodContext methodContext) { - return IntStream.range(0, length) // - .mapToObj(index -> methodContext.getParameterName(index).map(name -> name + "=").orElse("") + "{" - + index + "}") // - .collect(joining(", ")); - } - - private static String argumentsPattern(int length) { - return IntStream.range(0, length) // - .mapToObj(index -> "{" + index + "}") // - .collect(joining(", ")); - } - - private static class PlaceholderPosition { - - final int index; - final String placeholder; - - PlaceholderPosition(int index, String placeholder) { - this.index = index; - this.placeholder = placeholder; - } - - } - - private static class ArgumentsContext { - - private final int invocationIndex; - private final Arguments arguments; - private final Object[] consumedArguments; - - ArgumentsContext(int invocationIndex, Arguments arguments, Object[] consumedArguments) { - this.invocationIndex = invocationIndex; - this.arguments = arguments; - this.consumedArguments = consumedArguments; - } - } - - @FunctionalInterface - private interface PartialFormatter { - - PartialFormatter INDEX = (context, result) -> result.append(context.invocationIndex); - - PartialFormatter ARGUMENT_SET_NAME = (context, result) -> { - if (!(context.arguments instanceof ArgumentSet)) { - throw new ExtensionConfigurationException( - String.format("When the display name pattern for a @ParameterizedTest contains %s, " - + "the arguments must be supplied as an ArgumentSet.", - ARGUMENT_SET_NAME_PLACEHOLDER)); - } - result.append(((ArgumentSet) context.arguments).getName()); - }; - - void append(ArgumentsContext context, StringBuffer result); - } - - private static class MessageFormatPartialFormatter implements PartialFormatter { - - @SuppressWarnings("UnnecessaryUnicodeEscape") - private static final char ELLIPSIS = '\u2026'; - - private final MessageFormat messageFormat; - private final int argumentMaxLength; - - MessageFormatPartialFormatter(String pattern, int argumentMaxLength) { - this.messageFormat = new MessageFormat(pattern); - this.argumentMaxLength = argumentMaxLength; - } - - // synchronized because MessageFormat is not thread-safe - @Override - public synchronized void append(ArgumentsContext context, StringBuffer result) { - this.messageFormat.format(makeReadable(context.consumedArguments), result, new FieldPosition(0)); - } - - private Object[] makeReadable(Object[] arguments) { - Format[] formats = messageFormat.getFormatsByArgumentIndex(); - Object[] result = Arrays.copyOf(arguments, Math.min(arguments.length, formats.length), Object[].class); - for (int i = 0; i < result.length; i++) { - if (formats[i] == null) { - result[i] = truncateIfExceedsMaxLength(StringUtils.nullSafeToString(arguments[i])); - } - } - return result; - } - - private String truncateIfExceedsMaxLength(String argument) { - if (argument != null && argument.length() > this.argumentMaxLength) { - return argument.substring(0, this.argumentMaxLength - 1) + ELLIPSIS; - } - return argument; - } - } - - private static class CachingByArgumentsLengthPartialFormatter implements PartialFormatter { - - private final ConcurrentMap cache = new ConcurrentHashMap<>(1); - private final Function factory; - - CachingByArgumentsLengthPartialFormatter(Function factory) { - this.factory = factory; - } - - @Override - public void append(ArgumentsContext context, StringBuffer result) { - cache.computeIfAbsent(context.consumedArguments.length, factory).append(context, result); - } - } - - private static class PartialFormatters { - - private final Map formattersByPlaceholder = new LinkedHashMap<>(); - private int minimumPlaceholderLength = Integer.MAX_VALUE; - - void put(String placeholder, PartialFormatter formatter) { - formattersByPlaceholder.put(placeholder, formatter); - int newPlaceholderLength = placeholder.length(); - if (newPlaceholderLength < minimumPlaceholderLength) { - minimumPlaceholderLength = newPlaceholderLength; - } - } - - PartialFormatter get(String placeholder) { - return formattersByPlaceholder.get(placeholder); - } - - Set placeholders() { - return formattersByPlaceholder.keySet(); - } - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestParameterResolver.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestParameterResolver.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params; - -import java.lang.reflect.Executable; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.jupiter.api.Named; -import org.junit.jupiter.api.extension.AfterTestExecutionCallback; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ExtensionContext.Namespace; -import org.junit.jupiter.api.extension.ExtensionContext.Store; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.api.extension.ParameterResolver; -import org.junit.platform.commons.util.AnnotationUtils; - -/** - * @since 5.0 - */ -class ParameterizedTestParameterResolver implements ParameterResolver, AfterTestExecutionCallback { - - private static final Namespace NAMESPACE = Namespace.create(ParameterizedTestParameterResolver.class); - - private final ParameterizedTestMethodContext methodContext; - private final Object[] arguments; - private final int invocationIndex; - - ParameterizedTestParameterResolver(ParameterizedTestMethodContext methodContext, Object[] arguments, - int invocationIndex) { - - this.methodContext = methodContext; - this.arguments = arguments; - this.invocationIndex = invocationIndex; - } - - @Override - public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - Executable declaringExecutable = parameterContext.getDeclaringExecutable(); - Method testMethod = extensionContext.getTestMethod().orElse(null); - int parameterIndex = parameterContext.getIndex(); - - // Not a @ParameterizedTest method? - if (!declaringExecutable.equals(testMethod)) { - return false; - } - - // Current parameter is an aggregator? - if (this.methodContext.isAggregator(parameterIndex)) { - return true; - } - - // Ensure that the current parameter is declared before aggregators. - // Otherwise, a different ParameterResolver should handle it. - if (this.methodContext.hasAggregator()) { - return parameterIndex < this.methodContext.indexOfFirstAggregator(); - } - - // Else fallback to behavior for parameterized test methods without aggregators. - return parameterIndex < this.arguments.length; - } - - @Override - public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - return this.methodContext.resolve(parameterContext, extractPayloads(this.arguments), this.invocationIndex); - } - - /** - * @since 5.8 - */ - @Override - public void afterTestExecution(ExtensionContext context) { - ParameterizedTest parameterizedTest = AnnotationUtils.findAnnotation(context.getRequiredTestMethod(), - ParameterizedTest.class).get(); - if (!parameterizedTest.autoCloseArguments()) { - return; - } - - Store store = context.getStore(NAMESPACE); - AtomicInteger argumentIndex = new AtomicInteger(); - - Arrays.stream(this.arguments) // - .filter(AutoCloseable.class::isInstance) // - .map(AutoCloseable.class::cast) // - .map(CloseableArgument::new) // - .forEach(closeable -> store.put("closeableArgument#" + argumentIndex.incrementAndGet(), closeable)); - } - - private static class CloseableArgument implements Store.CloseableResource { - - private final AutoCloseable autoCloseable; - - CloseableArgument(AutoCloseable autoCloseable) { - this.autoCloseable = autoCloseable; - } - - @Override - public void close() throws Throwable { - this.autoCloseable.close(); - } - - } - - private Object[] extractPayloads(Object[] arguments) { - return Arrays.stream(arguments) // - .map(argument -> { - if (argument instanceof Named) { - return ((Named) argument).getPayload(); - } - return argument; - }) // - .toArray(); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.lang.reflect.Constructor; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ReflectionUtils; + +/** + * @since 5.12 + */ +class ParameterizedTestSpiInstantiator { + + static T instantiate(Class spiInterface, Class implementationClass, + ExtensionContext extensionContext) { + + return extensionContext.getExecutableInvoker() // + .invoke(findConstructor(spiInterface, implementationClass)); + } + + @SuppressWarnings("unchecked") + private static Constructor findConstructor(Class spiInterface, + Class implementationClass) { + + return (Constructor) findBestConstructor(spiInterface, implementationClass); + } + + /** + * Find the "best" constructor for the supplied implementation class. + * + *

For backward compatibility, it first checks for a single constructor + * and returns that. If there are multiple constructors, it checks for a + * default constructor which takes precedence over any other constructors. + * Otherwise, this method throws an exception stating that it failed to + * find a suitable constructor. + */ + private static Constructor findBestConstructor(Class spiInterface, + Class implementationClass) { + + Preconditions.condition(!ReflectionUtils.isInnerClass(implementationClass), + () -> String.format("The %s [%s] must be either a top-level class or a static nested class", + spiInterface.getSimpleName(), implementationClass.getName())); + + Constructor[] constructors = implementationClass.getDeclaredConstructors(); + + // Single constructor? + if (constructors.length == 1) { + return constructors[0]; + } + // Find default constructor. + for (Constructor constructor : constructors) { + if (constructor.getParameterCount() == 0) { + return constructor; + } + } + // Otherwise... + String message = String.format( + "Failed to find constructor for %s [%s]. " + + "Please ensure that a no-argument or a single constructor exists.", + spiInterface.getSimpleName(), implementationClass.getName()); + throw new JUnitException(message); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolutionCache.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolutionCache.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolutionCache.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolutionCache.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +import org.junit.jupiter.params.support.ParameterDeclaration; + +/** + * @since 5.13 + */ +interface ResolutionCache { + + static ResolutionCache enabled() { + return new Concurrent(); + } + + ResolutionCache DISABLED = (__, resolver) -> resolver.get(); + + Object resolve(ParameterDeclaration declaration, Supplier resolver); + + class Concurrent implements ResolutionCache { + + private final Map cache = new ConcurrentHashMap<>(); + + @Override + public Object resolve(ParameterDeclaration declaration, Supplier resolver) { + return cache.computeIfAbsent(declaration, __ -> resolver.get()); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,801 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static java.lang.System.lineSeparator; +import static java.util.Collections.unmodifiableList; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; +import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible; +import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.junit.jupiter.api.extension.AnnotatedElementContext; +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.params.aggregator.AggregateWith; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.aggregator.ArgumentsAggregationException; +import org.junit.jupiter.params.aggregator.ArgumentsAggregator; +import org.junit.jupiter.params.aggregator.SimpleArgumentsAggregator; +import org.junit.jupiter.params.converter.ArgumentConverter; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.converter.DefaultArgumentConverter; +import org.junit.jupiter.params.support.AnnotationConsumerInitializer; +import org.junit.jupiter.params.support.FieldContext; +import org.junit.jupiter.params.support.ParameterDeclaration; +import org.junit.jupiter.params.support.ParameterDeclarations; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.StringUtils; + +class ResolverFacade { + + static ResolverFacade create(Class clazz, List fields) { + Preconditions.notEmpty(fields, "Fields must not be empty"); + + NavigableMap> allIndexedParameters = new TreeMap<>(); + Set aggregatorParameters = new LinkedHashSet<>(); + + for (Field field : fields) { + Parameter annotation = findAnnotation(field, Parameter.class) // + .orElseThrow(() -> new JUnitException("No @Parameter annotation present")); + int index = annotation.value(); + + FieldParameterDeclaration declaration = new FieldParameterDeclaration(field, annotation.value()); + if (declaration.isAggregator()) { + aggregatorParameters.add(declaration); + } + else { + if (fields.size() == 1 && index == Parameter.UNSET_INDEX) { + index = 0; + declaration = new FieldParameterDeclaration(field, 0); + } + allIndexedParameters.computeIfAbsent(index, __ -> new ArrayList<>()) // + .add(declaration); + } + } + + NavigableMap uniqueIndexedParameters = validateFieldDeclarations( + allIndexedParameters, aggregatorParameters); + + Stream.concat(uniqueIndexedParameters.values().stream(), aggregatorParameters.stream()) // + .forEach(declaration -> makeAccessible(declaration.getField())); + + RequiredParameterCount requiredParameterCount = new RequiredParameterCount(uniqueIndexedParameters.size(), + "field injection"); + + return new ResolverFacade(clazz, uniqueIndexedParameters, aggregatorParameters, 0, requiredParameterCount); + } + + static ResolverFacade create(Constructor constructor, ParameterizedClass annotation) { + // Inner classes get the outer instance as first (implicit) parameter + int implicitParameters = isInnerClass(constructor.getDeclaringClass()) ? 1 : 0; + return create(constructor, annotation, implicitParameters); + } + + static ResolverFacade create(Method method, Annotation annotation) { + return create(method, annotation, 0); + } + + /** + * Create a new {@link ResolverFacade} for the supplied {@link Executable}. + * + *

This method takes a best-effort approach at enforcing the following + * policy for parameterized class constructors and parameterized test + * methods that accept aggregators as arguments. + *

    + *
  1. zero or more indexed arguments come first.
  2. + *
  3. zero or more aggregators come next.
  4. + *
  5. zero or more arguments supplied by other {@code ParameterResolver} + * implementations come last.
  6. + *
+ */ + private static ResolverFacade create(Executable executable, Annotation annotation, int indexOffset) { + NavigableMap indexedParameters = new TreeMap<>(); + NavigableMap aggregatorParameters = new TreeMap<>(); + java.lang.reflect.Parameter[] parameters = executable.getParameters(); + for (int index = indexOffset; index < parameters.length; index++) { + ExecutableParameterDeclaration declaration = new ExecutableParameterDeclaration(parameters[index], index, + indexOffset); + if (declaration.isAggregator()) { + Preconditions.condition( + aggregatorParameters.isEmpty() + || aggregatorParameters.lastKey() == declaration.getParameterIndex() - 1, + () -> String.format( + "@%s %s declares formal parameters in an invalid order: " + + "argument aggregators must be declared after any indexed arguments " + + "and before any arguments resolved by another ParameterResolver.", + annotation.annotationType().getSimpleName(), + DefaultParameterDeclarations.describe(executable))); + aggregatorParameters.put(declaration.getParameterIndex(), declaration); + } + else if (aggregatorParameters.isEmpty()) { + indexedParameters.put(declaration.getParameterIndex(), declaration); + } + } + return new ResolverFacade(executable, indexedParameters, new LinkedHashSet<>(aggregatorParameters.values()), + indexOffset, null); + } + + private final int parameterIndexOffset; + private final Map resolvers; + private final DefaultParameterDeclarations indexedParameterDeclarations; + private final Set aggregatorParameters; + private final RequiredParameterCount requiredParameterCount; + + private ResolverFacade(AnnotatedElement sourceElement, + NavigableMap indexedParameters, + Set aggregatorParameters, int parameterIndexOffset, + RequiredParameterCount requiredParameterCount) { + this.aggregatorParameters = aggregatorParameters; + this.parameterIndexOffset = parameterIndexOffset; + this.resolvers = new ConcurrentHashMap<>(indexedParameters.size() + aggregatorParameters.size()); + this.indexedParameterDeclarations = new DefaultParameterDeclarations(sourceElement, indexedParameters); + this.requiredParameterCount = requiredParameterCount; + } + + ParameterDeclarations getIndexedParameterDeclarations() { + return this.indexedParameterDeclarations; + } + + RequiredParameterCount getRequiredParameterCount() { + return this.requiredParameterCount; + } + + boolean isSupportedParameter(ParameterContext parameterContext, EvaluatedArgumentSet arguments) { + int index = toLogicalIndex(parameterContext); + if (this.indexedParameterDeclarations.get(index).isPresent()) { + return index < arguments.getConsumedLength(); + } + return !this.aggregatorParameters.isEmpty() + && this.aggregatorParameters.stream().anyMatch(it -> it.getParameterIndex() == index); + } + + /** + * Get the name of the parameter with the supplied index, if it is present + * and declared before the aggregators. + * + * @return an {@code Optional} containing the name of the parameter + */ + Optional getParameterName(int parameterIndex) { + return this.indexedParameterDeclarations.get(parameterIndex) // + .flatMap(ParameterDeclaration::getParameterName); + } + + /** + * Determine the length of the arguments array that is considered consumed + * by the parameter declarations in this resolver. + * + *

If an aggregator is present, all arguments are considered consumed. + * Otherwise, the consumed argument length is the minimum of the total + * length and the number of indexed parameter declarations. + */ + int determineConsumedArgumentLength(int totalLength) { + NavigableMap declarationsByIndex = this.indexedParameterDeclarations.declarationsByIndex; + return this.aggregatorParameters.isEmpty() // + ? Math.min(totalLength, declarationsByIndex.isEmpty() ? 0 : declarationsByIndex.lastKey() + 1) // + : totalLength; + } + + /** + * Determine the number of arguments that are considered consumed by the + * parameter declarations in this resolver. + * + *

If an aggregator is present, all arguments are considered consumed. + * Otherwise, the consumed argument count, is the number of indexes that + * correspond to indexed parameter declarations. + */ + int determineConsumedArgumentCount(EvaluatedArgumentSet arguments) { + if (this.aggregatorParameters.isEmpty()) { + return this.indexedParameterDeclarations.declarationsByIndex.subMap(0, + arguments.getConsumedLength()).size(); + } + return arguments.getTotalLength(); + } + + ArgumentSetLifecycleMethod.ParameterResolver createLifecycleMethodParameterResolver(Method method, + Annotation annotation) { + ResolverFacade originalResolverFacade = this; + ResolverFacade lifecycleMethodResolverFacade = create(method, annotation); + + Map parameterDeclarationMapping = new HashMap<>(); + List errors = validateLifecycleMethodParameters(method, annotation, originalResolverFacade, + lifecycleMethodResolverFacade, parameterDeclarationMapping); + + return Try // + .call(() -> configurationErrorOrSuccess(errors, + () -> new DefaultArgumentSetLifecycleMethodParameterResolver(originalResolverFacade, + lifecycleMethodResolverFacade, parameterDeclarationMapping))) // + .getOrThrow(cause -> new ExtensionConfigurationException( + String.format("Invalid @%s lifecycle method declaration: %s", + annotation.annotationType().getSimpleName(), method.toGenericString()), + cause)); + } + + /** + * Resolve the parameter for the supplied context using the supplied + * arguments. + */ + Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext, EvaluatedArgumentSet arguments, + int invocationIndex, ResolutionCache resolutionCache) { + + int parameterIndex = toLogicalIndex(parameterContext); + ResolvableParameterDeclaration declaration = findDeclaration(parameterIndex) // + .orElseThrow( + () -> new ParameterResolutionException("Parameter index out of bounds: " + parameterIndex)); + + return resolutionCache.resolve(declaration, + () -> resolve(declaration, extensionContext, arguments, invocationIndex, Optional.of(parameterContext))); + } + + private Optional findDeclaration(int parameterIndex) { + ResolvableParameterDeclaration declaration = this.indexedParameterDeclarations.declarationsByIndex // + .get(parameterIndex); + if (declaration == null) { + return this.aggregatorParameters.stream() // + .filter(it -> it.getParameterIndex() == parameterIndex) // + .findFirst(); + } + return Optional.of(declaration); + } + + void resolveAndInjectFields(Object testInstance, ExtensionContext extensionContext, EvaluatedArgumentSet arguments, + int invocationIndex, ResolutionCache resolutionCache) { + + if (this.indexedParameterDeclarations.sourceElement.equals(testInstance.getClass())) { + getAllParameterDeclarations() // + .filter(FieldParameterDeclaration.class::isInstance) // + .map(FieldParameterDeclaration.class::cast) // + .forEach(declaration -> setField(testInstance, declaration, extensionContext, arguments, + invocationIndex, resolutionCache)); + } + } + + private Stream getAllParameterDeclarations() { + return Stream.concat(this.indexedParameterDeclarations.declarationsByIndex.values().stream(), + aggregatorParameters.stream()); + } + + private void setField(Object testInstance, FieldParameterDeclaration declaration, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache) { + + Object argument = resolutionCache.resolve(declaration, + () -> resolve(declaration, extensionContext, arguments, invocationIndex, Optional.empty())); + try { + declaration.getField().set(testInstance, argument); + } + catch (Exception e) { + throw new JUnitException("Failed to inject parameter value into field: " + declaration.getField(), e); + } + } + + private Object resolve(ResolvableParameterDeclaration parameterDeclaration, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex, Optional parameterContext) { + Resolver resolver = getResolver(extensionContext, parameterDeclaration); + return parameterDeclaration.resolve(resolver, extensionContext, arguments, invocationIndex, parameterContext); + } + + private Resolver getResolver(ExtensionContext extensionContext, ResolvableParameterDeclaration declaration) { + return this.resolvers.computeIfAbsent(declaration, __ -> this.aggregatorParameters.contains(declaration) // + ? createAggregator(declaration, extensionContext) // + : createConverter(declaration, extensionContext)); + } + + private int toLogicalIndex(ParameterContext parameterContext) { + int index = parameterContext.getIndex() - this.parameterIndexOffset; + Preconditions.condition(index >= 0, () -> "Parameter index must be greater than or equal to zero"); + return index; + } + + private static NavigableMap validateFieldDeclarations( + NavigableMap> indexedParameters, + Set aggregatorParameters) { + + List errors = new ArrayList<>(); + validateIndexedParameters(indexedParameters, errors); + validateAggregatorParameters(aggregatorParameters, errors); + + return configurationErrorOrSuccess(errors, () -> indexedParameters.entrySet().stream() // + .collect(toMap(Map.Entry::getKey, entry -> entry.getValue().get(0), (d, __) -> d, TreeMap::new))); + } + + private static List validateLifecycleMethodParameters(Method method, Annotation annotation, + ResolverFacade originalResolverFacade, ResolverFacade lifecycleMethodResolverFacade, + Map parameterDeclarationMapping) { + List actualDeclarations = lifecycleMethodResolverFacade.indexedParameterDeclarations.getAll(); + List errors = new ArrayList<>(); + for (int parameterIndex = 0; parameterIndex < actualDeclarations.size(); parameterIndex++) { + ParameterDeclaration actualDeclaration = actualDeclarations.get(parameterIndex); + ResolvableParameterDeclaration originalDeclaration = originalResolverFacade.indexedParameterDeclarations.declarationsByIndex // + .get(parameterIndex); + if (originalDeclaration == null) { + break; + } + if (!actualDeclaration.getParameterType().equals(originalDeclaration.getParameterType())) { + errors.add(String.format( + "parameter%s with index %d is incompatible with the parameter declared on the parameterized class: expected type '%s' but found '%s'", + parameterName(actualDeclaration), parameterIndex, originalDeclaration.getParameterType(), + actualDeclaration.getParameterType())); + } + else if (findAnnotation(actualDeclaration.getAnnotatedElement(), ConvertWith.class).isPresent()) { + errors.add(String.format("parameter%s with index %d must not be annotated with @ConvertWith", + parameterName(actualDeclaration), parameterIndex)); + } + else if (errors.isEmpty()) { + parameterDeclarationMapping.put(actualDeclaration, originalDeclaration); + } + } + return errors; + } + + private static String parameterName(ParameterDeclaration actualDeclaration) { + return actualDeclaration.getParameterName().map(name -> " '" + name + "'").orElse(""); + } + + private static T configurationErrorOrSuccess(List errors, Supplier successfulResult) { + if (errors.isEmpty()) { + return successfulResult.get(); + } + else if (errors.size() == 1) { + throw new PreconditionViolationException("Configuration error: " + errors.get(0) + "."); + } + else { + throw new PreconditionViolationException(String.format("%d configuration errors:%n%s", errors.size(), + errors.stream().collect(joining(lineSeparator() + "- ", "- ", "")))); + } + } + + private static void validateIndexedParameters( + NavigableMap> indexedParameters, List errors) { + + if (indexedParameters.isEmpty()) { + return; + } + + indexedParameters.forEach( + (index, declarations) -> validateIndexedParameterDeclarations(index, declarations, errors)); + + for (int index = 0; index <= indexedParameters.lastKey(); index++) { + if (!indexedParameters.containsKey(index)) { + errors.add(String.format("no field annotated with @Parameter(%d) declared", index)); + } + } + } + + private static void validateIndexedParameterDeclarations(int index, List declarations, + List errors) { + List fields = declarations.stream().map(FieldParameterDeclaration::getField).collect(toList()); + if (index < 0) { + declarations.stream() // + .map(declaration -> String.format( + "index must be greater than or equal to zero in @Parameter(%d) annotation on field [%s]", index, + declaration.getField())) // + .forEach(errors::add); + } + else if (declarations.size() > 1) { + errors.add( + String.format("duplicate index declared in @Parameter(%d) annotation on fields %s", index, fields)); + } + fields.stream() // + .filter(ModifierSupport::isFinal) // + .map(field -> String.format("@Parameter field [%s] must not be declared as final", field)) // + .forEach(errors::add); + } + + private static void validateAggregatorParameters(Set aggregatorParameters, + List errors) { + aggregatorParameters.stream() // + .filter(declaration -> declaration.getParameterIndex() != Parameter.UNSET_INDEX) // + .map(declaration -> String.format( + "no index may be declared in @Parameter(%d) annotation on aggregator field [%s]", + declaration.getParameterIndex(), declaration.getField())) // + .forEach(errors::add); + } + + private static Converter createConverter(ParameterDeclaration declaration, ExtensionContext extensionContext) { + try { // @formatter:off + return findAnnotation(declaration.getAnnotatedElement(), ConvertWith.class) + .map(ConvertWith::value) + .map(clazz -> ParameterizedTestSpiInstantiator.instantiate(ArgumentConverter.class, clazz, extensionContext)) + .map(converter -> AnnotationConsumerInitializer.initialize(declaration.getAnnotatedElement(), converter)) + .map(Converter::new) + .orElseGet(() -> Converter.createDefault(extensionContext)); + } // @formatter:on + catch (Exception ex) { + throw parameterResolutionException("Error creating ArgumentConverter", ex, declaration.getParameterIndex()); + } + } + + private static Aggregator createAggregator(ParameterDeclaration declaration, ExtensionContext extensionContext) { + try { // @formatter:off + return findAnnotation(declaration.getAnnotatedElement(), AggregateWith.class) + .map(AggregateWith::value) + .map(clazz -> ParameterizedTestSpiInstantiator.instantiate(ArgumentsAggregator.class, clazz, extensionContext)) + .map(Aggregator::new) + .orElse(Aggregator.DEFAULT); + } // @formatter:on + catch (Exception ex) { + throw parameterResolutionException("Error creating ArgumentsAggregator", ex, + declaration.getParameterIndex()); + } + } + + private static ParameterResolutionException parameterResolutionException(String message, Exception cause, + int index) { + String fullMessage = message + " at index " + index; + if (StringUtils.isNotBlank(cause.getMessage())) { + fullMessage += ": " + cause.getMessage(); + } + return new ParameterResolutionException(fullMessage, cause); + } + + private interface Resolver { + + Object resolve(ParameterContext parameterContext, int parameterIndex, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex); + + Object resolve(FieldContext fieldContext, ExtensionContext extensionContext, EvaluatedArgumentSet arguments, + int invocationIndex); + + } + + private static class Converter implements Resolver { + + private final ArgumentConverter argumentConverter; + + private static Converter createDefault(ExtensionContext context) { + return new Converter(new DefaultArgumentConverter(context)); + } + + Converter(ArgumentConverter argumentConverter) { + this.argumentConverter = argumentConverter; + } + + @Override + public Object resolve(ParameterContext parameterContext, int parameterIndex, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex) { + Object argument = arguments.getConsumedPayload(parameterIndex); + try { + return this.argumentConverter.convert(argument, parameterContext); + } + catch (Exception ex) { + throw parameterResolutionException("Error converting parameter", ex, parameterContext.getIndex()); + } + } + + @Override + public Object resolve(FieldContext fieldContext, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex) { + + Object argument = arguments.getConsumedPayload(fieldContext.getParameterIndex()); + try { + return this.argumentConverter.convert(argument, fieldContext); + } + catch (Exception ex) { + throw parameterResolutionException("Error converting parameter", ex, fieldContext.getParameterIndex()); + } + } + } + + private static class Aggregator implements Resolver { + + private static final Aggregator DEFAULT = new Aggregator(new SimpleArgumentsAggregator() { + @Override + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException { + return accessor; + } + }); + + private final ArgumentsAggregator argumentsAggregator; + + Aggregator(ArgumentsAggregator argumentsAggregator) { + this.argumentsAggregator = argumentsAggregator; + } + + @Override + public Object resolve(ParameterContext parameterContext, int parameterIndex, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex) { + ArgumentsAccessor accessor = ParameterInfo.get(extensionContext).getArguments(); + try { + return this.argumentsAggregator.aggregateArguments(accessor, parameterContext); + } + catch (Exception ex) { + throw parameterResolutionException("Error aggregating arguments for parameter", ex, + parameterContext.getIndex()); + } + } + + @Override + public Object resolve(FieldContext fieldContext, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex) { + ArgumentsAccessor accessor = ParameterInfo.get(extensionContext).getArguments(); + try { + return this.argumentsAggregator.aggregateArguments(accessor, fieldContext); + } + catch (Exception ex) { + throw parameterResolutionException("Error aggregating arguments for parameter", ex, + fieldContext.getParameterIndex()); + } + } + } + + private static class DefaultParameterDeclarations implements ParameterDeclarations { + + private final AnnotatedElement sourceElement; + private final NavigableMap declarationsByIndex; + + DefaultParameterDeclarations(AnnotatedElement sourceElement, + NavigableMap declarationsByIndex) { + this.sourceElement = sourceElement; + this.declarationsByIndex = declarationsByIndex; + } + + @Override + public AnnotatedElement getSourceElement() { + return this.sourceElement; + } + + @Override + public Optional getFirst() { + return this.declarationsByIndex.isEmpty() // + ? Optional.empty() // + : Optional.of(this.declarationsByIndex.firstEntry().getValue()); + } + + @Override + public List getAll() { + return unmodifiableList(new ArrayList<>(this.declarationsByIndex.values())); + } + + @Override + public Optional get(int parameterIndex) { + return Optional.ofNullable(this.declarationsByIndex.get(parameterIndex)); + } + + @Override + public String getSourceElementDescription() { + return describe(this.sourceElement); + } + + static String describe(AnnotatedElement sourceElement) { + if (sourceElement instanceof Method) { + return String.format("method [%s]", ((Method) sourceElement).toGenericString()); + } + if (sourceElement instanceof Constructor) { + return String.format("constructor [%s]", ((Constructor) sourceElement).toGenericString()); + } + if (sourceElement instanceof Class) { + return String.format("class [%s]", ((Class) sourceElement).getName()); + } + return sourceElement.toString(); + } + } + + private abstract static class ResolvableParameterDeclaration implements ParameterDeclaration { + + /** + * Determine if the supplied {@link Parameter} is an aggregator (i.e., of + * type {@link ArgumentsAccessor} or annotated with {@link AggregateWith}). + * + * @return {@code true} if the parameter is an aggregator + */ + boolean isAggregator() { + return ArgumentsAccessor.class.isAssignableFrom(getParameterType()) + || isAnnotated(getAnnotatedElement(), AggregateWith.class); + } + + protected abstract Object resolve(Resolver resolver, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex, + Optional originalParameterContext); + } + + private static class FieldParameterDeclaration extends ResolvableParameterDeclaration implements FieldContext { + + private final Field field; + private final int index; + + FieldParameterDeclaration(Field field, int index) { + this.field = field; + this.index = index; + } + + @Override + public Field getField() { + return this.field; + } + + @Override + public Field getAnnotatedElement() { + return this.field; + } + + @Override + public Class getParameterType() { + return this.field.getType(); + } + + @Override + public int getParameterIndex() { + return index; + } + + @Override + public Optional getParameterName() { + return Optional.of(this.field.getName()); + } + + @Override + public Object resolve(Resolver resolver, ExtensionContext extensionContext, EvaluatedArgumentSet arguments, + int invocationIndex, Optional originalParameterContext) { + return resolver.resolve(this, extensionContext, arguments, invocationIndex); + } + } + + private static class ExecutableParameterDeclaration extends ResolvableParameterDeclaration { + + private final java.lang.reflect.Parameter parameter; + private final int index; + private final int indexOffset; + + ExecutableParameterDeclaration(java.lang.reflect.Parameter parameter, int index, int indexOffset) { + this.parameter = parameter; + this.index = index; + this.indexOffset = indexOffset; + } + + @Override + public java.lang.reflect.Parameter getAnnotatedElement() { + return this.parameter; + } + + @Override + public Class getParameterType() { + return this.parameter.getType(); + } + + @Override + public int getParameterIndex() { + return this.index - this.indexOffset; + } + + @Override + public Optional getParameterName() { + return this.parameter.isNamePresent() ? Optional.of(this.parameter.getName()) : Optional.empty(); + } + + @Override + public Object resolve(Resolver resolver, ExtensionContext extensionContext, EvaluatedArgumentSet arguments, + int invocationIndex, Optional originalParameterContext) { + ParameterContext parameterContext = originalParameterContext // + .filter(it -> it.getParameter().equals(this.parameter)) // + .orElseGet(() -> toParameterContext(extensionContext, originalParameterContext)); + return resolver.resolve(parameterContext, getParameterIndex(), extensionContext, arguments, + invocationIndex); + } + + private ParameterContext toParameterContext(ExtensionContext extensionContext, + Optional originalParameterContext) { + Optional target = originalParameterContext.flatMap(ParameterContext::getTarget); + if (!target.isPresent()) { + target = extensionContext.getTestInstance(); + } + return toParameterContext(target); + } + + private ParameterContext toParameterContext(Optional target) { + return new ParameterContext() { + @Override + public java.lang.reflect.Parameter getParameter() { + return ExecutableParameterDeclaration.this.parameter; + } + + @Override + public int getIndex() { + return ExecutableParameterDeclaration.this.index; + } + + @Override + public Optional getTarget() { + return target; + } + }; + } + } + + private static class DefaultArgumentSetLifecycleMethodParameterResolver + implements ArgumentSetLifecycleMethod.ParameterResolver { + + private final ResolverFacade originalResolverFacade; + private final ResolverFacade lifecycleMethodResolverFacade; + private final Map parameterDeclarationMapping; + + DefaultArgumentSetLifecycleMethodParameterResolver(ResolverFacade originalResolverFacade, + ResolverFacade lifecycleMethodResolverFacade, + Map parameterDeclarationMapping) { + this.originalResolverFacade = originalResolverFacade; + this.lifecycleMethodResolverFacade = lifecycleMethodResolverFacade; + this.parameterDeclarationMapping = parameterDeclarationMapping; + } + + @Override + public boolean supports(ParameterContext parameterContext) { + return this.lifecycleMethodResolverFacade.findDeclaration(parameterContext.getIndex()) // + .filter(it -> this.parameterDeclarationMapping.containsKey(it) || it.isAggregator()) // + .isPresent(); + } + + @Override + public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext, + EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache) { + + ResolvableParameterDeclaration actualDeclaration = this.lifecycleMethodResolverFacade // + .findDeclaration(parameterContext.getIndex()) // + .orElseThrow(() -> new ParameterResolutionException( + "Parameter index out of bounds: " + parameterContext.getIndex())); + + ResolvableParameterDeclaration originalDeclaration = this.parameterDeclarationMapping // + .get(actualDeclaration); + if (originalDeclaration == null) { + return this.lifecycleMethodResolverFacade.resolve(actualDeclaration, extensionContext, arguments, + invocationIndex, Optional.of(parameterContext)); + } + return resolutionCache.resolve(originalDeclaration, + () -> this.originalResolverFacade.resolve(originalDeclaration, extensionContext, arguments, + invocationIndex, Optional.of(parameterContext))); + } + } + + static class RequiredParameterCount { + private final int value; + private final String reason; + + RequiredParameterCount(int value, String reason) { + this.value = value; + this.reason = reason; + } + + int value() { + return value; + } + + String reason() { + return reason; + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/AggregateWith.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/AggregateWith.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/AggregateWith.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/AggregateWith.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -24,10 +24,14 @@ * {@code @AggregateWith} is an annotation that allows one to specify an * {@link ArgumentsAggregator}. * - *

This annotation may be applied to a parameter of a + *

This annotation may be applied to parameters of a + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} + * constructor or its + * {@link org.junit.jupiter.params.Parameter @Parameter}-annotated fields, or to + * parameters of a * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest} method * in order for an aggregated value to be resolved for the annotated parameter - * when the test method is invoked. + * when the parameterized class or method is invoked. * *

{@code @AggregateWith} may also be used as a meta-annotation in order to * create a custom composed annotation that inherits the semantics @@ -38,7 +42,7 @@ * @see org.junit.jupiter.params.ParameterizedTest */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.PARAMETER, ElementType.FIELD }) @Documented @API(status = STABLE, since = "5.7") public @interface AggregateWith { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentAccessException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentAccessException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentAccessException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentAccessException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAccessor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAccessor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAccessor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAccessor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregationException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregationException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregationException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregationException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,14 @@ package org.junit.jupiter.params.aggregator; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.params.support.FieldContext; +import org.junit.platform.commons.JUnitException; /** * {@code ArgumentsAggregator} is an abstraction for the aggregation of arguments @@ -33,14 +37,16 @@ * in a CSV file into a domain object such as a {@code Person}, {@code Address}, * {@code Order}, etc. * - *

Implementations must provide a no-args constructor and should not make any - * assumptions regarding when they are instantiated or how often they are called. - * Since instances may potentially be cached and called from different threads, - * they should be thread-safe and designed to be used as singletons. + *

Implementations must provide a no-args constructor or a single unambiguous + * constructor to use {@linkplain ParameterResolver parameter resolution}. They + * should not make any assumptions regarding when they are instantiated or how + * often they are called. Since instances may potentially be cached and called + * from different threads, they should be thread-safe. * * @since 5.2 * @see AggregateWith * @see ArgumentsAccessor + * @see SimpleArgumentsAggregator * @see org.junit.jupiter.params.ParameterizedTest */ @API(status = STABLE, since = "5.7") @@ -62,4 +68,27 @@ Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) throws ArgumentsAggregationException; + /** + * Aggregate the arguments contained in the supplied {@code accessor} into a + * single object. + * + * @param accessor an {@link ArgumentsAccessor} containing the arguments to be + * aggregated; never {@code null} + * @param context the field context where the aggregated result is to be + * injected; never {@code null} + * @return the aggregated result; may be {@code null} but only if the target + * type is a reference type + * @throws ArgumentsAggregationException if an error occurs during the + * aggregation + * @since 5.13 + */ + @API(status = MAINTAINED, since = "5.13.3") + default Object aggregateArguments(ArgumentsAccessor accessor, FieldContext context) + throws ArgumentsAggregationException { + throw new JUnitException( + String.format("ArgumentsAggregator does not override the convert(ArgumentsAccessor, FieldContext) method. " + + "Please report this issue to the maintainers of %s.", + getClass().getName())); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessor.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessor.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,9 +16,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.BiFunction; import org.apiguardian.api.API; -import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.converter.DefaultArgumentConverter; import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.Preconditions; @@ -36,17 +37,25 @@ @API(status = INTERNAL, since = "5.2") public class DefaultArgumentsAccessor implements ArgumentsAccessor { - private final ParameterContext parameterContext; private final int invocationIndex; private final Object[] arguments; + private final BiFunction, Object> converter; - public DefaultArgumentsAccessor(ParameterContext parameterContext, int invocationIndex, Object... arguments) { - Preconditions.notNull(parameterContext, "ParameterContext must not be null"); - Preconditions.condition(invocationIndex >= 1, () -> "invocation index must be >= 1"); - Preconditions.notNull(arguments, "Arguments array must not be null"); - this.parameterContext = parameterContext; + public static DefaultArgumentsAccessor create(ExtensionContext context, int invocationIndex, + ClassLoader classLoader, Object[] arguments) { + Preconditions.notNull(classLoader, "ClassLoader must not be null"); + + BiFunction, Object> converter = (source, targetType) -> new DefaultArgumentConverter(context) // + .convert(source, targetType, classLoader); + return new DefaultArgumentsAccessor(converter, invocationIndex, arguments); + } + + private DefaultArgumentsAccessor(BiFunction, Object> converter, int invocationIndex, + Object... arguments) { + Preconditions.condition(invocationIndex >= 1, () -> "Invocation index must be >= 1"); + this.converter = Preconditions.notNull(converter, "Converter must not be null"); this.invocationIndex = invocationIndex; - this.arguments = arguments; + this.arguments = Preconditions.notNull(arguments, "Arguments array must not be null"); } @Override @@ -61,8 +70,7 @@ Preconditions.notNull(requiredType, "requiredType must not be null"); Object value = get(index); try { - Object convertedValue = DefaultArgumentConverter.INSTANCE.convert(value, requiredType, - this.parameterContext); + Object convertedValue = converter.apply(value, requiredType); return requiredType.cast(convertedValue); } catch (Exception ex) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/SimpleArgumentsAggregator.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/SimpleArgumentsAggregator.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/SimpleArgumentsAggregator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/SimpleArgumentsAggregator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params.aggregator; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.AnnotatedElementContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.support.FieldContext; + +/** + * {@code SimpleArgumentsAggregator} is an abstract base class for + * {@link ArgumentsAggregator} implementations that do not need to distinguish + * between fields and method/constructor parameters. + * + * @since 5.0 + * @see ArgumentsAggregator + */ +@API(status = MAINTAINED, since = "5.13.3") +public abstract class SimpleArgumentsAggregator implements ArgumentsAggregator { + + public SimpleArgumentsAggregator() { + } + + @Override + public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) + throws ArgumentsAggregationException { + return aggregateArguments(accessor, context.getParameter().getType(), context, context.getIndex()); + } + + @Override + public Object aggregateArguments(ArgumentsAccessor accessor, FieldContext context) + throws ArgumentsAggregationException { + return aggregateArguments(accessor, context.getField().getType(), context, context.getParameterIndex()); + } + + protected abstract Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException; +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/AnnotationBasedArgumentConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/AnnotationBasedArgumentConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/AnnotationBasedArgumentConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/AnnotationBasedArgumentConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,13 +10,14 @@ package org.junit.jupiter.params.converter; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Annotation; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.params.support.AnnotationConsumer; +import org.junit.jupiter.params.support.FieldContext; import org.junit.platform.commons.util.Preconditions; /** @@ -29,7 +30,7 @@ * @see AnnotationConsumer * @see SimpleArgumentConverter */ -@API(status = EXPERIMENTAL, since = "5.10") +@API(status = MAINTAINED, since = "5.13.3") public abstract class AnnotationBasedArgumentConverter implements ArgumentConverter, AnnotationConsumer { @@ -49,6 +50,11 @@ return convert(source, context.getParameter().getType(), this.annotation); } + @Override + public final Object convert(Object source, FieldContext context) throws ArgumentConversionException { + return convert(source, context.getField().getType(), this.annotation); + } + /** * Convert the supplied {@code source} object into the supplied {@code targetType}, * based on metadata in the provided annotation. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConversionException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConversionException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConversionException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConversionException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,14 @@ package org.junit.jupiter.params.converter; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.params.support.FieldContext; +import org.junit.platform.commons.JUnitException; /** * {@code ArgumentConverter} is an abstraction that allows an input object to @@ -21,13 +25,18 @@ * *

Such an {@code ArgumentConverter} is applied to the method parameter * of a {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest} - * method with the help of a - * {@link org.junit.jupiter.params.converter.ConvertWith @ConvertWith} annotation. - * - *

Implementations must provide a no-args constructor and should not make any - * assumptions regarding when they are instantiated or how often they are called. - * Since instances may potentially be cached and called from different threads, - * they should be thread-safe and designed to be used as singletons. + * or a constructor parameter or + * {@link org.junit.jupiter.params.Parameter @Parameter}-annotated field of a + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} with + * the help of a + * {@link org.junit.jupiter.params.converter.ConvertWith @ConvertWith} + * annotation. + * + *

Implementations must provide a no-args constructor or a single unambiguous + * constructor to use {@linkplain ParameterResolver parameter resolution}. They + * should not make any assumptions regarding when they are instantiated or how + * often they are called. Since instances may potentially be cached and called + * from different threads, they should be thread-safe. * *

Extend {@link SimpleArgumentConverter} if your implementation only needs * to know the target type and does not need access to the {@link ParameterContext} @@ -38,7 +47,6 @@ * the {@link ParameterContext} to perform the conversion. * * @since 5.0 - * @see SimpleArgumentConverter * @see org.junit.jupiter.params.ParameterizedTest * @see org.junit.jupiter.params.converter.ConvertWith * @see org.junit.jupiter.params.support.AnnotationConsumer @@ -54,7 +62,7 @@ * * @param source the source object to convert; may be {@code null} * @param context the parameter context where the converted object will be - * used; never {@code null} + * supplied; never {@code null} * @return the converted object; may be {@code null} but only if the target * type is a reference type * @throws ArgumentConversionException if an error occurs during the @@ -62,4 +70,24 @@ */ Object convert(Object source, ParameterContext context) throws ArgumentConversionException; + /** + * Convert the supplied {@code source} object according to the supplied + * {@code context}. + * + * @param source the source object to convert; may be {@code null} + * @param context the field context where the converted object will be + * injected; never {@code null} + * @return the converted object; may be {@code null} but only if the target + * type is a reference type + * @throws ArgumentConversionException if an error occurs during the + * conversion + * @since 5.13 + */ + @API(status = MAINTAINED, since = "5.13.3") + default Object convert(Object source, FieldContext context) throws ArgumentConversionException { + throw new JUnitException( + String.format("ArgumentConverter does not override the convert(Object, FieldContext) method. " + + "Please report this issue to the maintainers of %s.", + getClass().getName())); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ConvertWith.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ConvertWith.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ConvertWith.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ConvertWith.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -23,16 +23,20 @@ /** * {@code @ConvertWith} is an annotation that allows one to specify an explicit * {@link ArgumentConverter}. - - *

This annotation may be applied to parameters of - * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest} methods + * + *

This annotation may be applied to parameters of a + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} + * constructor or its + * {@link org.junit.jupiter.params.Parameter @Parameter}-annotated fields, or to + * parameters of a + * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest} method * which need to have their {@code Arguments} converted before consuming them. * * @since 5.0 * @see org.junit.jupiter.params.ParameterizedTest * @see org.junit.jupiter.params.converter.ArgumentConverter */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.PARAMETER }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.PARAMETER, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Documented @API(status = STABLE, since = "5.7") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.jupiter.params.converter; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.util.ClassLoaderUtils.getClassLoader; import java.io.File; import java.math.BigDecimal; @@ -20,12 +21,14 @@ import java.util.Currency; import java.util.Locale; import java.util.UUID; +import java.util.function.Function; import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.support.FieldContext; import org.junit.platform.commons.support.conversion.ConversionException; import org.junit.platform.commons.support.conversion.ConversionSupport; -import org.junit.platform.commons.util.ClassLoaderUtils; import org.junit.platform.commons.util.ReflectionUtils; /** @@ -49,19 +52,48 @@ @API(status = INTERNAL, since = "5.0") public class DefaultArgumentConverter implements ArgumentConverter { - public static final DefaultArgumentConverter INSTANCE = new DefaultArgumentConverter(); + /** + * Property name used to set the format for the conversion of {@link Locale} + * arguments: {@value} + * + *

Supported Values

+ *
    + *
  • {@code bcp_47}: uses the IETF BCP 47 language tag format, delegating + * the conversion to {@link Locale#forLanguageTag(String)}
  • + *
  • {@code iso_639}: uses the ISO 639 alpha-2 or alpha-3 language code + * format, delegating the conversion to {@link Locale#Locale(String)}
  • + *
+ * + *

If not specified, the default is {@code bcp_47}. + * + * @since 5.13 + */ + public static final String DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME = "junit.jupiter.params.arguments.conversion.locale.format"; - private DefaultArgumentConverter() { - // nothing to initialize + private static final Function TRANSFORMER = value -> LocaleConversionFormat.valueOf( + value.trim().toUpperCase(Locale.ROOT)); + + private final ExtensionContext context; + + public DefaultArgumentConverter(ExtensionContext context) { + this.context = context; } @Override public final Object convert(Object source, ParameterContext context) { Class targetType = context.getParameter().getType(); - return convert(source, targetType, context); + ClassLoader classLoader = getClassLoader(context.getDeclaringExecutable().getDeclaringClass()); + return convert(source, targetType, classLoader); + } + + @Override + public final Object convert(Object source, FieldContext context) throws ArgumentConversionException { + Class targetType = context.getField().getType(); + ClassLoader classLoader = getClassLoader(context.getField().getDeclaringClass()); + return convert(source, targetType, classLoader); } - public final Object convert(Object source, Class targetType, ParameterContext context) { + public final Object convert(Object source, Class targetType, ClassLoader classLoader) { if (source == null) { if (targetType.isPrimitive()) { throw new ArgumentConversionException( @@ -75,10 +107,12 @@ } if (source instanceof String) { - Class declaringClass = context.getDeclaringExecutable().getDeclaringClass(); - ClassLoader classLoader = ClassLoaderUtils.getClassLoader(declaringClass); + if (targetType == Locale.class && getLocaleConversionFormat() == LocaleConversionFormat.BCP_47) { + return Locale.forLanguageTag((String) source); + } + try { - return ConversionSupport.convert((String) source, targetType, classLoader); + return convert((String) source, targetType, classLoader); } catch (ConversionException ex) { throw new ArgumentConversionException(ex.getMessage(), ex); @@ -90,4 +124,21 @@ source.getClass().getTypeName(), targetType.getTypeName())); } + private LocaleConversionFormat getLocaleConversionFormat() { + return context.getConfigurationParameter(DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME, TRANSFORMER) // + .orElse(LocaleConversionFormat.BCP_47); + } + + Object convert(String source, Class targetType, ClassLoader classLoader) { + return ConversionSupport.convert(source, targetType, classLoader); + } + + enum LocaleConversionFormat { + + BCP_47, + + ISO_639 + + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -52,7 +52,11 @@ @Override protected Object convert(Object input, Class targetClass, JavaTimeConversionPattern annotation) { if (input == null) { - throw new ArgumentConversionException("Cannot convert null to " + targetClass.getName()); + if (annotation.nullable()) { + return null; + } + throw new ArgumentConversionException( + "Cannot convert null to " + targetClass.getName() + "; consider setting 'nullable = true'"); } TemporalQuery temporalQuery = TEMPORAL_QUERIES.get(targetClass); if (temporalQuery == null) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeConversionPattern.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeConversionPattern.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeConversionPattern.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeConversionPattern.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.params.converter; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -19,18 +20,21 @@ import java.lang.annotation.Target; import org.apiguardian.api.API; -import org.junit.jupiter.params.ParameterizedTest; /** * {@code @JavaTimeConversionPattern} is an annotation that allows a date/time * conversion pattern to be specified on a parameter of a - * {@link ParameterizedTest @ParameterizedTest} method. + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} + * or + * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest}. * * @since 5.0 + * @see ConvertWith + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest * @see java.time.format.DateTimeFormatterBuilder#appendPattern(String) */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.PARAMETER }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.PARAMETER, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Documented @API(status = STABLE, since = "5.7") @@ -45,4 +49,15 @@ */ String value(); + /** + * Whether {@code null} argument values are allowed. + * + *

Defaults to {@code false}, in which case a {@code null} value will result in + * an exception. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + boolean nullable() default false; + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/SimpleArgumentConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/SimpleArgumentConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/SimpleArgumentConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/SimpleArgumentConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.support.FieldContext; /** * {@code SimpleArgumentConverter} is an abstract base class for @@ -36,6 +37,11 @@ return convert(source, context.getParameter().getType()); } + @Override + public final Object convert(Object source, FieldContext context) throws ArgumentConversionException { + return convert(source, context.getField().getType()); + } + /** * Convert the supplied {@code source} object into the supplied * {@code targetType}. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/TypedArgumentConverter.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/TypedArgumentConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/TypedArgumentConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/TypedArgumentConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.support.FieldContext; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; @@ -48,18 +49,27 @@ @Override public final Object convert(Object source, ParameterContext context) throws ArgumentConversionException { + return convert(source, context.getParameter().getType()); + } + + @Override + public final Object convert(Object source, FieldContext context) throws ArgumentConversionException { + return convert(source, context.getField().getType()); + } + + private T convert(Object source, Class actualTargetType) { if (source == null) { return convert(null); } if (!this.sourceType.isInstance(source)) { String message = String.format( "%s cannot convert objects of type [%s]. Only source objects of type [%s] are supported.", - getClass().getSimpleName(), source.getClass().getName(), this.sourceType.getName()); + getClass().getSimpleName(), source.getClass().getTypeName(), this.sourceType.getTypeName()); throw new ArgumentConversionException(message); } - if (!ReflectionUtils.isAssignableTo(this.targetType, context.getParameter().getType())) { + if (!ReflectionUtils.isAssignableTo(this.targetType, actualTargetType)) { String message = String.format("%s cannot convert to type [%s]. Only target type [%s] is supported.", - getClass().getSimpleName(), context.getParameter().getType().getName(), this.targetType.getName()); + getClass().getSimpleName(), actualTargetType.getTypeName(), this.targetType.getTypeName()); throw new ArgumentConversionException(message); } return convert(this.sourceType.cast(source)); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,8 @@ package org.junit.jupiter.params.provider; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -20,6 +21,8 @@ import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.support.AnnotationConsumer; +import org.junit.jupiter.params.support.ParameterDeclarations; +import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.util.Preconditions; /** @@ -28,13 +31,14 @@ * annotation in order to provide the arguments. * * @since 5.10 + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest * @see org.junit.jupiter.params.provider.ArgumentsSource * @see org.junit.jupiter.params.provider.Arguments * @see org.junit.jupiter.params.provider.ArgumentsProvider * @see org.junit.jupiter.params.support.AnnotationConsumer */ -@API(status = EXPERIMENTAL, since = "5.10") +@API(status = MAINTAINED, since = "5.13.3") public abstract class AnnotationBasedArgumentsProvider implements ArgumentsProvider, AnnotationConsumer { @@ -50,8 +54,8 @@ } @Override - public final Stream provideArguments(ExtensionContext context) { - return annotations.stream().flatMap(annotation -> provideArguments(context, annotation)); + public Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context) { + return annotations.stream().flatMap(annotation -> provideArguments(parameters, context, annotation)); } /** @@ -61,7 +65,29 @@ * @param context the current extension context; never {@code null} * @param annotation the annotation to process; never {@code null} * @return a stream of arguments; never {@code null} + * @deprecated Please implement + * {@link #provideArguments(ParameterDeclarations, ExtensionContext, Annotation)} + * instead. */ - protected abstract Stream provideArguments(ExtensionContext context, A annotation); + @Deprecated + @API(status = DEPRECATED, since = "5.13") + protected Stream provideArguments(ExtensionContext context, A annotation) { + throw new JUnitException(String.format( + "AnnotationBasedArgumentsProvider does not override the provideArguments(ParameterDeclarations, ExtensionContext, Annotation) method. " + + "Please report this issue to the maintainers of %s.", + getClass().getName())); + } + + /** + * The returned {@code Stream} will be {@link Stream#close() properly closed} + * by the default implementation of + * {@link #provideArguments(ParameterDeclarations, ExtensionContext)}, + * making it safe to use a resource such as + * {@link java.nio.file.Files#lines(java.nio.file.Path) Files.lines()}. + */ + protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context, + A annotation) { + return provideArguments(context, annotation); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/Arguments.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/Arguments.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/Arguments.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/Arguments.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.params.provider; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; @@ -118,7 +118,7 @@ * @see org.junit.jupiter.params.ParameterizedTest#ARGUMENT_SET_NAME_PLACEHOLDER * @see org.junit.jupiter.params.ParameterizedTest#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER */ - @API(status = EXPERIMENTAL, since = "5.11") + @API(status = MAINTAINED, since = "5.13.3") static ArgumentSet argumentSet(String name, Object... arguments) { return new ArgumentSet(name, arguments); } @@ -132,7 +132,7 @@ * @see org.junit.jupiter.params.ParameterizedTest#ARGUMENT_SET_NAME_PLACEHOLDER * @see org.junit.jupiter.params.ParameterizedTest#ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER */ - @API(status = EXPERIMENTAL, since = "5.11") + @API(status = MAINTAINED, since = "5.13.3") final class ArgumentSet implements Arguments { private final String name; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,24 +10,33 @@ package org.junit.jupiter.params.provider; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.stream.Stream; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.params.support.ParameterDeclarations; +import org.junit.platform.commons.JUnitException; /** - * An {@code ArgumentsProvider} is responsible for {@linkplain #provideArguments - * providing} a stream of arguments to be passed to a {@code @ParameterizedTest} - * method. + * An {@code ArgumentsProvider} is responsible for + * {@linkplain #provideArguments(ParameterDeclarations, ExtensionContext) providing} + * a stream of arguments to be passed to a + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} or + * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest}. * *

An {@code ArgumentsProvider} can be registered via the * {@link ArgumentsSource @ArgumentsSource} annotation. * - *

Implementations must provide a no-args constructor. + *

Implementations must provide a no-args constructor or a single unambiguous + * constructor to use {@linkplain ParameterResolver parameter resolution}. * * @since 5.0 + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest * @see org.junit.jupiter.params.provider.ArgumentsSource * @see org.junit.jupiter.params.provider.Arguments @@ -42,7 +51,39 @@ * * @param context the current extension context; never {@code null} * @return a stream of arguments; never {@code null} + * @deprecated Please implement + * {@link #provideArguments(ParameterDeclarations, ExtensionContext)} instead. */ - Stream provideArguments(ExtensionContext context) throws Exception; + @Deprecated + @API(status = DEPRECATED, since = "5.13") + default Stream provideArguments(@SuppressWarnings("unused") ExtensionContext context) + throws Exception { + throw new UnsupportedOperationException( + "Please implement provideArguments(ParameterDeclarations, ExtensionContext) instead."); + } + + /** + * Provide a {@link Stream} of {@link Arguments} to be passed to a + * {@code @ParameterizedClass} or {@code @ParameterizedTest}. + * + * @param parameters the parameter declarations for the parameterized + * class or test; never {@code null} + * @param context the current extension context; never {@code null} + * @return a stream of arguments; never {@code null} + * @since 5.13 + */ + @API(status = MAINTAINED, since = "5.13.3") + default Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context) + throws Exception { + try { + return provideArguments(context); + } + catch (Exception e) { + throw new JUnitException(String.format( + "ArgumentsProvider does not override the provideArguments(ParameterDeclarations, ExtensionContext) method. " + + "Please report this issue to the maintainers of %s.", + getClass().getName()), e); + } + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -24,18 +25,25 @@ /** * {@code @ArgumentsSource} is a {@linkplain Repeatable repeatable} annotation * that is used to register {@linkplain ArgumentsProvider arguments providers} - * for the annotated test method. + * for the annotated class or method. * *

{@code @ArgumentsSource} may also be used as a meta-annotation in order to * create a custom composed annotation that inherits the semantics * of {@code @ArgumentsSource}. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.0 * @see org.junit.jupiter.params.provider.ArgumentsProvider + * @see org.junit.jupiter.params.ParameterizedClass + * @see org.junit.jupiter.params.ParameterizedTest */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @Repeatable(ArgumentsSources.class) @API(status = STABLE, since = "5.7") public @interface ArgumentsSource { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSources.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -28,12 +29,17 @@ * optional since {@code @ArgumentsSource} is a {@linkplain java.lang.annotation.Repeatable * repeatable} annotation. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.0 * @see org.junit.jupiter.params.provider.ArgumentsSource */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.7") public @interface ArgumentsSources { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsUtils.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -35,13 +35,13 @@ } // Pass all multidimensional arrays "as is", in contrast to Object[]. - // See https://github.com/junit-team/junit5/issues/1665 + // See https://github.com/junit-team/junit-framework/issues/1665 if (ReflectionUtils.isMultidimensionalArray(item)) { return arguments(item); } // Special treatment for one-dimensional reference arrays. - // See https://github.com/junit-team/junit5/issues/1665 + // See https://github.com/junit-team/junit-framework/issues/1665 if (item instanceof Object[]) { return arguments((Object[]) item); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Named; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.UnrecoverableExceptions; @@ -41,7 +42,8 @@ private CsvParser csvParser; @Override - protected Stream provideArguments(ExtensionContext context, CsvSource csvSource) { + protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context, + CsvSource csvSource) { this.nullValues = toSet(csvSource.nullValues()); this.csvParser = createParserFor(csvSource); final boolean textBlockDeclared = !csvSource.textBlock().isEmpty(); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -34,6 +34,7 @@ import com.univocity.parsers.csv.CsvParser; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.Preconditions; @@ -58,7 +59,8 @@ } @Override - protected Stream provideArguments(ExtensionContext context, CsvFileSource csvFileSource) { + protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context, + CsvFileSource csvFileSource) { this.charset = getCharsetFrom(csvFileSource); this.numLinesToSkip = csvFileSource.numLinesToSkip(); this.csvParser = createParserFor(csvFileSource); @@ -90,7 +92,7 @@ this.csvParser.beginParsing(inputStream, this.charset); } catch (Throwable throwable) { - handleCsvException(throwable, csvFileSource); + throw handleCsvException(throwable, csvFileSource); } return this.csvParser; } @@ -104,7 +106,7 @@ csvParser.stopParsing(); } catch (Throwable throwable) { - handleCsvException(throwable, csvFileSource); + throw handleCsvException(throwable, csvFileSource); } }); } @@ -154,14 +156,14 @@ } } catch (Throwable throwable) { - handleCsvException(throwable, this.csvFileSource); + throw handleCsvException(throwable, this.csvFileSource); } } } @FunctionalInterface - private interface Source { + interface Source { InputStream open(ExtensionContext context); @@ -178,7 +180,7 @@ } default Source file(String path) { - return context -> openFile(path); + return __ -> openFile(path); } } @@ -190,6 +192,7 @@ @Override public InputStream openClasspathResource(Class baseClass, String path) { Preconditions.notBlank(path, () -> "Classpath resource [" + path + "] must not be null or blank"); + //noinspection resource (closed elsewhere) InputStream inputStream = baseClass.getResourceAsStream(path); return Preconditions.notNull(inputStream, () -> "Classpath resource [" + path + "] does not exist"); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,12 +14,14 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.apiguardian.api.API; +import org.junit.jupiter.params.ParameterizedInvocationConstants; /** * {@code @CsvFileSource} is a {@linkplain Repeatable repeatable} @@ -27,8 +29,10 @@ * files from one or more classpath {@link #resources} or {@link #files}. * *

The CSV records parsed from these resources and files will be provided as - * arguments to the annotated {@code @ParameterizedTest} method. Note that the - * first record may optionally be used to supply CSV headers (see + * arguments to the annotated + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} or + * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest}. Note + * that the first record may optionally be used to supply CSV headers (see * {@link #useHeadersInDisplayName}). * *

Any line beginning with a {@code #} symbol will be interpreted as a comment @@ -56,14 +60,20 @@ * column is trimmed by default. This behavior can be changed by setting the * {@link #ignoreLeadingAndTrailingWhitespace} attribute to {@code true}. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.0 * @see CsvSource * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @Repeatable(CsvFileSources.class) @API(status = STABLE, since = "5.7") @ArgumentsSource(CsvFileArgumentsProvider.class) @@ -104,16 +114,16 @@ * for columns. * *

When set to {@code true}, the header names will be used in the - * generated display name for each {@code @ParameterizedTest} method - * invocation. When using this feature, you must ensure that the display name - * pattern for {@code @ParameterizedTest} includes - * {@value org.junit.jupiter.params.ParameterizedTest#ARGUMENTS_PLACEHOLDER} instead of - * {@value org.junit.jupiter.params.ParameterizedTest#ARGUMENTS_WITH_NAMES_PLACEHOLDER} + * generated display name for each {@code @ParameterizedClass} or + * {@code @ParameterizedTest} invocation. When using this feature, you must + * ensure that the display name pattern for {@code @ParameterizedClass} or + * {@code @ParameterizedTest} includes + * {@value ParameterizedInvocationConstants#ARGUMENTS_PLACEHOLDER} instead of + * {@value ParameterizedInvocationConstants#ARGUMENTS_WITH_NAMES_PLACEHOLDER} * as demonstrated in the example below. * *

Defaults to {@code false}. * - * *

Example

*
 	 * {@literal @}ParameterizedTest(name = "[{index}] {arguments}")
diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSources.java
--- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSources.java	2025-10-22 19:33:55.000000000 +0000
+++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvFileSources.java	2026-06-21 20:26:05.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2026 the original author or authors.
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v2.0 which
@@ -14,6 +14,7 @@
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
@@ -28,13 +29,18 @@
  * optional since {@code @CsvFileSource} is a {@linkplain java.lang.annotation.Repeatable
  * repeatable} annotation.
  *
+ * 

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.11 * @see CsvFileSource * @see java.lang.annotation.Repeatable */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.11") public @interface CsvFileSources { @@ -43,4 +49,5 @@ * annotations. */ CsvFileSource[] value(); + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParserFactory.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParserFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParserFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParserFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParsingException.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParsingException.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParsingException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvParsingException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,12 +14,14 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.apiguardian.api.API; +import org.junit.jupiter.params.ParameterizedInvocationConstants; /** * {@code @CsvSource} is a {@linkplain Repeatable repeatable} @@ -28,7 +30,8 @@ * {@link #textBlock} attribute. * *

The supplied values will be provided as arguments to the annotated - * {@code @ParameterizedTest} method. + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} or + * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest}. * *

The column delimiter (which defaults to a comma ({@code ,})) can be customized * via either {@link #delimiter} or {@link #delimiterString}. @@ -59,15 +62,21 @@ * physical line within the text block. Thus, if a CSV column wraps across a * new line in a text block, the column must be a quoted string. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.0 * @see CsvFileSource * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Repeatable(CsvSources.class) @Documented +@Inherited @API(status = STABLE, since = "5.7") @ArgumentsSource(CsvArgumentsProvider.class) @SuppressWarnings("exports") @@ -163,11 +172,12 @@ * for columns. * *

When set to {@code true}, the header names will be used in the - * generated display name for each {@code @ParameterizedTest} method - * invocation. When using this feature, you must ensure that the display name - * pattern for {@code @ParameterizedTest} includes - * {@value org.junit.jupiter.params.ParameterizedTest#ARGUMENTS_PLACEHOLDER} instead of - * {@value org.junit.jupiter.params.ParameterizedTest#ARGUMENTS_WITH_NAMES_PLACEHOLDER} + * generated display name for each {@code @ParameterizedClass} or + * {@code @ParameterizedTest} invocation. When using this feature, you must + * ensure that the display name pattern for {@code @ParameterizedClass} or + * {@code @ParameterizedTest} includes + * {@value ParameterizedInvocationConstants#ARGUMENTS_PLACEHOLDER} instead of + * {@value ParameterizedInvocationConstants#ARGUMENTS_WITH_NAMES_PLACEHOLDER} * as demonstrated in the example below. * *

Defaults to {@code false}. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSources.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvSources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -28,13 +29,18 @@ * optional since {@code @CsvSource} is a {@linkplain java.lang.annotation.Repeatable * repeatable} annotation. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.11 * @see CsvSource * @see java.lang.annotation.Repeatable */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.11") public @interface CsvSources { @@ -43,4 +49,5 @@ * annotations. */ CsvSource[] value(); + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptyArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptyArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptyArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptyArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,7 +15,6 @@ import java.lang.reflect.Array; import java.lang.reflect.Constructor; -import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -29,6 +28,8 @@ import java.util.stream.Stream; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclaration; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.Preconditions; @@ -39,15 +40,15 @@ class EmptyArgumentsProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext context) { - Method testMethod = context.getRequiredTestMethod(); - Class[] parameterTypes = testMethod.getParameterTypes(); - - Preconditions.condition(parameterTypes.length > 0, () -> String.format( - "@EmptySource cannot provide an empty argument to method [%s]: the method does not declare any formal parameters.", - testMethod.toGenericString())); + public Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context) { - Class parameterType = parameterTypes[0]; + Optional firstParameter = parameters.getFirst(); + + Preconditions.condition(firstParameter.isPresent(), + () -> String.format("@EmptySource cannot provide an empty argument to %s: no formal parameters declared.", + parameters.getSourceElementDescription())); + + Class parameterType = firstParameter.get().getParameterType(); if (String.class.equals(parameterType)) { return Stream.of(arguments("")); @@ -88,8 +89,8 @@ } // else throw new PreconditionViolationException( - String.format("@EmptySource cannot provide an empty argument to method [%s]: [%s] is not a supported type.", - testMethod.toGenericString(), parameterType.getName())); + String.format("@EmptySource cannot provide an empty argument to %s: [%s] is not a supported type.", + parameters.getSourceElementDescription(), parameterType.getName())); } private static Optional> getDefaultConstructor(Class clazz) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptySource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptySource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptySource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EmptySource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -22,12 +23,13 @@ /** * {@code @EmptySource} is an {@link ArgumentsSource} which provides a single - * empty argument to the annotated {@code @ParameterizedTest} method. + * empty argument to the annotated {@code @ParameterizedClass} + * or {@code @ParameterizedTest}. * *

Supported Parameter Types

* *

This argument source will only provide an empty argument for the following - * method parameter types. + * parameter types. * *

    *
  • {@link java.lang.String}
  • @@ -43,15 +45,21 @@ *
  • object arrays — for example {@code String[]}, {@code Integer[][]}, etc.
  • *
* + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.4 * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest * @see NullSource * @see NullAndEmptySource */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.7") @ArgumentsSource(EmptyArgumentsProvider.class) @SuppressWarnings("exports") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,12 +13,14 @@ import static java.util.Arrays.stream; import static java.util.stream.Collectors.toSet; -import java.lang.reflect.Method; import java.util.EnumSet; import java.util.Set; import java.util.stream.Stream; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclaration; +import org.junit.jupiter.params.support.ParameterDeclarations; +import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.Preconditions; /** @@ -27,8 +29,9 @@ class EnumArgumentsProvider extends AnnotationBasedArgumentsProvider { @Override - protected Stream provideArguments(ExtensionContext context, EnumSource enumSource) { - Set> constants = getEnumConstants(context, enumSource); + protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context, + EnumSource enumSource) { + Set> constants = getEnumConstants(parameters, enumSource); EnumSource.Mode mode = enumSource.mode(); String[] declaredConstantNames = enumSource.names(); if (declaredConstantNames.length > 0) { @@ -41,23 +44,37 @@ return constants.stream().map(Arguments::of); } - private > Set getEnumConstants(ExtensionContext context, EnumSource enumSource) { - Class enumClass = determineEnumClass(context, enumSource); - return EnumSet.allOf(enumClass); + private > Set getEnumConstants(ParameterDeclarations parameters, + EnumSource enumSource) { + Class enumClass = determineEnumClass(parameters, enumSource); + E[] constants = enumClass.getEnumConstants(); + if (constants.length == 0) { + Preconditions.condition(enumSource.from().isEmpty() && enumSource.to().isEmpty(), + "No enum constant in " + enumClass.getSimpleName() + ", but 'from' or 'to' is not empty."); + return EnumSet.noneOf(enumClass); + } + E from = enumSource.from().isEmpty() ? constants[0] : Enum.valueOf(enumClass, enumSource.from()); + E to = enumSource.to().isEmpty() ? constants[constants.length - 1] : Enum.valueOf(enumClass, enumSource.to()); + Preconditions.condition(from.compareTo(to) <= 0, + () -> String.format( + "Invalid enum range: 'from' (%s) must come before 'to' (%s) in the natural order of enum constants.", + from, to)); + return EnumSet.range(from, to); } @SuppressWarnings({ "unchecked", "rawtypes" }) - private > Class determineEnumClass(ExtensionContext context, EnumSource enumSource) { + private > Class determineEnumClass(ParameterDeclarations parameters, EnumSource enumSource) { Class enumClass = enumSource.value(); if (enumClass.equals(NullEnum.class)) { - Method method = context.getRequiredTestMethod(); - Class[] parameterTypes = method.getParameterTypes(); - Preconditions.condition(parameterTypes.length > 0, - () -> "Test method must declare at least one parameter: " + method.toGenericString()); - Preconditions.condition(Enum.class.isAssignableFrom(parameterTypes[0]), - () -> "First parameter must reference an Enum type (alternatively, use the annotation's 'value' attribute to specify the type explicitly): " - + method.toGenericString()); - enumClass = parameterTypes[0]; + enumClass = parameters.getFirst() // + .map(ParameterDeclaration::getParameterType).map(parameterType -> { + Preconditions.condition(Enum.class.isAssignableFrom(parameterType), + () -> "First parameter must reference an Enum type (alternatively, use the annotation's 'value' attribute to specify the type explicitly): " + + parameters.getSourceElementDescription()); + return (Class) parameterType; + }).orElseThrow( + () -> new PreconditionViolationException("There must be at least one declared parameter for " + + parameters.getSourceElementDescription())); } return enumClass; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,11 +11,12 @@ package org.junit.jupiter.params.provider; import static java.util.stream.Collectors.toSet; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -34,22 +35,28 @@ * {@link ArgumentsSource} for constants of an {@link Enum}. * *

The enum constants will be provided as arguments to the annotated - * {@code @ParameterizedTest} method. + * {@code @ParameterizedClass} or {@code @ParameterizedTest}. * *

The enum type can be specified explicitly using the {@link #value} * attribute. Otherwise, the declared type of the first parameter of the - * {@code @ParameterizedTest} method is used. + * {@code @ParameterizedClass} or {@code @ParameterizedTest} is used. * - *

The set of enum constants can be restricted via the {@link #names} and - * {@link #mode} attributes. + *

The set of enum constants can be restricted via the {@link #names}, + * {@link #from}, {@link #to} and {@link #mode} attributes. + * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. * * @since 5.0 * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @Repeatable(EnumSources.class) @API(status = STABLE, since = "5.7") @ArgumentsSource(EnumArgumentsProvider.class) @@ -63,6 +70,8 @@ * first parameter of the {@code @ParameterizedTest} method is used. * * @see #names + * @see #from + * @see #to * @see #mode */ Class> value() default NullEnum.class; @@ -71,19 +80,61 @@ * The names of enum constants to provide, or regular expressions to select * the names of enum constants to provide. * - *

If no names or regular expressions are specified, all enum constants - * declared in the specified {@linkplain #value enum type} will be provided. + *

If no names or regular expressions are specified, and neither {@link #from} + * nor {@link #to} are specified, all enum constants declared in the specified + * {@linkplain #value enum type} will be provided. + * + *

If {@link #from} or {@link #to} are specified, the elements in names must + * fall within the range defined by {@link #from} and {@link #to}. * *

The {@link #mode} determines how the names are interpreted. * * @see #value + * @see #from + * @see #to * @see #mode */ String[] names() default {}; /** + * The starting enum constant of the range to be included. + * + *

Defaults to an empty string, where the range starts from the first enum + * constant of the specified {@linkplain #value enum type}. + * + * @see #value + * @see #names + * @see #to + * @see #mode + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + String from() default ""; + + /** + * The ending enum constant of the range to be included. + * + *

Defaults to an empty string, where the range ends at the last enum + * constant of the specified {@linkplain #value enum type}. + * + * @see #value + * @see #names + * @see #from + * @see #mode + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + String to() default ""; + + /** * The enum constant selection mode. * + *

The mode only applies to the {@link #names} attribute and does not change + * the behavior of {@link #from} and {@link #to}, which always define a range + * based on the natural order of the enum constants. + * *

Defaults to {@link Mode#INCLUDE INCLUDE}. * * @see Mode#INCLUDE @@ -92,6 +143,8 @@ * @see Mode#MATCH_ANY * @see Mode#MATCH_NONE * @see #names + * @see #from + * @see #to */ Mode mode() default Mode.INCLUDE; @@ -135,7 +188,7 @@ * @since 5.9 * @see java.util.stream.Stream#noneMatch(java.util.function.Predicate) */ - @API(status = EXPERIMENTAL, since = "5.9") + @API(status = MAINTAINED, since = "5.13.3") MATCH_NONE(Mode::validatePatterns, (name, patterns) -> patterns.stream().noneMatch(name::matches)); private final Validator validator; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSources.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -28,13 +29,18 @@ * optional since {@code @EnumSource} is a {@linkplain java.lang.annotation.Repeatable * repeatable} annotation. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.11 * @see EnumSource * @see java.lang.annotation.Repeatable */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.11") public @interface EnumSources { @@ -43,4 +49,5 @@ * annotations. */ EnumSource[] value(); + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,16 +14,21 @@ import static java.util.Arrays.stream; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Iterator; +import java.util.Optional; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.BaseStream; import java.util.stream.Stream; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ClassLoaderUtils; import org.junit.platform.commons.util.CollectionUtils; import org.junit.platform.commons.util.Preconditions; @@ -38,12 +43,16 @@ class FieldArgumentsProvider extends AnnotationBasedArgumentsProvider { @Override - protected Stream provideArguments(ExtensionContext context, FieldSource fieldSource) { + protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context, + FieldSource fieldSource) { Class testClass = context.getRequiredTestClass(); Object testInstance = context.getTestInstance().orElse(null); String[] fieldNames = fieldSource.value(); if (fieldNames.length == 0) { - fieldNames = new String[] { context.getRequiredTestMethod().getName() }; + Optional testMethod = context.getTestMethod(); + Preconditions.condition(testMethod.isPresent(), + "You must specify a field name when using @FieldSource with @ParameterizedClass"); + fieldNames = new String[] { testMethod.get().getName() }; } // @formatter:off return stream(fieldNames) @@ -87,7 +96,7 @@ } private static Field validateField(Field field, Object testInstance) { - Preconditions.condition(field.getDeclaringClass().isInstance(testInstance) || ReflectionUtils.isStatic(field), + Preconditions.condition(field.getDeclaringClass().isInstance(testInstance) || ModifierSupport.isStatic(field), () -> format("Field '%s' must be static: local @FieldSource fields must be static " + "unless the PER_CLASS @TestInstance lifecycle mode is used; " + "external @FieldSource fields must always be static.", @@ -96,7 +105,7 @@ } private static Object readField(Field field, Object testInstance) { - Object value = ReflectionUtils.tryToReadFieldValue(field, testInstance).getOrThrow( + Object value = ReflectionSupport.tryToReadFieldValue(field, testInstance).getOrThrow( cause -> new JUnitException(format("Could not read field [%s]", field.getName()), cause)); String fieldName = field.getName(); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,17 +10,17 @@ package org.junit.jupiter.params.provider; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.apiguardian.api.API; -import org.junit.jupiter.params.ParameterizedTest; /** * {@code @FieldSource} is a {@linkplain Repeatable repeatable} @@ -32,7 +32,8 @@ *

Each field must be able to supply a stream of arguments, * and each set of "arguments" within the "stream" will be provided as the physical * arguments for individual invocations of the annotated - * {@link ParameterizedTest @ParameterizedTest} method. + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} or + * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest}. * *

In this context, a "stream" is anything that JUnit can reliably convert to * a {@link java.util.stream.Stream Stream}; however, the actual concrete field @@ -43,11 +44,13 @@ * {@link java.util.stream.DoubleStream DoubleStream}, * {@link java.util.stream.LongStream LongStream}, or * {@link java.util.stream.IntStream IntStream}), a {@code Supplier} of an - * {@link java.util.Iterator Iterator}, an array of objects, or an array of - * primitives. Each set of "arguments" within the "stream" can be supplied as an - * instance of {@link Arguments}, an array of objects (for example, {@code Object[]}, - * {@code String[]}, etc.), or a single value if the parameterized test - * method accepts a single argument. + * {@link java.util.Iterator Iterator}, an array of objects or primitives, or + * any type that provides an {@link java.util.Iterator Iterator}-returning + * {@code iterator()} method (such as, for example, a + * {@code kotlin.sequences.Sequence}). Each set of "arguments" within the + * "stream" can be supplied as an instance of {@link Arguments}, an array of + * objects (for example, {@code Object[]}, {@code String[]}, etc.), or a single + * value if the parameterized class or test accepts a single argument. * *

In contrast to the supported return types for {@link MethodSource @MethodSource} * factory methods, the value of a {@code @FieldSource} field cannot be an instance of @@ -60,6 +63,12 @@ * use one of these types, you can wrap it in a {@code Supplier} — for * example, {@code Supplier}. * + *

If the {@code Supplier} return type is {@code Stream} or + * one of the primitive streams, JUnit will properly close it by calling + * {@link java.util.stream.BaseStream#close() BaseStream.close()}, + * making it safe to use a resource such as + * {@link java.nio.file.Files#lines(java.nio.file.Path) Files.lines()}. + * *

Please note that a one-dimensional array of objects supplied as a set of * "arguments" will be handled differently than other types of arguments. * Specifically, all of the elements of a one-dimensional array of objects will @@ -104,18 +113,28 @@ * test instance lifecycle mode is used; whereas, fields in external classes must * always be {@code static}. * + *

This behavior and the above examples also apply to parameters of a + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass}, + * regardless whether field or constructor injection is used. + * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.11 * @see MethodSource * @see Arguments * @see ArgumentsSource - * @see ParameterizedTest + * @see org.junit.jupiter.params.ParameterizedClass + * @see org.junit.jupiter.params.ParameterizedTest * @see org.junit.jupiter.api.TestInstance */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @Repeatable(FieldSources.class) -@API(status = EXPERIMENTAL, since = "5.11") +@API(status = MAINTAINED, since = "5.13.3") @ArgumentsSource(FieldArgumentsProvider.class) @SuppressWarnings("exports") public @interface FieldSource { @@ -131,7 +150,10 @@ * static nested class. * *

If no field names are declared, a field within the test class that has - * the same name as the test method will be used as the field by default. + * the same name as the test method will be used as the field by default in + * case this annotation is applied to a {@code @ParameterizedTest} method. + * For a {@code @ParameterizedClass}, at least one field name must be + * declared explicitly. * *

For further information, see the {@linkplain FieldSource class-level Javadoc}. */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSources.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/FieldSources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,11 @@ package org.junit.jupiter.params.provider; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -28,14 +29,19 @@ * optional since {@code @FieldSource} is a {@linkplain java.lang.annotation.Repeatable * repeatable} annotation. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.11 * @see FieldSource * @see java.lang.annotation.Repeatable */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented -@API(status = EXPERIMENTAL, since = "5.11") +@Inherited +@API(status = MAINTAINED, since = "5.13.3") public @interface FieldSources { /** @@ -43,4 +49,5 @@ * annotations. */ FieldSource[] value(); + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,11 +13,12 @@ import static java.lang.String.format; import static java.util.Arrays.stream; import static java.util.stream.Collectors.toList; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; import static org.junit.platform.commons.util.CollectionUtils.isConvertibleToStream; import java.lang.reflect.Method; import java.util.List; +import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Stream; @@ -25,6 +26,7 @@ import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.ClassLoaderUtils; import org.junit.platform.commons.util.CollectionUtils; @@ -41,9 +43,10 @@ method -> isConvertibleToStream(method.getReturnType()) && !isTestMethod(method); @Override - protected Stream provideArguments(ExtensionContext context, MethodSource methodSource) { + protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context, + MethodSource methodSource) { Class testClass = context.getRequiredTestClass(); - Method testMethod = context.getRequiredTestMethod(); + Optional testMethod = context.getTestMethod(); Object testInstance = context.getTestInstance().orElse(null); String[] methodNames = methodSource.value(); // @formatter:off @@ -56,13 +59,15 @@ // @formatter:on } - private static Method findFactoryMethod(Class testClass, Method testMethod, String factoryMethodName) { + private static Method findFactoryMethod(Class testClass, Optional testMethod, String factoryMethodName) { String originalFactoryMethodName = factoryMethodName; // If the user did not provide a factory method name, find a "default" local // factory method with the same name as the parameterized test method. if (StringUtils.isBlank(factoryMethodName)) { - factoryMethodName = testMethod.getName(); + Preconditions.condition(testMethod.isPresent(), + "You must specify a method name when using @MethodSource with @ParameterizedClass"); + factoryMethodName = testMethod.get().getName(); return findFactoryMethodBySimpleName(testClass, testMethod, factoryMethodName); } @@ -103,7 +108,7 @@ } // package-private for testing - static Method findFactoryMethodByFullyQualifiedName(Class testClass, Method testMethod, + static Method findFactoryMethodByFullyQualifiedName(Class testClass, Optional testMethod, String fullyQualifiedMethodName) { String[] methodParts = ReflectionUtils.parseFullyQualifiedMethodName(fullyQualifiedMethodName); String className = methodParts[0]; @@ -142,24 +147,25 @@ * @throws PreconditionViolationException if the factory method was not found or * multiple competing factory methods with the same name were found */ - private static Method findFactoryMethodBySimpleName(Class clazz, Method testMethod, String factoryMethodName) { + private static Method findFactoryMethodBySimpleName(Class clazz, Optional testMethod, + String factoryMethodName) { Predicate isCandidate = candidate -> factoryMethodName.equals(candidate.getName()) - && !testMethod.equals(candidate); + && !candidate.equals(testMethod.orElse(null)); List candidates = ReflectionUtils.findMethods(clazz, isCandidate); List factoryMethods = candidates.stream().filter(isFactoryMethod).collect(toList()); - Preconditions.condition(factoryMethods.size() > 0, () -> { + Preconditions.notEmpty(factoryMethods, () -> { + if (candidates.isEmpty()) { + // Report that we didn't find anything. + return format("Could not find factory method [%s] in class [%s]", factoryMethodName, clazz.getName()); + } // If we didn't find the factory method using the isFactoryMethod Predicate, perhaps // the specified factory method has an invalid return type or is a test method. // In that case, we report the invalid candidates that were found. - if (candidates.size() > 0) { - return format( - "Could not find valid factory method [%s] in class [%s] but found the following invalid candidates: %s", - factoryMethodName, clazz.getName(), candidates); - } - // Otherwise, report that we didn't find anything. - return format("Could not find factory method [%s] in class [%s]", factoryMethodName, clazz.getName()); + return format( + "Could not find valid factory method [%s] in class [%s] but found the following invalid candidates: %s", + factoryMethodName, clazz.getName(), candidates); }); Preconditions.condition(factoryMethods.size() == 1, () -> format("%d factory methods named [%s] were found in class [%s]: %s", factoryMethods.size(), diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,13 +14,13 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.apiguardian.api.API; -import org.junit.jupiter.params.ParameterizedTest; /** * {@code @MethodSource} is a {@linkplain Repeatable repeatable} @@ -30,24 +30,32 @@ * by fully qualified method name. * *

Each factory method must generate a stream of arguments, - * and each set of "arguments" within the "stream" will be provided as the physical - * arguments for individual invocations of the annotated - * {@link ParameterizedTest @ParameterizedTest} method. Generally speaking this - * translates to a {@link java.util.stream.Stream Stream} of {@link Arguments} - * (i.e., {@code Stream}); however, the actual concrete return type - * can take on many forms. In this context, a "stream" is anything that JUnit - * can reliably convert into a {@code Stream}, such as + * and each set of "arguments" within the "stream" will be provided as the + * physical arguments for individual invocations of the annotated + * {@code org.junit.jupiter.params.ParameterizedClass @ParameterizedClass} or + * {@link org.junit.jupiter.params.ParameterizedTest @ParameterizedTest}. + * Generally speaking this translates to a {@link java.util.stream.Stream Stream} + * of {@link Arguments} (i.e., {@code Stream}); however, the actual + * concrete return type can take on many forms. In this context, a "stream" is + * anything that JUnit can reliably convert into a {@code Stream}, such as * {@link java.util.stream.Stream Stream}, * {@link java.util.stream.DoubleStream DoubleStream}, * {@link java.util.stream.LongStream LongStream}, * {@link java.util.stream.IntStream IntStream}, * {@link java.util.Collection Collection}, - * {@link java.util.Iterator Iterator}, - * {@link Iterable}, an array of objects, or an array of primitives. Each set of - * "arguments" within the "stream" can be supplied as an instance of - * {@link Arguments}, an array of objects (e.g., {@code Object[]}, - * {@code String[]}, etc.), or a single value if the parameterized test - * method accepts a single argument. + * {@link java.util.Iterator Iterator}, an array of objects or primitives, or + * any type that provides an {@link java.util.Iterator Iterator}-returning + * {@code iterator()} method (such as, for example, a + * {@code kotlin.sequences.Sequence}). Each set of "arguments" within the + * "stream" can be supplied as an instance of {@link Arguments}, an array of + * objects (e.g., {@code Object[]}, {@code String[]}, etc.), or a single + * value if the parameterized test method accepts a single argument. + * + *

If the return type is {@code Stream} or + * one of the primitive streams, JUnit will properly close it by calling + * {@link java.util.stream.BaseStream#close() BaseStream.close()}, + * making it safe to use a resource such as + * {@link java.nio.file.Files#lines(java.nio.file.Path) Files.lines()}. * *

Please note that a one-dimensional array of objects supplied as a set of * "arguments" will be handled differently than other types of arguments. @@ -92,19 +100,29 @@ * test instance lifecycle mode is used; whereas, factory methods in external * classes must always be {@code static}. * + *

This behavior and the above examples also apply to parameters of a + * {@link org.junit.jupiter.params.ParameterizedClass @ParameterizedClass}, + * regardless whether field or constructor injection is used. + * *

Factory methods can declare parameters, which will be provided by registered * implementations of {@link org.junit.jupiter.api.extension.ParameterResolver}. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.0 * @see FieldSource * @see Arguments * @see ArgumentsSource - * @see ParameterizedTest + * @see org.junit.jupiter.params.ParameterizedClass + * @see org.junit.jupiter.params.ParameterizedTest * @see org.junit.jupiter.api.TestInstance */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @Repeatable(MethodSources.class) @API(status = STABLE, since = "5.7") @ArgumentsSource(MethodArgumentsProvider.class) @@ -131,7 +149,9 @@ * *

If no factory method names are declared, a method within the test class * that has the same name as the test method will be used as the factory - * method by default. + * method by default in case this annotation is applied to a + * {@code @ParameterizedTest} method. For a {@code @ParameterizedClass}, at + * least one method name must be declared explicitly. * *

For further information, see the {@linkplain MethodSource class-level Javadoc}. */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSources.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -28,13 +29,18 @@ * optional since {@code @MethodSource} is a {@linkplain java.lang.annotation.Repeatable * repeatable} annotation. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.11 * @see MethodSource * @see java.lang.annotation.Repeatable */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.11") public @interface MethodSources { @@ -43,4 +49,5 @@ * annotations. */ MethodSource[] value(); + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullAndEmptySource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullAndEmptySource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullAndEmptySource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullAndEmptySource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -25,18 +26,24 @@ * the functionality of {@link NullSource @NullSource} and * {@link EmptySource @EmptySource}. * - *

Annotating a {@code @ParameterizedTest} method with - * {@code @NullAndEmptySource} is equivalent to annotating the method with - * {@code @NullSource} and {@code @EmptySource}. + *

Annotating a {@code @ParameterizedClass} or {@code @ParameterizedTest} + * with {@code @NullAndEmptySource} is equivalent to annotating the method with + * both {@code @NullSource} and {@code @EmptySource}. + * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. * * @since 5.4 + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest * @see NullSource * @see EmptySource */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.7") @NullSource @EmptySource diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,10 +12,10 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; -import java.lang.reflect.Method; import java.util.stream.Stream; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.util.Preconditions; /** @@ -27,11 +27,10 @@ private static final Arguments nullArguments = arguments(new Object[] { null }); @Override - public Stream provideArguments(ExtensionContext context) { - Method testMethod = context.getRequiredTestMethod(); - Preconditions.condition(testMethod.getParameterCount() > 0, () -> String.format( - "@NullSource cannot provide a null argument to method [%s]: the method does not declare any formal parameters.", - testMethod.toGenericString())); + public Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context) { + Preconditions.condition(parameters.getFirst().isPresent(), + () -> String.format("@NullSource cannot provide a null argument to %s: no formal parameters declared.", + parameters.getSourceElementDescription())); return Stream.of(nullArguments); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullEnum.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullEnum.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullEnum.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullEnum.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/NullSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -22,21 +23,28 @@ /** * {@code @NullSource} is an {@link ArgumentsSource} which provides a single - * {@code null} argument to the annotated {@code @ParameterizedTest} method. + * {@code null} argument to the annotated {@code @ParameterizedClass} or + * {@code @ParameterizedTest}. * *

Note that {@code @NullSource} cannot be used for an argument that has * a primitive type, unless the argument is converted to a corresponding wrapper * type with an {@link org.junit.jupiter.params.converter.ArgumentConverter}. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.4 * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest * @see EmptySource * @see NullAndEmptySource */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.7") @ArgumentsSource(NullArgumentsProvider.class) @SuppressWarnings("exports") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueArgumentsProvider.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueArgumentsProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueArgumentsProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueArgumentsProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,6 +19,7 @@ import java.util.stream.Stream; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.util.Preconditions; /** @@ -27,7 +28,8 @@ class ValueArgumentsProvider extends AnnotationBasedArgumentsProvider { @Override - protected Stream provideArguments(ExtensionContext context, ValueSource valueSource) { + protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context, + ValueSource valueSource) { Object[] arguments = getArgumentsFromSource(valueSource); return Arrays.stream(arguments).map(Arguments::of); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSource.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSource.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -32,15 +33,21 @@ * {@code @ValueSource} declaration. * *

The supplied literal values will be provided as arguments to the - * annotated {@code @ParameterizedTest} method. + * annotated {@code @ParameterizedClass} or {@code @ParameterizedTest}. + * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. * * @since 5.0 * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedClass * @see org.junit.jupiter.params.ParameterizedTest */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @Repeatable(ValueSources.class) @API(status = STABLE, since = "5.7") @ArgumentsSource(ValueArgumentsProvider.class) diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSources.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSources.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueSources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -28,13 +29,18 @@ * optional since {@code @ValueSource} is a {@linkplain java.lang.annotation.Repeatable * repeatable} annotation. * + *

Inheritance

+ * + *

This annotation is inherited to subclasses. + * * @since 5.11 * @see ValueSource * @see java.lang.annotation.Repeatable */ -@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @API(status = STABLE, since = "5.11") public @interface ValueSources { @@ -43,4 +49,5 @@ * annotations. */ ValueSource[] value(); + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,10 +13,10 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; -import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; -import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; +import static org.junit.platform.commons.support.HierarchyTraversalMode.BOTTOM_UP; +import static org.junit.platform.commons.support.ReflectionSupport.findMethods; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; @@ -40,6 +40,7 @@ private static final List annotationConsumingMethodSignatures = asList( // new AnnotationConsumingMethodSignature("accept", 1, 0), // + new AnnotationConsumingMethodSignature("provideArguments", 3, 2), // new AnnotationConsumingMethodSignature("provideArguments", 2, 1), // new AnnotationConsumingMethodSignature("convert", 3, 2)); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/FieldContext.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/FieldContext.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/FieldContext.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/FieldContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params.support; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.reflect.Field; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.extension.AnnotatedElementContext; +import org.junit.jupiter.params.Parameter; +import org.junit.jupiter.params.ParameterizedClass; + +/** + * {@code FieldContext} encapsulates the context in which an + * {@link Parameter @Parameter}-annotated {@link Field} is declared in a + * {@link ParameterizedClass @ParameterizedClass}. + * + * @since 5.13 + * @see ParameterizedClass + * @see Parameter + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface FieldContext extends AnnotatedElementContext { + + /** + * {@return the field for this context; never {@code null}} + */ + Field getField(); + + /** + * {@return the index of the parameter} + * + *

This method returns {@value Parameter#UNSET_INDEX} for aggregator + * fields and a value greater than or equal to zero for indexed + * parameters. + * + * @see Parameter#value() + */ + int getParameterIndex(); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclaration.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclaration.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclaration.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclaration.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params.support; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.reflect.AnnotatedElement; +import java.util.Optional; + +import org.apiguardian.api.API; + +/** + * {@code ParameterDeclaration} encapsulates the declaration of an + * indexed {@code @ParameterizedClass} or {@code @ParameterizedTest} parameter. + * + * @since 5.13 + * @see ParameterDeclarations + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface ParameterDeclaration { + + /** + * {@return the {@link AnnotatedElement} that declares the parameter; never + * {@code null}} + * + *

This is either a {@link java.lang.reflect.Parameter} or a + * {@link java.lang.reflect.Field}. + */ + AnnotatedElement getAnnotatedElement(); + + /** + * {@return the type of the parameter; never {@code null}} + */ + Class getParameterType(); + + /** + * {@return the index of the parameter} + */ + int getParameterIndex(); + + /** + * {@return the name of the parameter, if available; never {@code null} but + * potentially empty} + */ + Optional getParameterName(); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclarations.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclarations.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclarations.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterDeclarations.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params.support; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.reflect.AnnotatedElement; +import java.util.List; +import java.util.Optional; + +import org.apiguardian.api.API; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; + +/** + * {@code ParameterDeclarations} encapsulates the combined declarations + * of all indexed {@code @ParameterizedClass} or + * {@code @ParameterizedTest} parameters. + * + *

For a {@code @ParameterizedTest}, the parameter declarations are derived + * from the method signature. For a {@code @ParameterizedClass}, they may be + * derived from the constructor or + * {@link java.lang.reflect.Parameter @Parameter}-annotated fields. + * + *

Aggregators, that is parameters of type + * {@link ArgumentsAccessor ArgumentsAccessor} or parameters annotated with + * {@link org.junit.jupiter.params.aggregator.AggregateWith @AggregateWith}, are + * not indexed and thus not included in the list of parameter + * declarations. + * + * @since 5.13 + * @see ParameterDeclaration + * @see org.junit.jupiter.params.ParameterizedClass + * @see org.junit.jupiter.params.ParameterizedTest + */ +@API(status = MAINTAINED, since = "5.13.3") +public interface ParameterDeclarations { + + /** + * {@return all indexed parameter declarations; never {@code null}, + * sorted by index} + */ + List getAll(); + + /** + * {@return the first indexed parameter declaration, if available; + * never {@code null}} + */ + Optional getFirst(); + + /** + * {@return the indexed parameter declaration for the supplied + * index, if available; never {@code null}} + */ + Optional get(int parameterIndex); + + /** + * {@return the source element of all parameter declarations} + * + *

For {@code @ParameterizedTest}, this always corresponds to the + * parameterized test method. For {@code @ParameterizedClass}, this + * corresponds to the parameterized test class constructor, if constructor + * injection is used; or the test class itself, if field injection is used. + */ + AnnotatedElement getSourceElement(); + + /** + * {@return a human-readable description of the source element} + * + *

This may, for example, be used in error messages. + * + * @see #getSourceElement() + */ + String getSourceElementDescription(); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterInfo.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterInfo.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterInfo.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/ParameterInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params.support; + +import static org.apiguardian.api.API.Status.DEPRECATED; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.ParameterizedTest; + +/** + * {@code ParameterInfo} is used to provide information about the current + * invocation of a parameterized class or test. + * + *

Registered {@link Extension} implementations may retrieve the current + * {@code ParameterInfo} instance by calling + * {@link ExtensionContext#getStore(Namespace)} with {@link #NAMESPACE} and + * {@link ExtensionContext.Store#get(Object, Class) Store.get(...)} with + * {@link #KEY}. Alternatively, the {@link #get(ExtensionContext)} method may + * be used to retrieve the {@code ParameterInfo} instance for the supplied + * {@code ExtensionContext}. Extensions must not modify any entries in the + * {@link ExtensionContext.Store Store} for {@link #NAMESPACE}. + * + *

When a {@link ParameterizedTest @ParameterizedTest} method is declared + * inside a {@link ParameterizedClass @ParameterizedClass} or a + * {@link Nested @Nested} {@link ParameterizedClass @ParameterizedClass} is + * declared inside an enclosing {@link ParameterizedClass @ParameterizedClass}, + * there will be multiple {@code ParameterInfo} instances available on different + * levels of the {@link ExtensionContext} hierarchy. In such cases, please use + * {@link ExtensionContext#getParent()} to navigate to the right level before + * retrieving the {@code ParameterInfo} instance from the + * {@link ExtensionContext.Store Store}. + * + * @since 5.13 + * @see ParameterizedClass + * @see ParameterizedTest + * @deprecated Please use {@link org.junit.jupiter.params.ParameterInfo} instead + */ +@Deprecated +@API(status = DEPRECATED, since = "5.14") +public interface ParameterInfo extends org.junit.jupiter.params.ParameterInfo { + + /** + * The {@link Namespace} for accessing the + * {@link ExtensionContext.Store Store} for {@code ParameterInfo}. + * @deprecated Please use + * {@link org.junit.jupiter.params.ParameterInfo#NAMESPACE} instead + */ + @Deprecated + @API(status = DEPRECATED, since = "5.14") + Namespace NAMESPACE = Namespace.create(ParameterInfo.class); + + /** + * The key for retrieving the {@code ParameterInfo} instance from the + * {@link ExtensionContext.Store Store}. + * @deprecated Please use + * {@link org.junit.jupiter.params.ParameterInfo#KEY} instead + */ + @Deprecated + @API(status = DEPRECATED, since = "5.14") + Object KEY = ParameterInfo.class; + + /** + * {@return the closest {@code ParameterInfo} instance for the supplied + * {@code ExtensionContext}; potentially {@code null}} + * @deprecated Please use + * {@link org.junit.jupiter.params.ParameterInfo#get(ExtensionContext)} + * instead + */ + @Deprecated + @API(status = DEPRECATED, since = "5.14") + static ParameterInfo get(ExtensionContext context) { + return context.getStore(NAMESPACE).get(KEY, ParameterInfo.class); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessor.kt jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessor.kt --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/main/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessor.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/main/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessor.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + @file:API(status = API.Status.STABLE, since = "5.7") package org.junit.jupiter.params.aggregator diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/module/org.junit.jupiter.params/module-info.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/module/org.junit.jupiter.params/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/module/org.junit.jupiter.params/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/module/org.junit.jupiter.params/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * JUnit Jupiter extension for parameterized tests. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/testFixtures/java/org/junit/jupiter/params/provider/RecordArguments.java jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/testFixtures/java/org/junit/jupiter/params/provider/RecordArguments.java --- jtreg8-8.1+1+ds1/junit5/junit-jupiter-params/src/testFixtures/java/org/junit/jupiter/params/provider/RecordArguments.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-jupiter-params/src/testFixtures/java/org/junit/jupiter/params/provider/RecordArguments.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params.provider; + +import java.util.Arrays; + +import org.junit.platform.commons.support.ReflectionSupport; + +public interface RecordArguments extends Arguments { + + @Override + default Object[] get() { + return Arrays.stream(getClass().getRecordComponents()) // + .map(component -> ReflectionSupport.invokeMethod(component.getAccessor(), this)) // + .toArray(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/junit-platform-commons.gradle.kts jtreg8-8.3+1+ds1/junit5/junit-platform-commons/junit-platform-commons.gradle.kts --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/junit-platform-commons.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/junit-platform-commons.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -12,6 +12,8 @@ api(platform(projects.junitBom)) compileOnlyApi(libs.apiguardian) + + testFixturesImplementation(libs.assertj) } tasks.jar { @@ -30,6 +32,7 @@ tasks.codeCoverageClassesJar { exclude("org/junit/platform/commons/util/ModuleUtils.class") exclude("org/junit/platform/commons/util/PackageNameUtils.class") + exclude("org/junit/platform/commons/util/ServiceLoaderUtils.class") } eclipse { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/JUnitException.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/JUnitException.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/JUnitException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/JUnitException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.platform.commons; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; @@ -33,4 +34,12 @@ super(message, cause); } + /** + * @since 1.13 + */ + @API(status = MAINTAINED, since = "1.13") + protected JUnitException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/PreconditionViolationException.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/PreconditionViolationException.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/PreconditionViolationException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/PreconditionViolationException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/annotation/Testable.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/annotation/Testable.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/annotation/Testable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/annotation/Testable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/Try.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/Try.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/Try.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/Try.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/package-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/function/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /** - * Maintained functional interfaces and support classes. + * Functional interfaces and support classes. */ package org.junit.platform.commons.function; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/DefaultResource.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/DefaultResource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/DefaultResource.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/DefaultResource.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.io; + +import java.net.URI; +import java.util.Objects; + +import org.junit.platform.commons.PreconditionViolationException; + +/** + * Default implementation of {@link Resource}. + * + * @since 1.14 + */ +class DefaultResource implements Resource { + + private final String name; + private final URI uri; + + DefaultResource(String name, URI uri) { + this.name = checkNotNull(name, "name"); + this.uri = checkNotNull(uri, "uri"); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public URI getUri() { + return this.uri; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Resource) { + Resource that = (Resource) obj; + return this.name.equals(that.getName()) // + && this.uri.equals(that.getUri()); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(name, uri); + } + + // Cannot use Preconditions due to package cycle + private static T checkNotNull(T input, String title) { + if (input == null) { + throw new PreconditionViolationException(title + " must not be null"); + } + return input; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/Resource.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/Resource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/Resource.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/Resource.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.io; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +import org.apiguardian.api.API; + +/** + * {@code Resource} represents a resource on the classpath. + * + *

WARNING: a {@code Resource} must provide correct + * {@link Object#equals(Object) equals} and {@link Object#hashCode() hashCode} + * implementations since a {@code Resource} may potentially be stored in a + * collection or map. + * + * @since 1.14 + * @see org.junit.platform.commons.support.ResourceSupport#findAllResourcesInClasspathRoot(URI, ResourceFilter) + * @see org.junit.platform.commons.support.ResourceSupport#findAllResourcesInPackage(String, ResourceFilter) + * @see org.junit.platform.commons.support.ResourceSupport#findAllResourcesInModule(String, ResourceFilter) + * @see org.junit.platform.commons.support.ResourceSupport#streamAllResourcesInClasspathRoot(URI, ResourceFilter) + * @see org.junit.platform.commons.support.ResourceSupport#streamAllResourcesInPackage(String, ResourceFilter) + * @see org.junit.platform.commons.support.ResourceSupport#streamAllResourcesInModule(String, ResourceFilter) + */ +@API(status = MAINTAINED, since = "1.14") +public interface Resource { + + /** + * Create a new {@link Resource} with the given name and URI. + * + * @param name the name of the resource; never {@code null} + * @param uri the URI of the resource; never {@code null} + * @return a new {@code Resource} + * @since 1.14 + */ + static Resource of(String name, URI uri) { + return new DefaultResource(name, uri); + } + + /** + * Get the name of this resource. + * + *

The resource name is a {@code /}-separated path. The path is relative + * to the classpath root in which the resource is located. + * + * @return the resource name; never {@code null} + */ + String getName(); + + /** + * Get the URI of this resource. + * + * @return the URI of the resource; never {@code null} + */ + URI getUri(); + + /** + * Get an {@link InputStream} for reading this resource. + * + *

The default implementation delegates to {@link java.net.URL#openStream()} + * for this resource's {@link #getUri() URI}. + * + * @return an input stream for this resource; never {@code null} + * @throws IOException if an I/O exception occurs + */ + default InputStream getInputStream() throws IOException { + return getUri().toURL().openStream(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/ResourceFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/ResourceFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/ResourceFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/ResourceFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.io; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.function.Predicate; + +import org.apiguardian.api.API; + +/** + * Resource filter used by reflection and classpath scanning support. + * + * @since 1.14 + * @see Resource + */ +@API(status = MAINTAINED, since = "1.14") +public class ResourceFilter { + + /** + * Create a {@link ResourceFilter} instance from a predicate. + * + * @param resourcePredicate the resource predicate; never {@code null} + * @return an instance of {@code ResourceFilter}; never {@code null} + */ + public static ResourceFilter of(Predicate resourcePredicate) { + return new ResourceFilter(resourcePredicate); + } + + private final Predicate predicate; + + private ResourceFilter(Predicate predicate) { + this.predicate = predicate; + } + + public boolean match(Resource resource) { + return predicate.test(resource); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/io/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,5 @@ +/** + * IO-related interfaces and support classes + */ + +package org.junit.platform.commons.io; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LogRecordListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LogRecordListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LogRecordListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LogRecordListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/Logger.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/Logger.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/Logger.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/Logger.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LoggerFactory.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LoggerFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LoggerFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/logging/LoggerFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/AnnotationSupport.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/AnnotationSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/AnnotationSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/AnnotationSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,14 +10,15 @@ package org.junit.platform.commons.support; +import static org.apiguardian.api.API.Status.DEPRECATED; import static org.apiguardian.api.API.Status.MAINTAINED; -import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; +import java.util.ListIterator; import java.util.Optional; import java.util.function.Predicate; @@ -41,6 +42,7 @@ * @see ClassSupport * @see ModifierSupport * @see ReflectionSupport + * @see ResourceSupport */ @API(status = MAINTAINED, since = "1.0") public final class AnnotationSupport { @@ -54,6 +56,10 @@ * present or meta-present on the supplied optional * {@code element}. * + *

Note: This method does not find repeatable annotations. + * To check for repeatable annotations, use {@link #findRepeatableAnnotations(Optional, Class)} + * and verify that the returned list is not empty. + * * @param element an {@link Optional} containing the element on which to * search for the annotation; may be {@code null} or empty * @param annotationType the annotation type to search for; never {@code null} @@ -61,6 +67,7 @@ * @since 1.3 * @see #isAnnotated(AnnotatedElement, Class) * @see #findAnnotation(Optional, Class) + * @see #findRepeatableAnnotations(Optional, Class) */ @API(status = MAINTAINED, since = "1.3") public static boolean isAnnotated(Optional element, @@ -74,12 +81,17 @@ * present or meta-present on the supplied * {@code element}. * + *

Note: This method does not find repeatable annotations. + * To check for repeatable annotations, use {@link #findRepeatableAnnotations(AnnotatedElement, Class)} + * and verify that the returned list is not empty. + * * @param element the element on which to search for the annotation; may be * {@code null} * @param annotationType the annotation type to search for; never {@code null} * @return {@code true} if the annotation is present or meta-present * @see #isAnnotated(Optional, Class) * @see #findAnnotation(AnnotatedElement, Class) + * @see #findRepeatableAnnotations(AnnotatedElement, Class) */ public static boolean isAnnotated(AnnotatedElement element, Class annotationType) { return AnnotationUtils.isAnnotated(element, annotationType); @@ -153,8 +165,14 @@ * @since 1.8 * @see SearchOption * @see #findAnnotation(AnnotatedElement, Class) + * @deprecated Use {@link #findAnnotation(AnnotatedElement, Class)} + * (for {@code SearchOption.DEFAULT}) or + * {@link #findAnnotation(Class, Class, List)} (for + * {@code SearchOption.INCLUDE_ENCLOSING_CLASSES}) instead */ - @API(status = STABLE, since = "1.10") + @Deprecated + @API(status = DEPRECATED, since = "1.12") + @SuppressWarnings("deprecation") public static Optional findAnnotation(Class clazz, Class annotationType, SearchOption searchOption) { @@ -165,6 +183,56 @@ } /** + * Find the first annotation of the specified type that is either + * directly present, meta-present, or indirectly + * present on the supplied class. + * + *

If the annotation is neither directly present nor meta-present + * on the class, this method will additionally search on interfaces implemented + * by the class before searching for an annotation that is indirectly present + * on the class (i.e., within the class inheritance hierarchy). + * + *

If the annotation still has not been found, this method will optionally + * search recursively through the supplied enclosing instance types, starting + * at the innermost enclosing class (the last one in the supplied list of + * {@code enclosingInstanceTypes}). + * + * @implNote The classes supplied as {@code enclosingInstanceTypes} may + * differ from the classes returned from invocations of + * {@link Class#getEnclosingClass()} — for example, when a nested test + * class is inherited from a superclass. + * + * @param the annotation type + * @param clazz the class on which to search for the annotation; may be {@code null} + * @param annotationType the annotation type to search for; never {@code null} + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances for the class, ordered from outermost to innermost, + * excluding {@code clazz}; never {@code null} + * @return an {@code Optional} containing the annotation; never {@code null} but + * potentially empty if {@code clazz} is not an inner class + * @since 1.12 + * @see #findAnnotation(AnnotatedElement, Class) + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Optional findAnnotation(Class clazz, Class annotationType, + List> enclosingInstanceTypes) { + + Preconditions.notNull(enclosingInstanceTypes, "enclosingInstanceTypes must not be null"); + + Optional annotation = findAnnotation(clazz, annotationType); + if (!annotation.isPresent()) { + ListIterator> iterator = enclosingInstanceTypes.listIterator(enclosingInstanceTypes.size()); + while (iterator.hasPrevious()) { + annotation = findAnnotation(iterator.previous(), annotationType); + if (annotation.isPresent()) { + break; + } + } + } + return annotation; + } + + /** * Find all repeatable {@linkplain Annotation annotations} of the * supplied {@code annotationType} that are either present, * indirectly present, or meta-present on the supplied diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ClassSupport.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ClassSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ClassSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ClassSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -31,6 +31,7 @@ * @see AnnotationSupport * @see ModifierSupport * @see ReflectionSupport + * @see ResourceSupport */ @API(status = MAINTAINED, since = "1.1") public final class ClassSupport { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/DefaultResource.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/DefaultResource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/DefaultResource.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/DefaultResource.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support; + +import java.net.URI; +import java.util.Objects; + +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ToStringBuilder; + +/** + * Default implementation of {@link Resource}. + * + * @since 1.11 + */ +@SuppressWarnings("deprecation") +class DefaultResource implements Resource { + + private final String name; + private final URI uri; + + DefaultResource(String name, URI uri) { + this.name = Preconditions.notNull(name, "name must not be null"); + this.uri = Preconditions.notNull(uri, "uri must not be null"); + } + + @Override + public String getName() { + return name; + } + + @Override + public URI getUri() { + return uri; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof org.junit.platform.commons.io.Resource) { + org.junit.platform.commons.io.Resource that = (org.junit.platform.commons.io.Resource) obj; + return this.name.equals(that.getName()) // + && this.uri.equals(that.getUri()); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(name, uri); + } + + @Override + public String toString() { + return new ToStringBuilder(this) // + .append("name", name) // + .append("uri", uri) // + .toString(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/HierarchyTraversalMode.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/HierarchyTraversalMode.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/HierarchyTraversalMode.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/HierarchyTraversalMode.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ModifierSupport.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ModifierSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ModifierSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ModifierSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -32,6 +32,7 @@ * @see AnnotationSupport * @see ClassSupport * @see ReflectionSupport + * @see ResourceSupport */ @API(status = MAINTAINED, since = "1.4") public final class ModifierSupport { @@ -143,6 +144,32 @@ } /** + * Determine if the supplied class is not {@code abstract}. + * + * @param clazz the class to check; never {@code null} + * @return {@code true} if the class is not {@code abstract} + * @since 1.13 + * @see java.lang.reflect.Modifier#isAbstract(int) + */ + @API(status = MAINTAINED, since = "1.13.3") + public static boolean isNotAbstract(Class clazz) { + return ReflectionUtils.isNotAbstract(clazz); + } + + /** + * Determine if the supplied member is not {@code abstract}. + * + * @param member the class to check; never {@code null} + * @return {@code true} if the member is not {@code abstract} + * @since 1.13 + * @see java.lang.reflect.Modifier#isAbstract(int) + */ + @API(status = MAINTAINED, since = "1.13.3") + public static boolean isNotAbstract(Member member) { + return ReflectionUtils.isNotAbstract(member); + } + + /** * Determine if the supplied class is {@code static}. * * @param clazz the class to check; never {@code null} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,21 +10,25 @@ package org.junit.platform.commons.support; +import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.DEPRECATED; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URI; +import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.io.ResourceFilter; import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; @@ -42,6 +46,7 @@ * @see AnnotationSupport * @see ClassSupport * @see ModifierSupport + * @see ResourceSupport */ @API(status = MAINTAINED, since = "1.0") public final class ReflectionSupport { @@ -67,6 +72,7 @@ */ @API(status = DEPRECATED, since = "1.4") @Deprecated + @SuppressWarnings("deprecation") public static Optional> loadClass(String name) { return ReflectionUtils.loadClass(name); } @@ -87,6 +93,7 @@ * never {@code null} * @since 1.4 * @see #tryToLoadClass(String, ClassLoader) + * @see ResourceSupport#tryToGetResources(String) */ @API(status = MAINTAINED, since = "1.4") public static Try> tryToLoadClass(String name) { @@ -107,13 +114,67 @@ * never {@code null} * @since 1.10 * @see #tryToLoadClass(String) + * @see ResourceSupport#tryToGetResources(String, ClassLoader) */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static Try> tryToLoadClass(String name, ClassLoader classLoader) { return ReflectionUtils.tryToLoadClass(name, classLoader); } /** + * Try to get the {@linkplain Resource resources} for the supplied classpath + * resource name. + * + *

The name of a classpath resource must follow the semantics + * for resource paths as defined in {@link ClassLoader#getResource(String)}. + * + *

If the supplied classpath resource name is prefixed with a slash + * ({@code /}), the slash will be removed. + * + * @param classpathResourceName the name of the resource to load; never + * {@code null} or blank + * @return a successful {@code Try} containing the loaded resources or a failed + * {@code Try} containing the exception if no such resources could be loaded; + * never {@code null} + * @since 1.12 + * @see #tryToGetResources(String, ClassLoader) + * @deprecated Please use {@link ResourceSupport#tryToGetResources(String)} instead + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + public static Try> tryToGetResources(String classpathResourceName) { + return ResourceSupport.tryToGetResources(classpathResourceName) // + .andThenTry(ReflectionSupport::toSupportResourcesSet); + } + + /** + * Try to load the {@linkplain Resource resources} for the supplied classpath + * resource name, using the supplied {@link ClassLoader}. + * + *

The name of a classpath resource must follow the semantics + * for resource paths as defined in {@link ClassLoader#getResource(String)}. + * + *

If the supplied classpath resource name is prefixed with a slash + * ({@code /}), the slash will be removed. + * + * @param classpathResourceName the name of the resource to load; never + * {@code null} or blank + * @param classLoader the {@code ClassLoader} to use; never {@code null} + * @return a successful {@code Try} containing the loaded resources or a failed + * {@code Try} containing the exception if no such resources could be loaded; + * never {@code null} + * @since 1.12 + * @see #tryToGetResources(String) + * @deprecated Please use {@link ResourceSupport#tryToGetResources(String, ClassLoader)} instead + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { + return ResourceSupport.tryToGetResources(classpathResourceName, classLoader) // + .andThenTry(ReflectionSupport::toSupportResourcesSet); + } + + /** * Find all {@linkplain Class classes} in the supplied classpath {@code root} * that match the specified {@code classFilter} and {@code classNameFilter} * predicates. @@ -129,6 +190,7 @@ * but potentially empty * @see #findAllClassesInPackage(String, Predicate, Predicate) * @see #findAllClassesInModule(String, Predicate, Predicate) + * @see ResourceSupport#findAllResourcesInClasspathRoot(URI, ResourceFilter) */ public static List> findAllClassesInClasspathRoot(URI root, Predicate> classFilter, Predicate classNameFilter) { @@ -151,11 +213,13 @@ * @since 1.11 * @see #findAllResourcesInPackage(String, Predicate) * @see #findAllResourcesInModule(String, Predicate) + * @deprecated Please use {@link ResourceSupport#findAllResourcesInClasspathRoot(URI, ResourceFilter)} instead */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = DEPRECATED, since = "1.14") + @Deprecated public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - - return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter); + return toSupportResourcesList( + ResourceSupport.findAllResourcesInClasspathRoot(root, toResourceFilter(resourceFilter))); } /** @@ -175,6 +239,7 @@ * @since 1.10 * @see #streamAllClassesInPackage(String, Predicate, Predicate) * @see #streamAllClassesInModule(String, Predicate, Predicate) + * @see ResourceSupport#streamAllResourcesInClasspathRoot(URI, ResourceFilter) */ @API(status = MAINTAINED, since = "1.10") public static Stream> streamAllClassesInClasspathRoot(URI root, Predicate> classFilter, @@ -198,11 +263,13 @@ * @since 1.11 * @see #streamAllResourcesInPackage(String, Predicate) * @see #streamAllResourcesInModule(String, Predicate) + * @deprecated Please use {@link ResourceSupport#streamAllResourcesInClasspathRoot(URI, ResourceFilter)} instead */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = DEPRECATED, since = "1.14") + @Deprecated public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - - return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter); + return toSupportResourcesStream( + ResourceSupport.streamAllResourcesInClasspathRoot(root, toResourceFilter(resourceFilter))); } /** @@ -222,6 +289,7 @@ * but potentially empty * @see #findAllClassesInClasspathRoot(URI, Predicate, Predicate) * @see #findAllClassesInModule(String, Predicate, Predicate) + * @see ResourceSupport#findAllResourcesInPackage(String, ResourceFilter) */ public static List> findAllClassesInPackage(String basePackageName, Predicate> classFilter, Predicate classNameFilter) { @@ -234,7 +302,8 @@ * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. + * beginning within the supplied base package. The resulting list may include + * identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -245,11 +314,13 @@ * @since 1.11 * @see #findAllResourcesInClasspathRoot(URI, Predicate) * @see #findAllResourcesInModule(String, Predicate) + * @deprecated Please use {@link ResourceSupport#findAllResourcesInPackage(String, ResourceFilter)} instead */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = DEPRECATED, since = "1.14") + @Deprecated public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { - - return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter); + return toSupportResourcesList( + ResourceSupport.findAllResourcesInPackage(basePackageName, toResourceFilter(resourceFilter))); } /** @@ -258,7 +329,8 @@ * predicates. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. + * beginning within the supplied base package. The resulting stream may + * include identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -270,6 +342,7 @@ * @since 1.10 * @see #streamAllClassesInClasspathRoot(URI, Predicate, Predicate) * @see #streamAllClassesInModule(String, Predicate, Predicate) + * @see ResourceSupport#streamAllResourcesInPackage(String, ResourceFilter) */ @API(status = MAINTAINED, since = "1.10") public static Stream> streamAllClassesInPackage(String basePackageName, Predicate> classFilter, @@ -283,7 +356,8 @@ * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. + * beginning within the supplied base package. The resulting stream may + * include identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -294,12 +368,15 @@ * @since 1.11 * @see #streamAllResourcesInClasspathRoot(URI, Predicate) * @see #streamAllResourcesInModule(String, Predicate) + * @deprecated Please use {@link ResourceSupport#streamAllResourcesInPackage(String, ResourceFilter)} instead */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = DEPRECATED, since = "1.14") + @Deprecated public static Stream streamAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter); + return toSupportResourcesStream( + ResourceSupport.streamAllResourcesInPackage(basePackageName, toResourceFilter(resourceFilter))); } /** @@ -319,7 +396,9 @@ * @since 1.1.1 * @see #findAllClassesInClasspathRoot(URI, Predicate, Predicate) * @see #findAllClassesInPackage(String, Predicate, Predicate) + * @see ResourceSupport#findAllResourcesInModule(String, ResourceFilter) */ + @API(status = MAINTAINED, since = "1.1.1") public static List> findAllClassesInModule(String moduleName, Predicate> classFilter, Predicate classNameFilter) { @@ -341,11 +420,13 @@ * @since 1.11 * @see #findAllResourcesInClasspathRoot(URI, Predicate) * @see #findAllResourcesInPackage(String, Predicate) + * @deprecated Please use {@link ResourceSupport#findAllResourcesInModule(String, ResourceFilter)} instead */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = DEPRECATED, since = "1.14") + @Deprecated public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { - - return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter); + return toSupportResourcesList( + ResourceSupport.findAllResourcesInModule(moduleName, toResourceFilter(resourceFilter))); } /** @@ -388,11 +469,13 @@ * @since 1.11 * @see #streamAllResourcesInClasspathRoot(URI, Predicate) * @see #streamAllResourcesInPackage(String, Predicate) + * @deprecated Please use {@link ResourceSupport#streamAllResourcesInModule(String, ResourceFilter)} instead */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = DEPRECATED, since = "1.14") + @Deprecated public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { - - return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter); + return toSupportResourcesStream( + ResourceSupport.streamAllResourcesInModule(moduleName, toResourceFilter(resourceFilter))); } /** @@ -652,4 +735,42 @@ return ReflectionUtils.streamNestedClasses(clazz, predicate); } + /** + * Make the supplied field accessible via reflection. + * + *

If you're looking for similar functionality for constructors or + * methods, consider using {@link #newInstance(Class, Object...)} or + * {@link #invokeMethod(Method, Object, Object...)}. + * + * @param field the field to make accessible; never {@code null} + * @return the supplied field + * @since 1.12 + * @see Field#setAccessible(boolean) + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Field makeAccessible(Field field) { + return ReflectionUtils.makeAccessible(Preconditions.notNull(field, "field must not be null")); + } + + @SuppressWarnings("deprecation") + private static ResourceFilter toResourceFilter(Predicate resourceFilter) { + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); + return ResourceFilter.of(r -> resourceFilter.test(Resource.of(r))); + } + + @SuppressWarnings("deprecation") + static List toSupportResourcesList(List resources) { + return toSupportResourcesStream(resources.stream()).collect(toList()); + } + + @SuppressWarnings("deprecation") + static Set toSupportResourcesSet(Set resources) { + return toSupportResourcesStream(resources.stream()).collect(Collectors.toCollection(LinkedHashSet::new)); + } + + @SuppressWarnings("deprecation") + static Stream toSupportResourcesStream(Stream resources) { + return resources.map(Resource::of); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,17 +10,22 @@ package org.junit.platform.commons.support; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.DEPRECATED; -import java.io.IOException; -import java.io.InputStream; import java.net.URI; import java.util.function.Predicate; import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; /** - * Represents a resource on the classpath. + * {@code Resource} represents a resource on the classpath. + * + *

WARNING: a {@code Resource} must provide correct + * {@link Object#equals(Object) equals} and {@link Object#hashCode() hashCode} + * implementations since a {@code Resource} may potentially be stored in a + * collection or map. + * * @since 1.11 * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate) * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate) @@ -28,34 +33,23 @@ * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate) * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate) * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate) + * @deprecated Please use {@link org.junit.platform.commons.io.Resource} instead. */ -@API(status = EXPERIMENTAL, since = "1.11") -public interface Resource { - - /** - * Get the resource name. - *

- * The resource name is a {@code /}-separated path. The path is relative to - * the classpath root in which the resource is located. - * - * @return the resource name; never {@code null} - */ - String getName(); +@API(status = DEPRECATED, since = "1.14") +@Deprecated +public interface Resource extends org.junit.platform.commons.io.Resource { /** - * Get URI to a resource. + * Create a new {@link Resource} from the supplied + * {@link org.junit.platform.commons.io.Resource}. * - * @return the uri of the resource; never {@code null} + * @param resource the resource to copy attributes from; never {@code null} + * @return a new {@code Resource} + * @since 1.14 */ - URI getUri(); - - /** - * Returns an input stream for reading this resource. - * - * @return an input stream for this resource; never {@code null} - * @throws IOException if an I/O exception occurs - */ - default InputStream getInputStream() throws IOException { - return getUri().toURL().openStream(); + static Resource of(org.junit.platform.commons.io.Resource resource) { + Preconditions.notNull(resource, "resource must not be null"); + return new DefaultResource(resource.getName(), resource.getUri()); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ResourceSupport.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ResourceSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ResourceSupport.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ResourceSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,219 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.net.URI; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.apiguardian.api.API; +import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; +import org.junit.platform.commons.util.ReflectionUtils; + +/** + * {@code ResourceSupport} provides static utility methods for common tasks + * dealing with resources; for example, scanning for resources on the class path + * or module path. + * + *

{@link org.junit.platform.engine.TestEngine TestEngine} and extension + * authors are encouraged to use these supported methods in order to align with + * the behavior of the JUnit Platform. + * + * @since 1.14 + * @see AnnotationSupport + * @see ClassSupport + * @see ModifierSupport + * @see ReflectionSupport + */ +@API(status = MAINTAINED, since = "1.14") +public class ResourceSupport { + + /** + * Try to get the {@linkplain Resource resources} for the supplied classpath + * resource name. + * + *

The name of a classpath resource must follow the semantics + * for resource paths as defined in {@link ClassLoader#getResource(String)}. + * + *

If the supplied classpath resource name is prefixed with a slash + * ({@code /}), the slash will be removed. + * + * @param classpathResourceName the name of the resource to load; never + * {@code null} or blank + * @return a successful {@code Try} containing the set of loaded resources + * (potentially empty) or a failed {@code Try} containing the exception in + * case a failure occurred while trying to list resources; never + * {@code null} + * @see #tryToGetResources(String, ClassLoader) + * @see ReflectionSupport#tryToLoadClass(String) + */ + public static Try> tryToGetResources(String classpathResourceName) { + return ReflectionUtils.tryToGetResources(classpathResourceName); + } + + /** + * Try to load the {@linkplain Resource resources} for the supplied classpath + * resource name, using the supplied {@link ClassLoader}. + * + *

The name of a classpath resource must follow the semantics + * for resource paths as defined in {@link ClassLoader#getResource(String)}. + * + *

If the supplied classpath resource name is prefixed with a slash + * ({@code /}), the slash will be removed. + * + * @param classpathResourceName the name of the resource to load; never + * {@code null} or blank + * @param classLoader the {@code ClassLoader} to use; never {@code null} + * @return a successful {@code Try} containing the set of loaded resources + * (potentially empty) or a failed {@code Try} containing the exception in + * case a failure occurred while trying to list resources; never + * {@code null} + * @see #tryToGetResources(String) + * @see ReflectionSupport#tryToLoadClass(String, ClassLoader) + */ + public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { + return ReflectionUtils.tryToGetResources(classpathResourceName, classLoader); + } + + /** + * Find all {@linkplain Resource resources} in the supplied classpath {@code root} + * that match the specified {@code resourceFilter}. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param root the URI for the classpath root in which to scan; never + * {@code null} + * @param resourceFilter the resource type filter; never {@code null} + * @return an immutable list of all such resources found; never {@code null} + * but potentially empty + * @see #findAllResourcesInPackage(String, ResourceFilter) + * @see #findAllResourcesInModule(String, ResourceFilter) + * @see ReflectionSupport#findAllClassesInClasspathRoot(URI, Predicate, Predicate) + */ + public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter); + } + + /** + * Find all {@linkplain Resource resources} in the supplied classpath {@code root} + * that match the specified {@code resourceFilter}. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param root the URI for the classpath root in which to scan; never + * {@code null} + * @param resourceFilter the resource type filter; never {@code null} + * @return a stream of all such classes found; never {@code null} + * but potentially empty + * @see #streamAllResourcesInPackage(String, ResourceFilter) + * @see #streamAllResourcesInModule(String, ResourceFilter) + * @see ReflectionSupport#streamAllClassesInClasspathRoot(URI, Predicate, Predicate) + */ + public static Stream streamAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter); + } + + /** + * Find all {@linkplain Resource resources} in the supplied {@code basePackageName} + * that match the specified {@code resourceFilter}. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning within the supplied base package. The resulting list may include + * identically named resources from different classpath roots. + * + * @param basePackageName the name of the base package in which to start + * scanning; must not be {@code null} and must be valid in terms of Java + * syntax + * @param resourceFilter the resource type filter; never {@code null} + * @return an immutable list of all such classes found; never {@code null} + * but potentially empty + * @see #findAllResourcesInClasspathRoot(URI, ResourceFilter) + * @see #findAllResourcesInModule(String, ResourceFilter) + * @see ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) + */ + public static List findAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter); + } + + /** + * Find all {@linkplain Resource resources} in the supplied {@code basePackageName} + * that match the specified {@code resourceFilter}. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning within the supplied base package. The resulting stream may + * include identically named resources from different classpath roots. + * + * @param basePackageName the name of the base package in which to start + * scanning; must not be {@code null} and must be valid in terms of Java + * syntax + * @param resourceFilter the resource type filter; never {@code null} + * @return a stream of all such resources found; never {@code null} + * but potentially empty + * @see #streamAllResourcesInClasspathRoot(URI, ResourceFilter) + * @see #streamAllResourcesInModule(String, ResourceFilter) + * @see ReflectionSupport#streamAllClassesInPackage(String, Predicate, Predicate) + */ + public static Stream streamAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter); + } + + /** + * Find all {@linkplain Resource resources} in the supplied {@code moduleName} + * that match the specified {@code resourceFilter}. + * + *

The module-path scanning algorithm searches recursively in all + * packages contained in the module. + * + * @param moduleName the name of the module to scan; never {@code null} or + * empty + * @param resourceFilter the resource type filter; never {@code null} + * @return an immutable list of all such resources found; never {@code null} + * but potentially empty + * @see #findAllResourcesInClasspathRoot(URI, ResourceFilter) + * @see #findAllResourcesInPackage(String, ResourceFilter) + * @see ReflectionSupport#findAllClassesInModule(String, Predicate, Predicate) + */ + public static List findAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter); + } + + /** + * Find all {@linkplain Resource resources} in the supplied {@code moduleName} + * that match the specified {@code resourceFilter}. + * + *

The module-path scanning algorithm searches recursively in all + * packages contained in the module. + * + * @param moduleName the name of the module to scan; never {@code null} or + * empty + * @param resourceFilter the resource type filter; never {@code null} + * @return a stream of all such resources found; never {@code null} + * but potentially empty + * @see #streamAllResourcesInClasspathRoot(URI, ResourceFilter) + * @see #streamAllResourcesInPackage(String, ResourceFilter) + * @see ReflectionSupport#streamAllClassesInModule(String, Predicate, Predicate) + */ + public static Stream streamAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter); + } + + private ResourceSupport() { + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/SearchOption.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/SearchOption.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/SearchOption.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/SearchOption.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.commons.support; -import static org.apiguardian.api.API.Status.STABLE; +import static org.apiguardian.api.API.Status.DEPRECATED; import org.apiguardian.api.API; @@ -20,8 +20,10 @@ * @since 1.8 * @see #DEFAULT * @see #INCLUDE_ENCLOSING_CLASSES + * @deprecated because there is only a single non-deprecated search option left */ -@API(status = STABLE, since = "1.10") +@Deprecated +@API(status = DEPRECATED, since = "1.12") public enum SearchOption { /** @@ -37,7 +39,12 @@ * Search the inheritance hierarchy as with the {@link #DEFAULT} search option * but also search the {@linkplain Class#getEnclosingClass() enclosing class} * hierarchy for inner classes (i.e., a non-static member classes). + * + * @deprecated because it is preferable to inspect the runtime enclosing + * types of a class rather than where they are declared. */ + @Deprecated // + @API(status = DEPRECATED, since = "1.12") INCLUDE_ENCLOSING_CLASSES } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.commons.support.conversion; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; @@ -21,7 +21,7 @@ * * @since 1.11 */ -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public class ConversionException extends JUnitException { private static final long serialVersionUID = 1L; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,7 +12,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableList; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.junit.platform.commons.util.ReflectionUtils.getWrapperType; import java.util.List; @@ -27,7 +27,7 @@ * * @since 1.11 */ -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public final class ConversionSupport { private static final List stringToObjectConverters = unmodifiableList(asList( // diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,12 +10,12 @@ package org.junit.platform.commons.support.conversion; -import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; +import static org.junit.platform.commons.support.HierarchyTraversalMode.BOTTOM_UP; +import static org.junit.platform.commons.support.ModifierSupport.isNotPrivate; +import static org.junit.platform.commons.support.ModifierSupport.isNotStatic; +import static org.junit.platform.commons.support.ReflectionSupport.findMethods; +import static org.junit.platform.commons.support.ReflectionSupport.invokeMethod; import static org.junit.platform.commons.util.ReflectionUtils.findConstructors; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; -import static org.junit.platform.commons.util.ReflectionUtils.invokeMethod; -import static org.junit.platform.commons.util.ReflectionUtils.isNotPrivate; -import static org.junit.platform.commons.util.ReflectionUtils.isNotStatic; import static org.junit.platform.commons.util.ReflectionUtils.newInstance; import java.lang.reflect.Constructor; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.commons.support.conversion; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; class StringToClassConverter implements StringToObjectConverter { @@ -27,7 +27,7 @@ @Override public Object convert(String className, Class targetType, ClassLoader classLoader) throws Exception { // @formatter:off - return ReflectionUtils.tryToLoadClass(className, classLoader) + return ReflectionSupport.tryToLoadClass(className, classLoader) .getOrThrow(cause -> new ConversionException( "Failed to convert String \"" + className + "\" to type java.lang.Class", cause)); // @formatter:on diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /** - * Maintained conversion APIs provided by the JUnit Platform. + * Conversion APIs provided by the JUnit Platform. */ package org.junit.platform.commons.support.conversion; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/package-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /** - * Maintained common support APIs provided by the JUnit Platform. + * Common support APIs provided by the JUnit Platform. * *

The purpose of this package is to provide {@code TestEngine} and * {@code Extension} authors convenient access to a subset of internal utility diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClassFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClassFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClassFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClassFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.scanning; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.function.Predicate; + +import org.apiguardian.api.API; +import org.junit.platform.commons.PreconditionViolationException; + +/** + * Class-related predicate used by reflection utilities. + * + * @since 1.1 + */ +@API(status = MAINTAINED, since = "1.13.3") +public class ClassFilter { + + /** + * Create a {@link ClassFilter} instance that accepts all names but filters classes. + * + * @param classPredicate the class type predicate; never {@code null} + * @return an instance of {@code ClassFilter}; never {@code null} + */ + public static ClassFilter of(Predicate> classPredicate) { + return of(name -> true, classPredicate); + } + + /** + * Create a {@link ClassFilter} instance that filters by names and classes. + * + * @param namePredicate the class name predicate; never {@code null} + * @param classPredicate the class type predicate; never {@code null} + * @return an instance of {@code ClassFilter}; never {@code null} + */ + public static ClassFilter of(Predicate namePredicate, Predicate> classPredicate) { + return new ClassFilter(namePredicate, classPredicate); + } + + private final Predicate namePredicate; + private final Predicate> classPredicate; + + private ClassFilter(Predicate namePredicate, Predicate> classPredicate) { + this.namePredicate = checkNotNull(namePredicate, "name predicate"); + this.classPredicate = checkNotNull(classPredicate, "class predicate"); + } + + // Cannot use Preconditions due to package cycle + private static T checkNotNull(T input, String title) { + if (input == null) { + throw new PreconditionViolationException(title + " must not be null"); + } + return input; + } + + /** + * Test the given name using the stored name predicate. + * + * @param name the name to test; never {@code null} + * @return {@code true} if the input name matches the predicate, otherwise + * {@code false} + */ + public boolean match(String name) { + return namePredicate.test(name); + } + + /** + * Test the given class using the stored class predicate. + * + * @param type the type to test; never {@code null} + * @return {@code true} if the input type matches the predicate, otherwise + * {@code false} + */ + public boolean match(Class type) { + return classPredicate.test(type); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClasspathScanner.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClasspathScanner.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClasspathScanner.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/ClasspathScanner.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,154 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.scanning; + +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.net.URI; +import java.util.List; +import java.util.function.Predicate; + +import org.apiguardian.api.API; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; + +/** + * {@code ClasspathScanner} allows to scan the classpath for classes and + * resources. + * + *

An implementation of this interface can be registered via the + * {@link java.util.ServiceLoader ServiceLoader} mechanism. + * + * @since 1.12 + */ +@API(status = MAINTAINED, since = "1.13.3") +public interface ClasspathScanner { + + /** + * Find all {@linkplain Class classes} in the supplied classpath {@code root} + * that match the specified {@code classFilter} filter. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param basePackageName the name of the base package in which to start + * scanning; must not be {@code null} and must be valid in terms of Java + * syntax + * @param classFilter the class type filter; never {@code null} + * @return a list of all such classes found; never {@code null} + * but potentially empty + */ + List> scanForClassesInPackage(String basePackageName, ClassFilter classFilter); + + /** + * Find all {@linkplain Class classes} in the supplied classpath {@code root} + * that match the specified {@code classFilter} filter. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param root the URI for the classpath root in which to scan; never + * {@code null} + * @param classFilter the class type filter; never {@code null} + * @return a list of all such classes found; never {@code null} + * but potentially empty + */ + List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter); + + /** + * Find all {@linkplain org.junit.platform.commons.support.Resource resources} in the supplied classpath {@code root} + * that match the specified {@code resourceFilter} predicate. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param basePackageName the name of the base package in which to start + * scanning; must not be {@code null} and must be valid in terms of Java + * syntax + * @param resourceFilter the resource type filter; never {@code null} + * @return a list of all such resources found; never {@code null} + * but potentially empty + * @deprecated Please implement + * {@link #scanForResourcesInPackage(String, ResourceFilter)} instead + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + @SuppressWarnings("unused") + default List scanForResourcesInPackage(String basePackageName, + Predicate resourceFilter) { + throw new UnsupportedOperationException("Implement scanForResourcesInPackage(String, ResourceFilter) instead"); + } + + /** + * Find all {@linkplain org.junit.platform.commons.support.Resource resources} in the supplied classpath {@code root} + * that match the specified {@code resourceFilter} predicate. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param root the URI for the classpath root in which to scan; never + * {@code null} + * @param resourceFilter the resource type filter; never {@code null} + * @return a list of all such resources found; never {@code null} + * but potentially empty + * @deprecated Please implement + * {@link #scanForResourcesInClasspathRoot(URI, ResourceFilter)} instead + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + @SuppressWarnings("unused") + default List scanForResourcesInClasspathRoot(URI root, + Predicate resourceFilter) { + throw new UnsupportedOperationException( + "Implement scanForResourcesInClasspathRoot(URI, ResourceFilter) instead"); + } + + /** + * Find all {@linkplain Resource resources} in the supplied classpath {@code root} + * that match the specified {@code resourceFilter} predicate. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param basePackageName the name of the base package in which to start + * scanning; must not be {@code null} and must be valid in terms of Java + * syntax + * @param resourceFilter the resource type filter; never {@code null} + * @return a list of all such resources found; never {@code null} + * but potentially empty + * @since 1.14 + */ + @API(status = MAINTAINED, since = "1.14") + default List scanForResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + return scanForResourcesInPackage(basePackageName, resourceFilter::match); + } + + /** + * Find all {@linkplain Resource resources} in the supplied classpath {@code root} + * that match the specified {@code resourceFilter} predicate. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param root the URI for the classpath root in which to scan; never + * {@code null} + * @param resourceFilter the resource type filter; never {@code null} + * @return a list of all such resources found; never {@code null} + * but potentially empty + * @since 1.14 + */ + @API(status = MAINTAINED, since = "1.14") + default List scanForResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + return scanForResourcesInClasspathRoot(root, resourceFilter::match); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/support/scanning/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,5 @@ +/** + * Classpath scanning APIs provided by the JUnit Platform. + */ + +package org.junit.platform.commons.support.scanning; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/BlacklistedExceptions.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/BlacklistedExceptions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/BlacklistedExceptions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/BlacklistedExceptions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFilter.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.util.function.Predicate; - -import org.apiguardian.api.API; - -/** - * Class-related predicate used by reflection utilities. - * - *

DISCLAIMER

- * - *

These utilities are intended solely for usage within the JUnit framework - * itself. Any usage by external parties is not supported. - * Use at your own risk! - * - * @since 1.1 - */ -@API(status = INTERNAL, since = "1.1") -public class ClassFilter implements Predicate> { - - /** - * Create a {@link ClassFilter} instance that accepts all names but filters classes. - */ - public static ClassFilter of(Predicate> classPredicate) { - return of(name -> true, classPredicate); - } - - /** - * Create a {@link ClassFilter} instance that filters by names and classes. - */ - public static ClassFilter of(Predicate namePredicate, Predicate> classPredicate) { - return new ClassFilter(namePredicate, classPredicate); - } - - private final Predicate namePredicate; - private final Predicate> classPredicate; - - private ClassFilter(Predicate namePredicate, Predicate> classPredicate) { - this.namePredicate = Preconditions.notNull(namePredicate, "name predicate must not be null"); - this.classPredicate = Preconditions.notNull(classPredicate, "class predicate must not be null"); - } - - /** - * Test name using the stored name predicate. - */ - public boolean match(String name) { - return namePredicate.test(name); - } - - /** - * Test class using the stored class predicate. - */ - public boolean match(Class type) { - return classPredicate.test(type); - } - - /** - * @implNote This implementation combines all tests stored in the predicates - * of this instance. Any new predicate must be added to this test method as - * well. - */ - @Override - public boolean test(Class type) { - return match(type.getName()) && match(type); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassLoaderUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassLoaderUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassLoaderUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassLoaderUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassNamePatternFilterUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassNamePatternFilterUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassNamePatternFilterUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassNamePatternFilterUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -41,7 +41,9 @@ /* no-op */ } - public static final String DEACTIVATE_ALL_PATTERN = "*"; + public static final String ALL_PATTERN = "*"; + + public static final String BLANK = ""; /** * Create a {@link Predicate} that can be used to exclude (i.e., filter out) @@ -51,7 +53,7 @@ * @param patterns a comma-separated list of patterns */ public static Predicate excludeMatchingClasses(String patterns) { - return excludeMatchingClasses(patterns, object -> object.getClass().getName()); + return matchingClasses(patterns, object -> object.getClass().getName(), FilterType.EXCLUDE); } /** @@ -61,26 +63,57 @@ * @param patterns a comma-separated list of patterns */ public static Predicate excludeMatchingClassNames(String patterns) { - return excludeMatchingClasses(patterns, Function.identity()); + return matchingClasses(patterns, Function.identity(), FilterType.EXCLUDE); + } + + /** + * Create a {@link Predicate} that can be used to include (i.e., filter in) + * objects of type {@code T} whose fully qualified class names match any of + * the supplied patterns. + * + * @param patterns a comma-separated list of patterns + */ + public static Predicate includeMatchingClasses(String patterns) { + return matchingClasses(patterns, object -> object.getClass().getName(), FilterType.INCLUDE); } - private static Predicate excludeMatchingClasses(String patterns, Function classNameGetter) { + /** + * Create a {@link Predicate} that can be used to include (i.e., filter in) + * fully qualified class names matching any of the supplied patterns. + * + * @param patterns a comma-separated list of patterns + */ + public static Predicate includeMatchingClassNames(String patterns) { + return matchingClasses(patterns, Function.identity(), FilterType.INCLUDE); + } + + private enum FilterType { + INCLUDE, EXCLUDE + } + + private static Predicate matchingClasses(String patterns, Function classNameProvider, + FilterType type) { // @formatter:off return Optional.ofNullable(patterns) .filter(StringUtils::isNotBlank) .map(String::trim) - .map(trimmedPatterns -> createPredicateFromPatterns(trimmedPatterns, classNameGetter)) - .orElse(object -> true); + .map(trimmedPatterns -> createPredicateFromPatterns(trimmedPatterns, classNameProvider, type)) + .orElse(type == FilterType.EXCLUDE ? __ -> true : __ -> false); // @formatter:on } - private static Predicate createPredicateFromPatterns(String patterns, - Function classNameProvider) { - if (DEACTIVATE_ALL_PATTERN.equals(patterns)) { - return object -> false; + private static Predicate createPredicateFromPatterns(String patterns, Function classNameProvider, + FilterType type) { + if (ALL_PATTERN.equals(patterns)) { + return type == FilterType.INCLUDE ? __ -> true : __ -> false; } + List patternList = convertToRegularExpressions(patterns); - return object -> patternList.stream().noneMatch(it -> it.matcher(classNameProvider.apply(object)).matches()); + return object -> { + boolean isMatchingAnyPattern = patternList.stream().anyMatch( + pattern -> pattern.matcher(classNameProvider.apply(object)).matches()); + return (type == FilterType.INCLUDE) == isMatchingAnyPattern; + }; } private static List convertToRegularExpressions(String patterns) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import java.net.URI; -import java.util.Objects; - -import org.junit.platform.commons.support.Resource; - -/** - * @since 1.11 - */ -class ClasspathResource implements Resource { - - private final String name; - private final URI uri; - - ClasspathResource(String name, URI uri) { - this.name = Preconditions.notNull(name, "name must not be null"); - this.uri = Preconditions.notNull(uri, "uri must not be null"); - } - - @Override - public String getName() { - return name; - } - - @Override - public URI getUri() { - return uri; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - ClasspathResource that = (ClasspathResource) o; - return name.equals(that.name) && uri.equals(that.uri); - } - - @Override - public int hashCode() { - return Objects.hash(name, uri); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,349 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; -import static org.junit.platform.commons.util.ClasspathFilters.CLASS_FILE_SUFFIX; -import static org.junit.platform.commons.util.StringUtils.isNotBlank; - -import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.function.Try; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.support.Resource; - -/** - *

DISCLAIMER

- * - *

These utilities are intended solely for usage within the JUnit framework - * itself. Any usage by external parties is not supported. - * Use at your own risk! - * - * @since 1.0 - */ -class ClasspathScanner { - - private static final Logger logger = LoggerFactory.getLogger(ClasspathScanner.class); - - private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; - private static final String CLASSPATH_RESOURCE_PATH_SEPARATOR_STRING = String.valueOf( - CLASSPATH_RESOURCE_PATH_SEPARATOR); - private static final char PACKAGE_SEPARATOR_CHAR = '.'; - private static final String PACKAGE_SEPARATOR_STRING = String.valueOf(PACKAGE_SEPARATOR_CHAR); - - /** - * Malformed class name InternalError like reported in #401. - */ - private static final String MALFORMED_CLASS_NAME_ERROR_MESSAGE = "Malformed class name"; - - private final Supplier classLoaderSupplier; - - private final BiFunction>> loadClass; - - ClasspathScanner(Supplier classLoaderSupplier, - BiFunction>> loadClass) { - - this.classLoaderSupplier = classLoaderSupplier; - this.loadClass = loadClass; - } - - List> scanForClassesInPackage(String basePackageName, ClassFilter classFilter) { - Preconditions.condition( - PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), - "basePackageName must not be null or blank"); - Preconditions.notNull(classFilter, "classFilter must not be null"); - basePackageName = basePackageName.trim(); - - List roots = getRootUrisForPackageNameOnClassPathAndModulePath(basePackageName); - return findClassesForUris(roots, basePackageName, classFilter); - } - - List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) { - Preconditions.notNull(root, "root must not be null"); - Preconditions.notNull(classFilter, "classFilter must not be null"); - - return findClassesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, classFilter); - } - - List scanForResourcesInPackage(String basePackageName, Predicate resourceFilter) { - Preconditions.condition( - PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), - "basePackageName must not be null or blank"); - Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); - basePackageName = basePackageName.trim(); - - List roots = getRootUrisForPackageNameOnClassPathAndModulePath(basePackageName); - return findResourcesForUris(roots, basePackageName, resourceFilter); - } - - List scanForResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - Preconditions.notNull(root, "root must not be null"); - Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); - - return findResourcesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, resourceFilter); - } - - /** - * Recursively scan for classes in all the supplied source directories. - */ - private List> findClassesForUris(List baseUris, String basePackageName, ClassFilter classFilter) { - // @formatter:off - return baseUris.stream() - .map(baseUri -> findClassesForUri(baseUri, basePackageName, classFilter)) - .flatMap(Collection::stream) - .distinct() - .collect(toList()); - // @formatter:on - } - - private List> findClassesForUri(URI baseUri, String basePackageName, ClassFilter classFilter) { - List> classes = new ArrayList<>(); - // @formatter:off - walkFilesForUri(baseUri, ClasspathFilters.classFiles(), - (baseDir, file) -> - processClassFileSafely(baseDir, basePackageName, classFilter, file, classes::add)); - // @formatter:on - return classes; - } - - /** - * Recursively scan for resources in all the supplied source directories. - */ - private List findResourcesForUris(List baseUris, String basePackageName, - Predicate resourceFilter) { - // @formatter:off - return baseUris.stream() - .map(baseUri -> findResourcesForUri(baseUri, basePackageName, resourceFilter)) - .flatMap(Collection::stream) - .distinct() - .collect(toList()); - // @formatter:on - } - - private List findResourcesForUri(URI baseUri, String basePackageName, - Predicate resourceFilter) { - List resources = new ArrayList<>(); - // @formatter:off - walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), - (baseDir, file) -> - processResourceFileSafely(baseDir, basePackageName, resourceFilter, file, resources::add)); - // @formatter:on - return resources; - } - - private static void walkFilesForUri(URI baseUri, Predicate filter, BiConsumer consumer) { - try (CloseablePath closeablePath = CloseablePath.create(baseUri)) { - Path baseDir = closeablePath.getPath(); - Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); - try { - Files.walkFileTree(baseDir, new ClasspathFileVisitor(baseDir, filter, consumer)); - } - catch (IOException ex) { - logger.warn(ex, () -> "I/O error scanning files in " + baseDir); - } - } - catch (PreconditionViolationException ex) { - throw ex; - } - catch (Exception ex) { - logger.warn(ex, () -> "Error scanning files for URI " + baseUri); - } - } - - private void processClassFileSafely(Path baseDir, String basePackageName, ClassFilter classFilter, Path classFile, - Consumer> classConsumer) { - try { - String fullyQualifiedClassName = determineFullyQualifiedClassName(baseDir, basePackageName, classFile); - if (classFilter.match(fullyQualifiedClassName)) { - try { - // @formatter:off - loadClass.apply(fullyQualifiedClassName, getClassLoader()) - .toOptional() - // Always use ".filter(classFilter)" to include future predicates. - .filter(classFilter) - .ifPresent(classConsumer); - // @formatter:on - } - catch (InternalError internalError) { - handleInternalError(classFile, fullyQualifiedClassName, internalError); - } - } - } - catch (Throwable throwable) { - handleThrowable(classFile, throwable); - } - } - - private void processResourceFileSafely(Path baseDir, String basePackageName, Predicate resourceFilter, - Path resourceFile, Consumer resourceConsumer) { - try { - String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, - resourceFile); - Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); - if (resourceFilter.test(resource)) { - resourceConsumer.accept(resource); - } - // @formatter:on - } - catch (Throwable throwable) { - handleThrowable(resourceFile, throwable); - } - } - - private String determineFullyQualifiedClassName(Path baseDir, String basePackageName, Path classFile) { - // @formatter:off - return Stream.of( - basePackageName, - determineSubpackageName(baseDir, classFile), - determineSimpleClassName(classFile) - ) - .filter(value -> !value.isEmpty()) // Handle default package appropriately. - .collect(joining(PACKAGE_SEPARATOR_STRING)); - // @formatter:on - } - - /** - * The fully qualified resource name is a {@code /}-separated path. - *

- * The path is relative to the classpath root in which the resource is located. - - * @return the resource name; never {@code null} - */ - private String determineFullyQualifiedResourceName(Path baseDir, String basePackageName, Path resourceFile) { - // @formatter:off - return Stream.of( - packagePath(basePackageName), - packagePath(determineSubpackageName(baseDir, resourceFile)), - determineSimpleResourceName(resourceFile) - ) - .filter(value -> !value.isEmpty()) // Handle default package appropriately. - .collect(joining(CLASSPATH_RESOURCE_PATH_SEPARATOR_STRING)); - // @formatter:on - } - - private String determineSimpleClassName(Path classFile) { - String fileName = classFile.getFileName().toString(); - return fileName.substring(0, fileName.length() - CLASS_FILE_SUFFIX.length()); - } - - private String determineSimpleResourceName(Path resourceFile) { - return resourceFile.getFileName().toString(); - } - - private String determineSubpackageName(Path baseDir, Path classFile) { - Path relativePath = baseDir.relativize(classFile.getParent()); - String pathSeparator = baseDir.getFileSystem().getSeparator(); - String subpackageName = relativePath.toString().replace(pathSeparator, PACKAGE_SEPARATOR_STRING); - if (subpackageName.endsWith(pathSeparator)) { - // Workaround for JDK bug: https://bugs.openjdk.java.net/browse/JDK-8153248 - subpackageName = subpackageName.substring(0, subpackageName.length() - pathSeparator.length()); - } - return subpackageName; - } - - private void handleInternalError(Path classFile, String fullyQualifiedClassName, InternalError ex) { - if (MALFORMED_CLASS_NAME_ERROR_MESSAGE.equals(ex.getMessage())) { - logMalformedClassName(classFile, fullyQualifiedClassName, ex); - } - else { - logGenericFileProcessingException(classFile, ex); - } - } - - private void handleThrowable(Path classFile, Throwable throwable) { - UnrecoverableExceptions.rethrowIfUnrecoverable(throwable); - logGenericFileProcessingException(classFile, throwable); - } - - private void logMalformedClassName(Path classFile, String fullyQualifiedClassName, InternalError ex) { - try { - logger.debug(ex, () -> format("The java.lang.Class loaded from path [%s] has a malformed class name [%s].", - classFile.toAbsolutePath(), fullyQualifiedClassName)); - } - catch (Throwable t) { - UnrecoverableExceptions.rethrowIfUnrecoverable(t); - ex.addSuppressed(t); - logGenericFileProcessingException(classFile, ex); - } - } - - private void logGenericFileProcessingException(Path classpathFile, Throwable throwable) { - logger.debug(throwable, - () -> format("Failed to load [%s] during classpath scanning.", classpathFile.toAbsolutePath())); - } - - private ClassLoader getClassLoader() { - return this.classLoaderSupplier.get(); - } - - private List getRootUrisForPackageNameOnClassPathAndModulePath(String basePackageName) { - Set uriSet = new LinkedHashSet<>(getRootUrisForPackage(basePackageName)); - if (!basePackageName.isEmpty() && !basePackageName.endsWith(PACKAGE_SEPARATOR_STRING)) { - getRootUrisForPackage(basePackageName + PACKAGE_SEPARATOR_STRING).stream() // - .map(ClasspathScanner::removeTrailingClasspathResourcePathSeparator) // - .forEach(uriSet::add); - } - return new ArrayList<>(uriSet); - } - - private static URI removeTrailingClasspathResourcePathSeparator(URI uri) { - String string = uri.toString(); - if (string.endsWith(CLASSPATH_RESOURCE_PATH_SEPARATOR_STRING)) { - return URI.create(string.substring(0, string.length() - 1)); - } - return uri; - } - - private static String packagePath(String packageName) { - if (packageName.isEmpty()) { - return ""; - } - return packageName.replace(PACKAGE_SEPARATOR_CHAR, CLASSPATH_RESOURCE_PATH_SEPARATOR); - } - - private List getRootUrisForPackage(String basePackageName) { - try { - Enumeration resources = getClassLoader().getResources(packagePath(basePackageName)); - List uris = new ArrayList<>(); - while (resources.hasMoreElements()) { - URL resource = resources.nextElement(); - uris.add(resource.toURI()); - } - return uris; - } - catch (Exception ex) { - logger.warn(ex, () -> "Error reading URIs from class loader for base package " + basePackageName); - return emptyList(); - } - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScannerLoader.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScannerLoader.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScannerLoader.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScannerLoader.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static java.util.stream.Collectors.toList; +import static java.util.stream.StreamSupport.stream; + +import java.util.List; +import java.util.ServiceLoader; + +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.scanning.ClasspathScanner; + +/** + * @since 1.12 + */ +class ClasspathScannerLoader { + + static ClasspathScanner getInstance() { + ServiceLoader serviceLoader = ServiceLoader.load(ClasspathScanner.class, + ClassLoaderUtils.getDefaultClassLoader()); + + List classpathScanners = stream(serviceLoader.spliterator(), false).collect(toList()); + + if (classpathScanners.size() == 1) { + return classpathScanners.get(0); + } + + if (classpathScanners.size() > 1) { + throw new JUnitException(String.format( + "There should not be more than one ClasspathScanner implementation present on the classpath but there were %d: %s", + classpathScanners.size(), classpathScanners)); + } + + return new DefaultClasspathScanner(ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CollectionUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CollectionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CollectionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CollectionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,8 +16,10 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.StreamSupport.stream; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.util.ReflectionUtils.invokeMethod; import java.lang.reflect.Array; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -126,8 +128,7 @@ *

 	 * public static <T> Collector<T, ?, List<T>> toUnmodifiableList(Supplier<List<T>> listSupplier) {
 	 *     return Collectors.collectingAndThen(Collectors.toCollection(listSupplier), Collections::unmodifiableList);
-	 * }
-	 * 
+ * }
* * @param the type of the input elements * @return a {@code Collector} which collects all the input elements into @@ -162,7 +163,8 @@ || Iterable.class.isAssignableFrom(type)// || Iterator.class.isAssignableFrom(type)// || Object[].class.isAssignableFrom(type)// - || (type.isArray() && type.getComponentType().isPrimitive())); + || (type.isArray() && type.getComponentType().isPrimitive())// + || findIteratorMethod(type).isPresent()); } /** @@ -178,6 +180,9 @@ *
  • {@link Iterator}
  • *
  • {@link Object} array
  • *
  • primitive array
  • + *
  • any type that provides an + * {@link java.util.Iterator Iterator}-returning {@code iterator()} method + * (such as, for example, a {@code kotlin.sequences.Sequence})
  • * * * @param object the object to convert into a stream; never {@code null} @@ -224,8 +229,21 @@ if (object.getClass().isArray() && object.getClass().getComponentType().isPrimitive()) { return IntStream.range(0, Array.getLength(object)).mapToObj(i -> Array.get(object, i)); } - throw new PreconditionViolationException( - "Cannot convert instance of " + object.getClass().getName() + " into a Stream: " + object); + return tryConvertToStreamByReflection(object); + } + + private static Stream tryConvertToStreamByReflection(Object object) { + return findIteratorMethod(object.getClass()) // + .map(method -> (Iterator) invokeMethod(method, object)) // + .map(iterator -> spliteratorUnknownSize(iterator, ORDERED)) // + .map(spliterator -> stream(spliterator, false)) // + .orElseThrow(() -> new PreconditionViolationException(String.format( + "Cannot convert instance of %s into a Stream: %s", object.getClass().getName(), object))); + } + + private static Optional findIteratorMethod(Class type) { + return ReflectionUtils.findMethod(type, "iterator") // + .filter(method -> method.getReturnType() == Iterator.class); } /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/DefaultClasspathScanner.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/DefaultClasspathScanner.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/DefaultClasspathScanner.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/DefaultClasspathScanner.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,355 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; +import static org.junit.platform.commons.util.ClasspathFilters.CLASS_FILE_SUFFIX; +import static org.junit.platform.commons.util.StringUtils.isNotBlank; + +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.scanning.ClassFilter; +import org.junit.platform.commons.support.scanning.ClasspathScanner; + +/** + *

    DISCLAIMER

    + * + *

    These utilities are intended solely for usage within the JUnit framework + * itself. Any usage by external parties is not supported. + * Use at your own risk! + * + * @since 1.0 + */ +class DefaultClasspathScanner implements ClasspathScanner { + + private static final Logger logger = LoggerFactory.getLogger(DefaultClasspathScanner.class); + + private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; + private static final String CLASSPATH_RESOURCE_PATH_SEPARATOR_STRING = String.valueOf( + CLASSPATH_RESOURCE_PATH_SEPARATOR); + private static final char PACKAGE_SEPARATOR_CHAR = '.'; + private static final String PACKAGE_SEPARATOR_STRING = String.valueOf(PACKAGE_SEPARATOR_CHAR); + + /** + * Malformed class name InternalError like reported in #401. + */ + private static final String MALFORMED_CLASS_NAME_ERROR_MESSAGE = "Malformed class name"; + + private final Supplier classLoaderSupplier; + + private final BiFunction>> loadClass; + + DefaultClasspathScanner(Supplier classLoaderSupplier, + BiFunction>> loadClass) { + + this.classLoaderSupplier = classLoaderSupplier; + this.loadClass = loadClass; + } + + @Override + public List> scanForClassesInPackage(String basePackageName, ClassFilter classFilter) { + Preconditions.condition( + PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), + "basePackageName must not be null or blank"); + Preconditions.notNull(classFilter, "classFilter must not be null"); + basePackageName = basePackageName.trim(); + + List roots = getRootUrisForPackageNameOnClassPathAndModulePath(basePackageName); + return findClassesForUris(roots, basePackageName, classFilter); + } + + @Override + public List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) { + Preconditions.notNull(root, "root must not be null"); + Preconditions.notNull(classFilter, "classFilter must not be null"); + + return findClassesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, classFilter); + } + + @Override + public List scanForResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + Preconditions.condition( + PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), + "basePackageName must not be null or blank"); + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); + basePackageName = basePackageName.trim(); + + List roots = getRootUrisForPackageNameOnClassPathAndModulePath(basePackageName); + return findResourcesForUris(roots, basePackageName, resourceFilter); + } + + @Override + public List scanForResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + Preconditions.notNull(root, "root must not be null"); + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); + + return findResourcesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, resourceFilter); + } + + /** + * Recursively scan for classes in all the supplied source directories. + */ + private List> findClassesForUris(List baseUris, String basePackageName, ClassFilter classFilter) { + // @formatter:off + return baseUris.stream() + .map(baseUri -> findClassesForUri(baseUri, basePackageName, classFilter)) + .flatMap(Collection::stream) + .distinct() + .collect(toList()); + // @formatter:on + } + + private List> findClassesForUri(URI baseUri, String basePackageName, ClassFilter classFilter) { + List> classes = new ArrayList<>(); + // @formatter:off + walkFilesForUri(baseUri, ClasspathFilters.classFiles(), + (baseDir, file) -> + processClassFileSafely(baseDir, basePackageName, classFilter, file, classes::add)); + // @formatter:on + return classes; + } + + /** + * Recursively scan for resources in all the supplied source directories. + */ + private List findResourcesForUris(List baseUris, String basePackageName, + ResourceFilter resourceFilter) { + // @formatter:off + return baseUris.stream() + .map(baseUri -> findResourcesForUri(baseUri, basePackageName, resourceFilter)) + .flatMap(Collection::stream) + .distinct() + .collect(toList()); + // @formatter:on + } + + private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { + List resources = new ArrayList<>(); + // @formatter:off + walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), + (baseDir, file) -> + processResourceFileSafely(baseDir, basePackageName, resourceFilter, file, resources::add)); + // @formatter:on + return resources; + } + + private static void walkFilesForUri(URI baseUri, Predicate filter, BiConsumer consumer) { + try (CloseablePath closeablePath = CloseablePath.create(baseUri)) { + Path baseDir = closeablePath.getPath(); + Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); + try { + Files.walkFileTree(baseDir, new ClasspathFileVisitor(baseDir, filter, consumer)); + } + catch (IOException ex) { + logger.warn(ex, () -> "I/O error scanning files in " + baseDir); + } + } + catch (PreconditionViolationException ex) { + throw ex; + } + catch (Exception ex) { + logger.warn(ex, () -> "Error scanning files for URI " + baseUri); + } + } + + private void processClassFileSafely(Path baseDir, String basePackageName, ClassFilter classFilter, Path classFile, + Consumer> classConsumer) { + try { + String fullyQualifiedClassName = determineFullyQualifiedClassName(baseDir, basePackageName, classFile); + if (classFilter.match(fullyQualifiedClassName)) { + try { + // @formatter:off + loadClass.apply(fullyQualifiedClassName, getClassLoader()) + .toOptional() + .filter(classFilter::match) + .ifPresent(classConsumer); + // @formatter:on + } + catch (InternalError internalError) { + handleInternalError(classFile, fullyQualifiedClassName, internalError); + } + } + } + catch (Throwable throwable) { + handleThrowable(classFile, throwable); + } + } + + private void processResourceFileSafely(Path baseDir, String basePackageName, ResourceFilter resourceFilter, + Path resourceFile, Consumer resourceConsumer) { + try { + String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, + resourceFile); + Resource resource = Resource.of(fullyQualifiedResourceName, resourceFile.toUri()); + if (resourceFilter.match(resource)) { + resourceConsumer.accept(resource); + } + // @formatter:on + } + catch (Throwable throwable) { + handleThrowable(resourceFile, throwable); + } + } + + private String determineFullyQualifiedClassName(Path baseDir, String basePackageName, Path classFile) { + // @formatter:off + return Stream.of( + basePackageName, + determineSubpackageName(baseDir, classFile), + determineSimpleClassName(classFile) + ) + .filter(value -> !value.isEmpty()) // Handle default package appropriately. + .collect(joining(PACKAGE_SEPARATOR_STRING)); + // @formatter:on + } + + /** + * The fully qualified resource name is a {@code /}-separated path. + * + *

    The path is relative to the classpath root in which the resource is + * located. + * + * @return the resource name; never {@code null} + */ + private String determineFullyQualifiedResourceName(Path baseDir, String basePackageName, Path resourceFile) { + // @formatter:off + return Stream.of( + packagePath(basePackageName), + packagePath(determineSubpackageName(baseDir, resourceFile)), + determineSimpleResourceName(resourceFile) + ) + .filter(value -> !value.isEmpty()) // Handle default package appropriately. + .collect(joining(CLASSPATH_RESOURCE_PATH_SEPARATOR_STRING)); + // @formatter:on + } + + private String determineSimpleClassName(Path classFile) { + String fileName = classFile.getFileName().toString(); + return fileName.substring(0, fileName.length() - CLASS_FILE_SUFFIX.length()); + } + + private String determineSimpleResourceName(Path resourceFile) { + return resourceFile.getFileName().toString(); + } + + private String determineSubpackageName(Path baseDir, Path classFile) { + Path relativePath = baseDir.relativize(classFile.getParent()); + String pathSeparator = baseDir.getFileSystem().getSeparator(); + String subpackageName = relativePath.toString().replace(pathSeparator, PACKAGE_SEPARATOR_STRING); + if (subpackageName.endsWith(pathSeparator)) { + // Workaround for JDK bug: https://bugs.openjdk.java.net/browse/JDK-8153248 + subpackageName = subpackageName.substring(0, subpackageName.length() - pathSeparator.length()); + } + return subpackageName; + } + + private void handleInternalError(Path classFile, String fullyQualifiedClassName, InternalError ex) { + if (MALFORMED_CLASS_NAME_ERROR_MESSAGE.equals(ex.getMessage())) { + logMalformedClassName(classFile, fullyQualifiedClassName, ex); + } + else { + logGenericFileProcessingException(classFile, ex); + } + } + + private void handleThrowable(Path classFile, Throwable throwable) { + UnrecoverableExceptions.rethrowIfUnrecoverable(throwable); + logGenericFileProcessingException(classFile, throwable); + } + + private void logMalformedClassName(Path classFile, String fullyQualifiedClassName, InternalError ex) { + try { + logger.debug(ex, () -> format("The java.lang.Class loaded from path [%s] has a malformed class name [%s].", + classFile.toAbsolutePath(), fullyQualifiedClassName)); + } + catch (Throwable t) { + UnrecoverableExceptions.rethrowIfUnrecoverable(t); + ex.addSuppressed(t); + logGenericFileProcessingException(classFile, ex); + } + } + + private void logGenericFileProcessingException(Path classpathFile, Throwable throwable) { + logger.debug(throwable, + () -> format("Failed to load [%s] during classpath scanning.", classpathFile.toAbsolutePath())); + } + + private ClassLoader getClassLoader() { + return this.classLoaderSupplier.get(); + } + + private List getRootUrisForPackageNameOnClassPathAndModulePath(String basePackageName) { + Set uriSet = new LinkedHashSet<>(getRootUrisForPackage(basePackageName)); + if (!basePackageName.isEmpty() && !basePackageName.endsWith(PACKAGE_SEPARATOR_STRING)) { + getRootUrisForPackage(basePackageName + PACKAGE_SEPARATOR_STRING).stream() // + .map(DefaultClasspathScanner::removeTrailingClasspathResourcePathSeparator) // + .forEach(uriSet::add); + } + return new ArrayList<>(uriSet); + } + + private static URI removeTrailingClasspathResourcePathSeparator(URI uri) { + String string = uri.toString(); + if (string.endsWith(CLASSPATH_RESOURCE_PATH_SEPARATOR_STRING)) { + return URI.create(string.substring(0, string.length() - 1)); + } + return uri; + } + + private static String packagePath(String packageName) { + if (packageName.isEmpty()) { + return ""; + } + return packageName.replace(PACKAGE_SEPARATOR_CHAR, CLASSPATH_RESOURCE_PATH_SEPARATOR); + } + + private List getRootUrisForPackage(String basePackageName) { + try { + Enumeration resources = getClassLoader().getResources(packagePath(basePackageName)); + List uris = new ArrayList<>(); + while (resources.hasMoreElements()) { + URL resource = resources.nextElement(); + uris.add(resource.toURI()); + } + return uris; + } + catch (Exception ex) { + logger.warn(ex, () -> "Error reading URIs from class loader for base package " + basePackageName); + return emptyList(); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/FunctionUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/FunctionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/FunctionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/FunctionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/KotlinReflectionUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/KotlinReflectionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/KotlinReflectionUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/KotlinReflectionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.util.ReflectionUtils.EMPTY_CLASS_ARRAY; +import static org.junit.platform.commons.util.ReflectionUtils.findMethod; +import static org.junit.platform.commons.util.ReflectionUtils.isStatic; +import static org.junit.platform.commons.util.ReflectionUtils.tryToLoadClass; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Arrays; + +import org.apiguardian.api.API; +import org.junit.platform.commons.function.Try; + +/** + * Internal Kotlin-specific reflection utilities + * + * @since 1.13.3 + */ +@API(status = INTERNAL, since = "1.13.3") +public class KotlinReflectionUtils { + + private static final String DEFAULT_IMPLS_CLASS_NAME = "DefaultImpls"; + + private static final Class kotlinMetadata; + + static { + Try> metadata = tryToLoadKotlinMetadataClass(); + kotlinMetadata = metadata.toOptional().orElse(null); + } + + @SuppressWarnings("unchecked") + private static Try> tryToLoadKotlinMetadataClass() { + return tryToLoadClass("kotlin.Metadata") // + .andThenTry(it -> (Class) it); + } + + /** + * Determines whether the supplied class is a {@code DefaultImpls} class + * generated by the Kotlin compiler. + * + *

    See + * Kotlin documentation + * for details. + */ + public static boolean isKotlinInterfaceDefaultImplsClass(Class clazz) { + if (!isKotlinType(clazz) || !DEFAULT_IMPLS_CLASS_NAME.equals(clazz.getSimpleName()) || !isStatic(clazz)) { + return false; + } + + Class enclosingClass = clazz.getEnclosingClass(); + if (enclosingClass != null && enclosingClass.isInterface()) { + return Arrays.stream(clazz.getDeclaredMethods()) // + .anyMatch(method -> isCompilerGeneratedDefaultMethod(method, enclosingClass)); + } + + return false; + } + + private static boolean isCompilerGeneratedDefaultMethod(Method method, Class enclosingClass) { + if (isStatic(method) && method.getParameterCount() > 0) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes[0] == enclosingClass) { + Class[] originalParameterTypes = copyWithoutFirst(parameterTypes); + return findMethod(enclosingClass, method.getName(), originalParameterTypes).isPresent(); + } + } + return false; + } + + private static Class[] copyWithoutFirst(Class[] values) { + if (values.length == 1) { + return EMPTY_CLASS_ARRAY; + } + Class[] result = new Class[values.length - 1]; + System.arraycopy(values, 1, result, 0, result.length); + return result; + } + + private static boolean isKotlinType(Class clazz) { + return kotlinMetadata != null // + && clazz.getDeclaredAnnotation(kotlinMetadata) != null; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/LruCache.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/LruCache.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/LruCache.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/LruCache.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,12 +17,13 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.function.Predicate; import org.apiguardian.api.API; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.support.Resource; +import org.junit.platform.commons.support.scanning.ClassFilter; /** * Collection of utilities for working with {@code java.lang.Module} @@ -110,7 +111,7 @@ * @since 1.11 */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate filter) { + public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -40,7 +40,7 @@ /* no-op */ } - static final String DEFAULT_PACKAGE_NAME = ""; + public static final String DEFAULT_PACKAGE_NAME = ""; /** * Get the package attribute for the supplied {@code type} using the @@ -95,17 +95,17 @@ return Optional.ofNullable(mainAttributes.getValue(name)); } } - catch (Exception e) { + catch (Exception ex) { return Optional.empty(); } } /** * Get the module or implementation version for the supplied {@code type}. - *

    - * The former is only available if the type is part of a versioned module on - * the module path; the latter only if the type is part of a JAR file with a - * manifest that contains an {@code Implementation-Version} attribute. + * + *

    The former is only available if the type is part of a versioned module + * on the module path; the latter only if the type is part of a JAR file with + * a manifest that contains an {@code Implementation-Version} attribute. * * @since 1.11 */ @@ -117,4 +117,5 @@ } return getAttribute(type, Package::getImplementationVersion); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PreconditionViolationException.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PreconditionViolationException.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PreconditionViolationException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PreconditionViolationException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/Preconditions.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/Preconditions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/Preconditions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/Preconditions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,11 +13,9 @@ import static java.lang.String.format; import static java.util.Collections.synchronizedMap; import static java.util.stream.Collectors.toCollection; -import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import static org.apiguardian.api.API.Status.DEPRECATED; import static org.apiguardian.api.API.Status.INTERNAL; -import static org.apiguardian.api.API.Status.STABLE; import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; import static org.junit.platform.commons.util.PackageNameUtils.getPackageName; import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; @@ -36,12 +34,15 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.LinkedHashSet; @@ -50,6 +51,8 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -58,9 +61,12 @@ import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.support.Resource; +import org.junit.platform.commons.support.scanning.ClassFilter; +import org.junit.platform.commons.support.scanning.ClasspathScanner; /** * Collection of utilities for working with the Java reflection APIs. @@ -124,30 +130,14 @@ BOTTOM_UP } - // Pattern: "[Ljava.lang.String;", "[[[[Ljava.lang.String;", etc. - private static final Pattern VM_INTERNAL_OBJECT_ARRAY_PATTERN = Pattern.compile("^(\\[+)L(.+);$"); - - /** - * Pattern: "[x", "[[[[x", etc., where x is Z, B, C, D, F, I, J, S, etc. - * - *

    The pattern intentionally captures the last bracket with the - * capital letter so that the combination can be looked up via - * {@link #classNameToTypeMap}. For example, the last matched group - * will contain {@code "[I"} instead of {@code "I"}. - * - * @see Class#getName() - */ - private static final Pattern VM_INTERNAL_PRIMITIVE_ARRAY_PATTERN = Pattern.compile("^(\\[+)(\\[[ZBCDFIJS])$"); - // Pattern: "java.lang.String[]", "int[]", "int[][][][]", etc. // ?> => non-capturing atomic group // ++ => possessive quantifier private static final Pattern SOURCE_CODE_SYNTAX_ARRAY_PATTERN = Pattern.compile("^([^\\[\\]]+)((?>\\[\\])++)$"); - private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - private static final ClasspathScanner classpathScanner = new ClasspathScanner( - ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass); + private static final ClasspathScanner classpathScanner = ClasspathScannerLoader.getInstance(); /** * Cache for equivalent methods on an interface implemented by the declaring class. @@ -162,7 +152,7 @@ *

    This serves as a cache to avoid repeated cycle detection for classes * that have already been checked. * @since 1.6 - * @see #detectInnerClassCycle(Class) + * @see #detectInnerClassCycle(Class, CycleErrorHandling) */ private static final Set noCyclesDetectedCache = ConcurrentHashMap.newKeySet(); @@ -187,6 +177,7 @@ long.class, float.class, double.class, + void.class, boolean[].class, byte[].class, @@ -214,6 +205,7 @@ Long.class, Float.class, Double.class, + Void.class, String.class, Boolean[].class, @@ -247,7 +239,7 @@ classNameToTypeMap = Collections.unmodifiableMap(classNamesToTypes); - Map, Class> primitivesToWrappers = new IdentityHashMap<>(8); + Map, Class> primitivesToWrappers = new IdentityHashMap<>(9); primitivesToWrappers.put(boolean.class, Boolean.class); primitivesToWrappers.put(byte.class, Byte.class); @@ -298,11 +290,21 @@ return Modifier.isAbstract(clazz.getModifiers()); } + @API(status = INTERNAL, since = "1.13") + public static boolean isNotAbstract(Class clazz) { + return !isAbstract(clazz); + } + public static boolean isAbstract(Member member) { Preconditions.notNull(member, "Member must not be null"); return Modifier.isAbstract(member.getModifiers()); } + @API(status = INTERNAL, since = "1.13") + public static boolean isNotAbstract(Member member) { + return !isAbstract(member); + } + public static boolean isStatic(Class clazz) { Preconditions.notNull(clazz, "Class must not be null"); return Modifier.isStatic(clazz.getModifiers()); @@ -375,6 +377,25 @@ } /** + * {@return whether the supplied {@code object} is an instance of a record class} + * @since 1.12 + */ + @API(status = INTERNAL, since = "1.12") + public static boolean isRecordObject(Object object) { + return object != null && isRecordClass(object.getClass()); + } + + /** + * {@return whether the supplied {@code clazz} is a record class} + * @since 1.12 + */ + @API(status = INTERNAL, since = "1.12") + public static boolean isRecordClass(Class clazz) { + Class superclass = clazz.getSuperclass(); + return superclass != null && "java.lang.Record".equals(superclass.getName()); + } + + /** * Determine if the return type of the supplied method is primitive {@code void}. * * @param method the method to test; never {@code null} @@ -412,8 +433,7 @@ * *

    In contrast to {@link Class#isAssignableFrom(Class)}, this method * returns {@code true} if the target type represents a primitive type whose - * wrapper matches the supplied source type. In addition, this method - * also supports + * wrapper matches the supplied source type. In addition, this method also supports * * widening conversions for primitive target types. * @@ -447,9 +467,8 @@ * type for the purpose of reflective method invocations. * *

    In contrast to {@link Class#isInstance(Object)}, this method returns - * {@code true} if the target type represents a primitive type whose - * wrapper matches the supplied object's type. In addition, this method - * also supports + * {@code true} if the target type represents a primitive type whose wrapper + * matches the supplied object's type. In addition, this method also supports * * widening conversions for primitive types and their corresponding * wrapper types. @@ -851,32 +870,8 @@ } return Try.call(() -> { - Matcher matcher; - - // Primitive arrays such as "[I", "[[[[D", etc. - matcher = VM_INTERNAL_PRIMITIVE_ARRAY_PATTERN.matcher(trimmedName); - if (matcher.matches()) { - String brackets = matcher.group(1); - String componentTypeName = matcher.group(2); - // Calculate dimensions by counting brackets. - int dimensions = brackets.length(); - - return loadArrayType(classLoader, componentTypeName, dimensions); - } - - // Object arrays such as "[Ljava.lang.String;", "[[[[Ljava.lang.String;", etc. - matcher = VM_INTERNAL_OBJECT_ARRAY_PATTERN.matcher(trimmedName); - if (matcher.matches()) { - String brackets = matcher.group(1); - String componentTypeName = matcher.group(2); - // Calculate dimensions by counting brackets. - int dimensions = brackets.length(); - - return loadArrayType(classLoader, componentTypeName, dimensions); - } - // Arrays such as "java.lang.String[]", "int[]", "int[][][][]", etc. - matcher = SOURCE_CODE_SYNTAX_ARRAY_PATTERN.matcher(trimmedName); + Matcher matcher = SOURCE_CODE_SYNTAX_ARRAY_PATTERN.matcher(trimmedName); if (matcher.matches()) { String componentTypeName = matcher.group(1); String bracketPairs = matcher.group(2); @@ -891,6 +886,54 @@ }); } + /** + * Try to get {@linkplain Resource resources} by their name, using the + * {@link ClassLoaderUtils#getDefaultClassLoader()}. + * + *

    See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResources(String)} + * for details. + * + * @param classpathResourceName the name of the resources to load; never {@code null} or blank + * @since 1.12 + * @see org.junit.platform.commons.support.ResourceSupport#tryToGetResources(String, ClassLoader) + */ + @API(status = INTERNAL, since = "1.12") + public static Try> tryToGetResources(String classpathResourceName) { + return tryToGetResources(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); + } + + /** + * Try to get {@linkplain Resource resources} by their name, using the + * supplied {@link ClassLoader}. + * + *

    See {@link org.junit.platform.commons.support.ResourceSupport#tryToGetResources(String, ClassLoader)} + * for details. + * + * @param classpathResourceName the name of the resources to load; never {@code null} or blank + * @param classLoader the {@code ClassLoader} to use; never {@code null} + * @since 1.12 + */ + @API(status = INTERNAL, since = "1.12") + public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { + Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); + Preconditions.notNull(classLoader, "Class loader must not be null"); + boolean startsWithSlash = classpathResourceName.startsWith("/"); + String canonicalClasspathResourceName = (startsWithSlash ? classpathResourceName.substring(1) + : classpathResourceName); + + return Try.call(() -> { + List resources = Collections.list(classLoader.getResources(canonicalClasspathResourceName)); + return resources.stream().map(url -> { + try { + return Resource.of(canonicalClasspathResourceName, url.toURI()); + } + catch (URISyntaxException e) { + throw ExceptionUtils.throwAsUncheckedException(e); + } + }).collect(toCollection(LinkedHashSet::new)); + }); + } + private static Class loadArrayType(ClassLoader classLoader, String componentTypeName, int dimensions) throws ClassNotFoundException { @@ -934,21 +977,22 @@ */ public static String getFullyQualifiedMethodName(Class clazz, String methodName, Class... parameterTypes) { Preconditions.notNull(clazz, "Class must not be null"); - Preconditions.notBlank(methodName, "Method name must not be null or blank"); return getFullyQualifiedMethodName(clazz.getName(), methodName, ClassUtils.nullSafeToString(parameterTypes)); } /** * Build the fully qualified method name for the method described by the - * supplied class, method name, and parameter types. + * supplied class name, method name, and parameter types. * *

    Note that the class is not necessarily the class in which the method is * declared. * - * @param className the name of the class from which the method should be referenced; never {@code null} + * @param className the name of the class from which the method should be referenced; + * never {@code null} * @param methodName the name of the method; never {@code null} or blank - * @param parameterTypeNames the parameter type names of the method; may be empty but not {@code null} + * @param parameterTypeNames the parameter type names of the method; may be + * empty but not {@code null} * @return fully qualified method name; never {@code null} * @since 1.11 */ @@ -1072,7 +1116,7 @@ /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); } @@ -1086,7 +1130,7 @@ /** * @since 1.11 */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + public static Stream streamAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { return findAllResourcesInClasspathRoot(root, resourceFilter).stream(); } @@ -1118,7 +1162,7 @@ /** * @since 1.11 */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { + public static List findAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { return Collections.unmodifiableList( classpathScanner.scanForResourcesInPackage(basePackageName, resourceFilter)); } @@ -1133,8 +1177,7 @@ /** * @since 1.11 */ - public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter) { + public static Stream streamAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { return findAllResourcesInPackage(basePackageName, resourceFilter).stream(); } @@ -1167,7 +1210,7 @@ /** * @since 1.11 */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { + public static List findAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { return Collections.unmodifiableList(ModuleUtils.findAllResourcesInModule(moduleName, resourceFilter)); } @@ -1181,7 +1224,7 @@ /** * @since 1.11 */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { + public static Stream streamAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { return findAllResourcesInModule(moduleName, resourceFilter).stream(); } @@ -1189,37 +1232,92 @@ * @see org.junit.platform.commons.support.ReflectionSupport#findNestedClasses(Class, Predicate) */ public static List> findNestedClasses(Class clazz, Predicate> predicate) { + return findNestedClasses(clazz, predicate, CycleErrorHandling.THROW_EXCEPTION); + } + + /** + * @since 1.13.2 + */ + @API(status = INTERNAL, since = "1.13.2") + public static List> findNestedClasses(Class clazz, Predicate> predicate, + CycleErrorHandling errorHandling) { Preconditions.notNull(clazz, "Class must not be null"); Preconditions.notNull(predicate, "Predicate must not be null"); Set> candidates = new LinkedHashSet<>(); - findNestedClasses(clazz, predicate, candidates); + visitAllNestedClasses(clazz, predicate, candidates::add, errorHandling); return Collections.unmodifiableList(new ArrayList<>(candidates)); } /** - * since 1.10 + * Determine if a nested class within the supplied class, or inherited by the + * supplied class, that conforms to the supplied predicate is present. + * + *

    This method does not search for nested classes + * recursively. + * + * @param clazz the class to be searched; never {@code null} + * @param predicate the predicate against which the list of nested classes is + * checked; never {@code null} + * @return {@code true} if such a nested class is present + * @throws JUnitException if a cycle is detected within an inner class hierarchy + * @since 1.13.2 + */ + @API(status = INTERNAL, since = "1.13.2") + public static boolean isNestedClassPresent(Class clazz, Predicate> predicate, + CycleErrorHandling errorHandling) { + Preconditions.notNull(clazz, "Class must not be null"); + Preconditions.notNull(predicate, "Predicate must not be null"); + Preconditions.notNull(errorHandling, "CycleErrorHandling must not be null"); + + AtomicBoolean foundNestedClass = new AtomicBoolean(false); + visitAllNestedClasses(clazz, predicate, __ -> foundNestedClass.set(true), errorHandling); + return foundNestedClass.get(); + } + + /** + * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamNestedClasses(Class, Predicate) */ + @API(status = INTERNAL, since = "1.10") public static Stream> streamNestedClasses(Class clazz, Predicate> predicate) { return findNestedClasses(clazz, predicate).stream(); } - private static void findNestedClasses(Class clazz, Predicate> predicate, Set> candidates) { + /** + * @since 1.13.2 + */ + @API(status = INTERNAL, since = "1.13.2") + public static Stream> streamNestedClasses(Class clazz, Predicate> predicate, + CycleErrorHandling errorHandling) { + return findNestedClasses(clazz, predicate, errorHandling).stream(); + } + + /** + * Visit all nested classes without support for short-circuiting + * in order to ensure all of them are checked for class cycles. + */ + private static void visitAllNestedClasses(Class clazz, Predicate> predicate, + Consumer> consumer, CycleErrorHandling errorHandling) { + if (!isSearchable(clazz)) { return; } if (isInnerClass(clazz) && predicate.test(clazz)) { - detectInnerClassCycle(clazz); + if (detectInnerClassCycle(clazz, errorHandling)) { + return; + } } try { // Candidates in current class for (Class nestedClass : clazz.getDeclaredClasses()) { if (predicate.test(nestedClass)) { - detectInnerClassCycle(nestedClass); - candidates.add(nestedClass); + consumer.accept(nestedClass); + if (detectInnerClassCycle(nestedClass, errorHandling)) { + return; + } } } } @@ -1228,11 +1326,11 @@ } // Search class hierarchy - findNestedClasses(clazz.getSuperclass(), predicate, candidates); + visitAllNestedClasses(clazz.getSuperclass(), predicate, consumer, errorHandling); // Search interface hierarchy for (Class ifc : clazz.getInterfaces()) { - findNestedClasses(ifc, predicate, candidates); + visitAllNestedClasses(ifc, predicate, consumer, errorHandling); } } @@ -1240,10 +1338,8 @@ * Detect a cycle in the inner class hierarchy in which the supplied class * resides — from the supplied class up to the outermost enclosing class * — and throw a {@link JUnitException} if a cycle is detected. - * *

    This method does not detect cycles within inner class * hierarchies below the supplied class. - * *

    If the supplied class is not an inner class and does not have a * searchable superclass, this method is effectively a no-op. * @@ -1251,25 +1347,26 @@ * @see #isInnerClass(Class) * @see #isSearchable(Class) */ - private static void detectInnerClassCycle(Class clazz) { + private static boolean detectInnerClassCycle(Class clazz, CycleErrorHandling errorHandling) { Preconditions.notNull(clazz, "Class must not be null"); String className = clazz.getName(); if (noCyclesDetectedCache.contains(className)) { - return; + return false; } Class superclass = clazz.getSuperclass(); if (isInnerClass(clazz) && isSearchable(superclass)) { for (Class enclosing = clazz.getEnclosingClass(); enclosing != null; enclosing = enclosing.getEnclosingClass()) { if (superclass.equals(enclosing)) { - throw new JUnitException(String.format("Detected cycle in inner class hierarchy between %s and %s", - className, enclosing.getName())); + errorHandling.handle(clazz, enclosing); + return true; } } } noCyclesDetectedCache.add(className); + return false; } /** @@ -1287,14 +1384,14 @@ public static Constructor getDeclaredConstructor(Class clazz) { Preconditions.notNull(clazz, "Class must not be null"); try { - List> constructors = Arrays.stream(clazz.getDeclaredConstructors())// + Constructor[] constructors = Arrays.stream(clazz.getDeclaredConstructors())// .filter(ctor -> !ctor.isSynthetic())// - .collect(toList()); + .toArray(Constructor[]::new); - Preconditions.condition(constructors.size() == 1, + Preconditions.condition(constructors.length == 1, () -> String.format("Class [%s] must declare a single constructor", clazz.getName())); - return (Constructor) constructors.get(0); + return (Constructor) constructors[0]; } catch (Throwable t) { throw ExceptionUtils.throwAsUncheckedException(getUnderlyingCause(t)); @@ -1345,6 +1442,7 @@ * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamFields(Class, Predicate, org.junit.platform.commons.support.HierarchyTraversalMode) */ + @API(status = INTERNAL, since = "1.10") public static Stream streamFields(Class clazz, Predicate predicate, HierarchyTraversalMode traversalMode) { @@ -1364,26 +1462,26 @@ Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null"); // @formatter:off - List localFields = getDeclaredFields(clazz).stream() + Field[] localFields = getDeclaredFields(clazz).stream() .filter(field -> !field.isSynthetic()) - .collect(toList()); - List superclassFields = getSuperclassFields(clazz, traversalMode).stream() - .filter(field -> !isFieldShadowedByLocalFields(field, localFields)) - .collect(toList()); - List interfaceFields = getInterfaceFields(clazz, traversalMode).stream() - .filter(field -> !isFieldShadowedByLocalFields(field, localFields)) - .collect(toList()); + .toArray(Field[]::new); + Field[] superclassFields = getSuperclassFields(clazz, traversalMode).stream() + .filter(field -> isNotShadowedByLocalFields(field, localFields)) + .toArray(Field[]::new); + Field[] interfaceFields = getInterfaceFields(clazz, traversalMode).stream() + .filter(field -> isNotShadowedByLocalFields(field, localFields)) + .toArray(Field[]::new); // @formatter:on - List fields = new ArrayList<>(); + List fields = new ArrayList<>(superclassFields.length + interfaceFields.length + localFields.length); if (traversalMode == TOP_DOWN) { - fields.addAll(superclassFields); - fields.addAll(interfaceFields); + Collections.addAll(fields, superclassFields); + Collections.addAll(fields, interfaceFields); } - fields.addAll(localFields); + Collections.addAll(fields, localFields); if (traversalMode == BOTTOM_UP) { - fields.addAll(interfaceFields); - fields.addAll(superclassFields); + Collections.addAll(fields, interfaceFields); + Collections.addAll(fields, superclassFields); } return fields; } @@ -1512,6 +1610,9 @@ return findMethod(clazz, methodName, resolveParameterTypes(clazz, methodName, parameterTypeNames)); } + /** + * @since 1.10 + */ @API(status = INTERNAL, since = "1.10") public static Class[] resolveParameterTypes(Class clazz, String methodName, String parameterTypeNames) { if (StringUtils.isBlank(parameterTypeNames)) { @@ -1596,7 +1697,7 @@ * @since 1.7 * @see #findMethod(Class, String, Class...) */ - @API(status = STABLE, since = "1.7") + @API(status = INTERNAL, since = "1.7") public static Method getRequiredMethod(Class clazz, String methodName, Class... parameterTypes) { return ReflectionUtils.findMethod(clazz, methodName, parameterTypes).orElseThrow( () -> new JUnitException(format("Could not find method [%s] in class [%s]", methodName, clazz.getName()))); @@ -1632,6 +1733,7 @@ * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamMethods(Class, Predicate, org.junit.platform.commons.support.HierarchyTraversalMode) */ + @API(status = INTERNAL, since = "1.10") public static Stream streamMethods(Class clazz, Predicate predicate, HierarchyTraversalMode traversalMode) { @@ -1655,26 +1757,27 @@ Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null"); // @formatter:off - List localMethods = getDeclaredMethods(clazz, traversalMode).stream() + Method[] localMethods = getDeclaredMethods(clazz, traversalMode).stream() .filter(method -> !method.isSynthetic()) - .collect(toList()); - List superclassMethods = getSuperclassMethods(clazz, traversalMode).stream() - .filter(method -> !isMethodOverriddenByLocalMethods(method, localMethods)) - .collect(toList()); - List interfaceMethods = getInterfaceMethods(clazz, traversalMode).stream() - .filter(method -> !isMethodOverriddenByLocalMethods(method, localMethods)) - .collect(toList()); + .toArray(Method[]::new); + Method[] superclassMethods = getSuperclassMethods(clazz, traversalMode).stream() + .filter(method -> isNotOverriddenByLocalMethods(method, localMethods)) + .toArray(Method[]::new); + Method[] interfaceMethods = getInterfaceMethods(clazz, traversalMode).stream() + .filter(method -> isNotOverriddenByLocalMethods(method, localMethods)) + .toArray(Method[]::new); // @formatter:on - List methods = new ArrayList<>(); + List methods = new ArrayList<>( + superclassMethods.length + interfaceMethods.length + localMethods.length); if (traversalMode == TOP_DOWN) { - methods.addAll(superclassMethods); - methods.addAll(interfaceMethods); + Collections.addAll(methods, superclassMethods); + Collections.addAll(methods, interfaceMethods); } - methods.addAll(localMethods); + Collections.addAll(methods, localMethods); if (traversalMode == BOTTOM_UP) { - methods.addAll(interfaceMethods); - methods.addAll(superclassMethods); + Collections.addAll(methods, interfaceMethods); + Collections.addAll(methods, superclassMethods); } return methods; } @@ -1755,21 +1858,18 @@ } private static List toSortedMutableList(Field[] fields) { - // @formatter:off - return Arrays.stream(fields) - .sorted(ReflectionUtils::defaultFieldSorter) - // Use toCollection() instead of toList() to ensure list is mutable. - .collect(toCollection(ArrayList::new)); - // @formatter:on + return toSortedMutableList(fields, ReflectionUtils::defaultFieldSorter); } private static List toSortedMutableList(Method[] methods) { - // @formatter:off - return Arrays.stream(methods) - .sorted(ReflectionUtils::defaultMethodSorter) - // Use toCollection() instead of toList() to ensure list is mutable. - .collect(toCollection(ArrayList::new)); - // @formatter:on + return toSortedMutableList(methods, ReflectionUtils::defaultMethodSorter); + } + + private static List toSortedMutableList(T[] items, Comparator comparator) { + List result = new ArrayList<>(items.length); + Collections.addAll(result, items); + result.sort(comparator); + return result; } /** @@ -1802,21 +1902,21 @@ for (Class ifc : clazz.getInterfaces()) { // @formatter:off - List localInterfaceMethods = getMethods(ifc).stream() + Method[] localInterfaceMethods = getMethods(ifc).stream() .filter(m -> !isAbstract(m)) - .collect(toList()); + .toArray(Method[]::new); - List superinterfaceMethods = getInterfaceMethods(ifc, traversalMode).stream() - .filter(method -> !isMethodOverriddenByLocalMethods(method, localInterfaceMethods)) - .collect(toList()); + Method[] superinterfaceMethods = getInterfaceMethods(ifc, traversalMode).stream() + .filter(method -> isNotOverriddenByLocalMethods(method, localInterfaceMethods)) + .toArray(Method[]::new); // @formatter:on if (traversalMode == TOP_DOWN) { - allInterfaceMethods.addAll(superinterfaceMethods); + Collections.addAll(allInterfaceMethods, superinterfaceMethods); } - allInterfaceMethods.addAll(localInterfaceMethods); + Collections.addAll(allInterfaceMethods, localInterfaceMethods); if (traversalMode == BOTTOM_UP) { - allInterfaceMethods.addAll(superinterfaceMethods); + Collections.addAll(allInterfaceMethods, superinterfaceMethods); } } return allInterfaceMethods; @@ -1825,20 +1925,21 @@ private static List getInterfaceFields(Class clazz, HierarchyTraversalMode traversalMode) { List allInterfaceFields = new ArrayList<>(); for (Class ifc : clazz.getInterfaces()) { - List localInterfaceFields = getFields(ifc); + Field[] localInterfaceFields = ifc.getFields(); + Arrays.sort(localInterfaceFields, ReflectionUtils::defaultFieldSorter); // @formatter:off - List superinterfaceFields = getInterfaceFields(ifc, traversalMode).stream() - .filter(field -> !isFieldShadowedByLocalFields(field, localInterfaceFields)) - .collect(toList()); + Field[] superinterfaceFields = getInterfaceFields(ifc, traversalMode).stream() + .filter(field -> isNotShadowedByLocalFields(field, localInterfaceFields)) + .toArray(Field[]::new); // @formatter:on if (traversalMode == TOP_DOWN) { - allInterfaceFields.addAll(superinterfaceFields); + Collections.addAll(allInterfaceFields, superinterfaceFields); } - allInterfaceFields.addAll(localInterfaceFields); + Collections.addAll(allInterfaceFields, localInterfaceFields); if (traversalMode == BOTTOM_UP) { - allInterfaceFields.addAll(superinterfaceFields); + Collections.addAll(allInterfaceFields, superinterfaceFields); } } return allInterfaceFields; @@ -1852,11 +1953,16 @@ return findAllFieldsInHierarchy(superclass, traversalMode); } - private static boolean isFieldShadowedByLocalFields(Field field, List localFields) { + private static boolean isNotShadowedByLocalFields(Field field, Field[] localFields) { if (useLegacySearchSemantics) { - return localFields.stream().anyMatch(local -> local.getName().equals(field.getName())); + for (Field local : localFields) { + if (local.getName().equals(field.getName())) { + return false; + } + } + return true; } - return false; + return true; } private static List getSuperclassMethods(Class clazz, HierarchyTraversalMode traversalMode) { @@ -1867,8 +1973,13 @@ return findAllMethodsInHierarchy(superclass, traversalMode); } - private static boolean isMethodOverriddenByLocalMethods(Method method, List localMethods) { - return localMethods.stream().anyMatch(local -> isMethodOverriddenBy(method, local)); + private static boolean isNotOverriddenByLocalMethods(Method method, Method[] localMethods) { + for (Method local : localMethods) { + if (isMethodOverriddenBy(method, local)) { + return false; + } + } + return true; } private static boolean isMethodOverriddenBy(Method upper, Method lower) { @@ -1886,7 +1997,7 @@ } // Cannot override a package-private method in another package. - if (isPackagePrivate(upper) && !declaredInSamePackage(upper, lower)) { + if (isPackagePrivate(upper) && !isDeclaredInSamePackage(upper, lower)) { return false; } } @@ -1894,13 +2005,25 @@ return hasCompatibleSignature(upper, lower.getName(), lower.getParameterTypes()); } - private static boolean isPackagePrivate(Member member) { + /** + * @since 5.14.1 + */ + @API(status = INTERNAL, since = "5.14.1") + public static boolean isPackagePrivate(Member member) { int modifiers = member.getModifiers(); return !(Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers) || Modifier.isPrivate(modifiers)); } - private static boolean declaredInSamePackage(Method m1, Method m2) { - return getPackageName(m1.getDeclaringClass()).equals(getPackageName(m2.getDeclaringClass())); + private static boolean isDeclaredInSamePackage(Method m1, Method m2) { + return isDeclaredInSamePackage(m1.getDeclaringClass(), m2.getDeclaringClass()); + } + + /** + * @since 5.14.1 + */ + @API(status = INTERNAL, since = "5.14.1") + public static boolean isDeclaredInSamePackage(Class c1, Class c2) { + return getPackageName(c1).equals(getPackageName(c2)); } /** @@ -1946,6 +2069,9 @@ return type instanceof TypeVariable || type instanceof GenericArrayType; } + /** + * @since 1.11 + */ @API(status = INTERNAL, since = "1.11") @SuppressWarnings("deprecation") // "AccessibleObject.isAccessible()" is deprecated in Java 9 public static T makeAccessible(T executable) { @@ -1955,7 +2081,10 @@ return executable; } - @API(status = INTERNAL, since = "1.11") + /** + * @since 1.12 + */ + @API(status = INTERNAL, since = "1.12") @SuppressWarnings("deprecation") // "AccessibleObject.isAccessible()" is deprecated in Java 9 public static Field makeAccessible(Field field) { if ((!isPublic(field) || !isPublic(field.getDeclaringClass()) || isFinal(field)) && !field.isAccessible()) { @@ -2030,4 +2159,28 @@ return isTrue; } + /** + * @since 1.13.2 + */ + @API(status = INTERNAL, since = "1.13.2") + public enum CycleErrorHandling { + + THROW_EXCEPTION { + @Override + void handle(Class clazz, Class enclosing) { + throw new JUnitException(String.format("Detected cycle in inner class hierarchy between %s and %s", + clazz.getName(), enclosing.getName())); + } + }, + + ABORT_VISIT { + @Override + void handle(Class clazz, Class enclosing) { + // ignore + } + }; + + abstract void handle(Class clazz, Class enclosing); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.net.URI; + +import org.apiguardian.api.API; + +/** + * Collection of static utility methods for working with resources. + * + * @since 1.3 (originally in org.junit.platform.engine.support.descriptor) + */ +@API(status = INTERNAL, since = "1.12") +public final class ResourceUtils { + + private ResourceUtils() { + /* no-op */ + } + + /** + * Strip the {@link URI#getQuery() query} component from the supplied + * {@link URI}. + * + * @param uri the {@code URI} from which to strip the query component + * @return a new {@code URI} with the query component removed, or the + * original {@code URI} unmodified if it does not have a query component + * + * @since 1.3 + */ + public static URI stripQueryComponent(URI uri) { + Preconditions.notNull(uri, "URI must not be null"); + + if (StringUtils.isBlank(uri.getQuery())) { + return uri; + } + + String uriAsString = uri.toString(); + return URI.create(uriAsString.substring(0, uriAsString.indexOf('?'))); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ServiceLoaderUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ServiceLoaderUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ServiceLoaderUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ServiceLoaderUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import java.util.ServiceLoader; +import java.util.function.Predicate; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.apiguardian.api.API; + +/** + * Collection of utilities for working with {@link ServiceLoader}. + * + *

    DISCLAIMER

    + * + *

    These utilities are intended solely for usage within the JUnit framework + * itself. Any usage by external parties is not supported. + * Use at your own risk! + * + * @since 1.11 + */ +@API(status = API.Status.INTERNAL, since = "1.11") +public class ServiceLoaderUtils { + + private ServiceLoaderUtils() { + /* no-op */ + } + + /** + * Filters the supplied service loader using the supplied predicate. + * + * @param the type of the service + * @param serviceLoader the service loader to be filtered + * @param providerPredicate the predicate to filter the loaded services + * @return a stream of loaded services that match the predicate + */ + public static Stream filter(ServiceLoader serviceLoader, + Predicate> providerPredicate) { + return StreamSupport.stream(serviceLoader.spliterator(), false).filter(it -> { + @SuppressWarnings("unchecked") + Class type = (Class) it.getClass(); + return providerPredicate.test(type); + }); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/StringUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/StringUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/StringUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/StringUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -41,7 +41,7 @@ /** * Guard against "IllegalArgumentException: Unsupported flags: 256" errors. - * @see #1800 + * @see #1800 */ static Pattern compileIsoControlPattern() { // https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#posix @@ -306,9 +306,10 @@ public interface TwoPartSplitResult { /** - * Maps the result of splitting a string into two parts or throw an exception. + * Map the result of splitting a string into two parts or throw an exception. * - * @param onePartExceptionCreator the exception creator to use if the string was split into a single part + * @param onePartExceptionCreator the exception creator to use if the string + * was split into a single part * @param twoPartsMapper the mapper to use if the string was split into two parts */ default T mapTwo(Supplier onePartExceptionCreator, @@ -320,7 +321,7 @@ } /** - * Maps the result of splitting a string into up to two parts. + * Map the result of splitting a string into up to two parts. * * @param onePartMapper the mapper to use if the string was split into a single part * @param twoPartsMapper the mapper to use if the string was split into two parts @@ -340,7 +341,7 @@ @Override public T map(Function onePartMapper, BiFunction twoPartsMapper) { - return onePartMapper.apply(value); + return onePartMapper.apply(this.value); } } @@ -357,7 +358,7 @@ @Override public T map(Function onePartMapper, BiFunction twoPartsMapper) { - return twoPartsMapper.apply(first, second); + return twoPartsMapper.apply(this.first, this.second); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ToStringBuilder.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ToStringBuilder.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ToStringBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ToStringBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/UnrecoverableExceptions.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/UnrecoverableExceptions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/UnrecoverableExceptions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java/org/junit/platform/commons/util/UnrecoverableExceptions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -35,9 +35,11 @@ import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.support.Resource; +import org.junit.platform.commons.support.scanning.ClassFilter; /** * Collection of utilities for working with {@code java.lang.Module} @@ -128,7 +130,7 @@ * @since 1.11 */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate filter) { + public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); @@ -186,8 +188,7 @@ * Scan for classes using the supplied set of module references, class * filter, and loader. */ - private static List scan(Set references, Predicate filter, - ClassLoader loader) { + private static List scan(Set references, ResourceFilter filter, ClassLoader loader) { logger.debug(() -> "Scanning " + references.size() + " module references: " + references); ModuleReferenceResourceScanner scanner = new ModuleReferenceResourceScanner(filter, loader); List classes = new ArrayList<>(); @@ -225,8 +226,7 @@ .filter(name -> !name.equals("module-info")) .filter(classFilter::match) .map(this::loadClassUnchecked) - // Always use ".filter(classFilter)" to include future predicates. - .filter(classFilter) + .filter(classFilter::match) .collect(Collectors.toList()); // @formatter:on } @@ -268,10 +268,10 @@ */ static class ModuleReferenceResourceScanner { - private final Predicate resourceFilter; + private final ResourceFilter resourceFilter; private final ClassLoader classLoader; - ModuleReferenceResourceScanner(Predicate resourceFilter, ClassLoader classLoader) { + ModuleReferenceResourceScanner(ResourceFilter resourceFilter, ClassLoader classLoader) { this.resourceFilter = resourceFilter; this.classLoader = classLoader; } @@ -285,7 +285,7 @@ // @formatter:off return names.filter(name -> !name.endsWith(".class")) .map(this::loadResourceUnchecked) - .filter(resourceFilter) + .filter(resourceFilter::match) .collect(Collectors.toList()); // @formatter:on } @@ -298,7 +298,7 @@ private Resource loadResourceUnchecked(String binaryName) { try { URI uri = classLoader.getResource(binaryName).toURI(); - return new ClasspathResource(binaryName, uri); + return Resource.of(binaryName, uri); } catch (URISyntaxException e) { throw new JUnitException("Failed to load resource with name '" + binaryName + "'.", e); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ServiceLoaderUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ServiceLoaderUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ServiceLoaderUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ServiceLoaderUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import java.util.ServiceLoader; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.apiguardian.api.API; +import org.apiguardian.api.API.Status; + +/** + * Collection of utilities for working with {@link ServiceLoader}. + * + *

    DISCLAIMER

    + * + *

    These utilities are intended solely for usage within the JUnit framework + * itself. Any usage by external parties is not supported. + * Use at your own risk! + * + * @since 1.11 + */ +@API(status = Status.INTERNAL, since = "1.11") +public class ServiceLoaderUtils { + + private ServiceLoaderUtils() { + /* no-op */ + } + + /** + * Filters the supplied service loader using the supplied predicate. + * + * @param the type of the service + * @param serviceLoader the service loader to be filtered + * @param providerPredicate the predicate to filter the loaded services + * @return a stream of loaded services that match the predicate + */ + public static Stream filter(ServiceLoader serviceLoader, + Predicate> providerPredicate) { + // @formatter:off + return serviceLoader + .stream() + .filter(provider -> providerPredicate.test(provider.type())) + .map(ServiceLoader.Provider::get); + // @formatter:on + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Common APIs and support utilities for the JUnit Platform. * @@ -21,6 +22,7 @@ exports org.junit.platform.commons; exports org.junit.platform.commons.annotation; exports org.junit.platform.commons.function; + exports org.junit.platform.commons.io; exports org.junit.platform.commons.logging to org.junit.jupiter.api, org.junit.jupiter.engine, @@ -37,6 +39,7 @@ org.junit.vintage.engine; exports org.junit.platform.commons.support; exports org.junit.platform.commons.support.conversion; + exports org.junit.platform.commons.support.scanning; exports org.junit.platform.commons.util to org.junit.jupiter.api, org.junit.jupiter.engine, @@ -44,6 +47,7 @@ org.junit.jupiter.params, org.junit.platform.console, org.junit.platform.engine, + org.junit.platform.jfr, org.junit.platform.launcher, org.junit.platform.reporting, org.junit.platform.runner, @@ -52,4 +56,5 @@ org.junit.platform.suite.engine, org.junit.platform.testkit, org.junit.vintage.engine; + uses org.junit.platform.commons.support.scanning.ClasspathScanner; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/ConcurrencyTestingUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/ConcurrencyTestingUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/ConcurrencyTestingUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/ConcurrencyTestingUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/IdeUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/IdeUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/IdeUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/IdeUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.test; + +/** + * Collection of test utilities for IDEs. + */ +public class IdeUtils { + + /** + * Determine if the current code is running in the Eclipse IDE. + *

    Copied from {@code org.springframework.core.testfixture.ide.IdeUtils}. + */ + public static boolean runningInEclipse() { + return StackWalker.getInstance().walk( + stream -> stream.anyMatch(stackFrame -> stackFrame.getClassName().startsWith("org.eclipse.jdt"))); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/PreconditionAssertions.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/PreconditionAssertions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/PreconditionAssertions.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/PreconditionAssertions.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.test; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.assertj.core.api.ThrowableAssertAlternative; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.Preconditions; + +/** + * Collection of assertions for working with {@link Preconditions}. + * + * @since 1.14 + */ +public final class PreconditionAssertions { + + private PreconditionAssertions() { + /* no-op */ + } + + public static void assertPreconditionViolationNotNullFor(String name, ThrowingCallable throwingCallable) { + assertPreconditionViolationFor(throwingCallable).withMessage("%s must not be null", name); + } + + public static void assertPreconditionViolationNotNullOrBlankFor(String name, ThrowingCallable throwingCallable) { + assertPreconditionViolationFor(throwingCallable).withMessage("%s must not be null or blank", name); + } + + public static ThrowableAssertAlternative assertPreconditionViolationFor( + ThrowingCallable throwingCallable) { + + return assertThatExceptionOfType(PreconditionViolationException.class).isThrownBy(throwingCallable); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/TestClassLoader.java jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/TestClassLoader.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/TestClassLoader.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-commons/src/testFixtures/java/org/junit/platform/commons/test/TestClassLoader.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/junit-platform-console.gradle.kts jtreg8-8.3+1+ds1/junit5/junit-platform-console/junit-platform-console.gradle.kts --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/junit-platform-console.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/junit-platform-console.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,3 +1,4 @@ +import junitbuild.extensions.javaModuleName import junitbuild.java.UpdateJarAction plugins { @@ -15,6 +16,7 @@ compileOnlyApi(libs.apiguardian) compileOnly(libs.openTestReporting.events) + compileOnly(libs.openTestReporting.tooling.spi) shadowed(libs.picocli) @@ -26,7 +28,7 @@ compileModule { options.compilerArgs.addAll(listOf( "--add-modules", "org.opentest4j.reporting.events", - "--add-reads", "${project.projects.junitPlatformReporting.dependencyProject.javaModuleName}=org.opentest4j.reporting.events", + "--add-reads", "${project.projects.junitPlatformReporting.javaModuleName}=org.opentest4j.reporting.events", "--add-modules", "info.picocli", "--add-reads", "${javaModuleName}=info.picocli" )) @@ -50,6 +52,12 @@ "-C", release17ClassesDir.absolutePath, "." ) }) + bundle { + // Ignore warning for package that is only exported as "INTERNAL" + bnd(""" + -fixupmessages.picocli.export: "Export org.junit.platform.console.options";is:=ignore + """) + } } codeCoverageClassesJar { exclude("org/junit/platform/console/options/ConsoleUtils.class") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/ConsoleLauncher.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/ConsoleLauncher.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/ConsoleLauncher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/ConsoleLauncher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,9 +16,10 @@ import java.io.PrintWriter; import org.apiguardian.api.API; -import org.junit.platform.console.options.CommandFacade; -import org.junit.platform.console.options.CommandResult; -import org.junit.platform.console.tasks.ConsoleTestExecutor; +import org.junit.platform.console.command.CommandFacade; +import org.junit.platform.console.command.CommandResult; +import org.junit.platform.console.command.ConsoleTestExecutor; +import org.junit.platform.console.command.CustomClassLoaderCloseStrategy; /** * The {@code ConsoleLauncher} is a stand-alone application for launching the @@ -30,17 +31,20 @@ public class ConsoleLauncher { public static void main(String... args) { - CommandResult result = newCommandFacade().run(args); + CommandFacade facade = newCommandFacade(CustomClassLoaderCloseStrategy.KEEP_OPEN); + CommandResult result = facade.run(args); System.exit(result.getExitCode()); } @API(status = INTERNAL, since = "1.0") public static CommandResult run(PrintWriter out, PrintWriter err, String... args) { - return newCommandFacade().run(args, out, err); + CommandFacade facade = newCommandFacade(CustomClassLoaderCloseStrategy.CLOSE_AFTER_CALLING_LAUNCHER); + return facade.run(args, out, err); } - private static CommandFacade newCommandFacade() { - return new CommandFacade(ConsoleTestExecutor::new); + private static CommandFacade newCommandFacade(CustomClassLoaderCloseStrategy classLoaderCleanupStrategy) { + return new CommandFacade((discoveryOptions, outputOptions) -> new ConsoleTestExecutor(discoveryOptions, + outputOptions, classLoaderCleanupStrategy)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BannerOptionMixin.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BannerOptionMixin.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BannerOptionMixin.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BannerOptionMixin.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import picocli.CommandLine.Option; + +class BannerOptionMixin { + + @Option(names = "--disable-banner", description = "Disable print out of the welcome message.") + private boolean disableBanner; + + @Option(names = "-disable-banner", hidden = true) + private boolean disableBanner2; + + public boolean isDisableBanner() { + return disableBanner || disableBanner2; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BaseCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BaseCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BaseCommand.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/BaseCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.io.PrintWriter; +import java.util.concurrent.Callable; + +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.console.options.AnsiColorOptionMixin; + +import picocli.CommandLine; +import picocli.CommandLine.Mixin; +import picocli.CommandLine.Model.CommandSpec; +import picocli.CommandLine.Option; +import picocli.CommandLine.ParameterException; +import picocli.CommandLine.Spec; + +abstract class BaseCommand implements Callable { + + @Spec + CommandSpec commandSpec; + + @Mixin + AnsiColorOptionMixin ansiColorOption; + + @Mixin + BannerOptionMixin bannerOption; + + @SuppressWarnings("unused") + @Option(names = { "-h", "--help" }, usageHelp = true, description = "Display help information.") + private boolean helpRequested; + + @SuppressWarnings("unused") + @Option(names = "--version", versionHelp = true, description = "Display version information.") + private boolean versionHelpRequested; + + void execute(String... args) { + toCommandLine().execute(args); + } + + void parseArgs(String... args) { + toCommandLine().parseArgs(args); + } + + private CommandLine toCommandLine() { + return BaseCommand.initialize(new CommandLine(this)); + } + + static CommandLine initialize(CommandLine commandLine) { + CommandLine.IParameterExceptionHandler defaultParameterExceptionHandler = commandLine.getParameterExceptionHandler(); + return commandLine // + .setParameterExceptionHandler((ex, args) -> { + defaultParameterExceptionHandler.handleParseException(ex, args); + return CommandResult.FAILURE; + }) // + .setExecutionExceptionHandler((ex, cmd, __) -> { + commandLine.getErr().println(cmd.getColorScheme().richStackTraceString(ex)); + commandLine.getErr().println(); + commandLine.getErr().flush(); + cmd.usage(commandLine.getOut()); + return CommandResult.FAILURE; + }) // + .setCaseInsensitiveEnumValuesAllowed(true) // + .setAtFileCommentChar(null); + } + + @Override + public final T call() { + PrintWriter out = getOut(); + if (!bannerOption.isDisableBanner()) { + displayBanner(out); + } + try { + return execute(out); + } + catch (PreconditionViolationException e) { + throw new ParameterException(commandSpec.commandLine(), e.getMessage(), e.getCause()); + } + } + + private PrintWriter getOut() { + return commandSpec.commandLine().getOut(); + } + + private void displayBanner(PrintWriter out) { + out.println(); + CommandLine.Help.ColorScheme colorScheme = getColorScheme(); + if (colorScheme.ansi().enabled()) { + out.print("💚 "); + } + out.println(colorScheme.string( + "@|italic Thanks for using JUnit!|@ Support its development at @|underline https://junit.org/sponsoring|@")); + out.println(); + out.flush(); + } + + protected final CommandLine.Help.ColorScheme getColorScheme() { + return commandSpec.commandLine().getColorScheme(); + } + + protected abstract T execute(PrintWriter out); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandFacade.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandFacade.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandFacade.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandFacade.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.io.PrintWriter; +import java.util.Optional; + +import org.apiguardian.api.API; + +/** + * Internal facade to run a CLI command that exists to hide implementation + * details such as the used library. + * + * @since 1.10 + */ +@API(status = INTERNAL, since = "1.10") +public class CommandFacade { + + private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; + + public CommandFacade(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { + this.consoleTestExecutorFactory = consoleTestExecutorFactory; + } + + public CommandResult run(String[] args) { + return run(args, Optional.empty()); + } + + public CommandResult run(String[] args, PrintWriter out, PrintWriter err) { + try { + return run(args, Optional.of(new OutputStreamConfig(out, err))); + } + finally { + out.flush(); + err.flush(); + } + } + + private CommandResult run(String[] args, Optional outputStreamConfig) { + Optional version = ManifestVersionProvider.getImplementationVersion(); + System.setProperty("junit.docs.version", + version.map(it -> it.endsWith("-SNAPSHOT") ? "snapshot" : it).orElse("current")); + return new MainCommand(consoleTestExecutorFactory).run(args, outputStreamConfig); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandResult.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CommandResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.Optional; + +import org.apiguardian.api.API; + +/** + * @since 1.10 + */ +@API(status = INTERNAL, since = "1.10") +public class CommandResult { + + /** + * Exit code indicating successful execution. + */ + public static final int SUCCESS = 0; + + /** + * Exit code indicating any failure(s). + */ + protected static final int FAILURE = -1; + + public static CommandResult success() { + return create(SUCCESS, null); + } + + public static CommandResult failure() { + return create(FAILURE, null); + } + + public static CommandResult create(int exitCode, T value) { + return new CommandResult<>(exitCode, value); + } + + private final int exitCode; + private final T value; + + private CommandResult(int exitCode, T value) { + this.exitCode = exitCode; + this.value = value; + } + + public int getExitCode() { + return this.exitCode; + } + + public Optional getValue() { + return Optional.ofNullable(this.value); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ConsoleTestExecutor.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ConsoleTestExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ConsoleTestExecutor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ConsoleTestExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,236 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.console.command.DiscoveryRequestCreator.toDiscoveryRequestBuilder; +import static org.junit.platform.launcher.LauncherConstants.OUTPUT_DIR_PROPERTY_NAME; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; + +import org.apiguardian.api.API; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.util.ClassLoaderUtils; +import org.junit.platform.console.options.Details; +import org.junit.platform.console.options.TestConsoleOutputOptions; +import org.junit.platform.console.options.TestDiscoveryOptions; +import org.junit.platform.console.output.ColorPalette; +import org.junit.platform.console.output.DetailsPrintingListener; +import org.junit.platform.console.output.FlatPrintingListener; +import org.junit.platform.console.output.TestFeedPrintingListener; +import org.junit.platform.console.output.Theme; +import org.junit.platform.console.output.TreePrintingListener; +import org.junit.platform.console.output.VerboseTreePrintingListener; +import org.junit.platform.launcher.Launcher; +import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.TestExecutionListener; +import org.junit.platform.launcher.TestPlan; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; +import org.junit.platform.launcher.core.LauncherFactory; +import org.junit.platform.launcher.listeners.SummaryGeneratingListener; +import org.junit.platform.launcher.listeners.TestExecutionSummary; +import org.junit.platform.reporting.legacy.xml.LegacyXmlReportGeneratingListener; + +/** + * @since 1.0 + */ +@API(status = INTERNAL, since = "1.0") +public class ConsoleTestExecutor { + + private final TestDiscoveryOptions discoveryOptions; + private final TestConsoleOutputOptions outputOptions; + private final Supplier launcherSupplier; + private final CustomClassLoaderCloseStrategy classLoaderCloseStrategy; + + public ConsoleTestExecutor(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions) { + this(discoveryOptions, outputOptions, CustomClassLoaderCloseStrategy.CLOSE_AFTER_CALLING_LAUNCHER); + } + + public ConsoleTestExecutor(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions, + CustomClassLoaderCloseStrategy classLoaderCloseStrategy) { + this(discoveryOptions, outputOptions, classLoaderCloseStrategy, LauncherFactory::create); + } + + // for tests only + ConsoleTestExecutor(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions, + Supplier launcherSupplier) { + this(discoveryOptions, outputOptions, CustomClassLoaderCloseStrategy.CLOSE_AFTER_CALLING_LAUNCHER, + launcherSupplier); + } + + private ConsoleTestExecutor(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions, + CustomClassLoaderCloseStrategy classLoaderCloseStrategy, Supplier launcherSupplier) { + this.discoveryOptions = discoveryOptions; + this.outputOptions = outputOptions; + this.launcherSupplier = launcherSupplier; + this.classLoaderCloseStrategy = classLoaderCloseStrategy; + } + + public void discover(PrintWriter out) { + createCustomContextClassLoaderExecutor().invoke(() -> { + discoverTests(out); + return null; + }); + } + + public TestExecutionSummary execute(PrintWriter out, Optional reportsDir) { + return createCustomContextClassLoaderExecutor() // + .invoke(() -> executeTests(out, reportsDir)); + } + + private CustomContextClassLoaderExecutor createCustomContextClassLoaderExecutor() { + return new CustomContextClassLoaderExecutor(createCustomClassLoader(), classLoaderCloseStrategy); + } + + private void discoverTests(PrintWriter out) { + Launcher launcher = launcherSupplier.get(); + Optional commandLineTestPrinter = createDetailsPrintingListener(out); + + LauncherDiscoveryRequest discoveryRequest = toDiscoveryRequestBuilder(discoveryOptions).build(); + TestPlan testPlan = launcher.discover(discoveryRequest); + + commandLineTestPrinter.ifPresent(printer -> printer.listTests(testPlan)); + if (outputOptions.getDetails() != Details.NONE) { + printFoundTestsSummary(out, testPlan); + } + } + + private static void printFoundTestsSummary(PrintWriter out, TestPlan testPlan) { + SummaryGeneratingListener summaryListener = new SummaryGeneratingListener(); + summaryListener.testPlanExecutionStarted(testPlan); + TestExecutionSummary summary = summaryListener.getSummary(); + + out.printf("%n[%10d containers found ]%n[%10d tests found ]%n%n", summary.getContainersFoundCount(), + summary.getTestsFoundCount()); + out.flush(); + } + + private TestExecutionSummary executeTests(PrintWriter out, Optional reportsDir) { + Launcher launcher = launcherSupplier.get(); + SummaryGeneratingListener summaryListener = registerListeners(out, reportsDir, launcher); + + PrintStream originalOut = System.out; + PrintStream originalErr = System.err; + try (StandardStreamsHandler standardStreamsHandler = new StandardStreamsHandler()) { + standardStreamsHandler.redirectStandardStreams(outputOptions.getStdoutPath(), + outputOptions.getStderrPath()); + launchTests(launcher, reportsDir); + } + finally { + System.setOut(originalOut); + System.setErr(originalErr); + } + + TestExecutionSummary summary = summaryListener.getSummary(); + if (summary.getTotalFailureCount() > 0 || outputOptions.getDetails() != Details.NONE) { + printSummary(summary, out); + } + + return summary; + } + + private void launchTests(Launcher launcher, Optional reportsDir) { + LauncherDiscoveryRequestBuilder discoveryRequestBuilder = toDiscoveryRequestBuilder(discoveryOptions); + reportsDir.ifPresent(dir -> discoveryRequestBuilder.configurationParameter(OUTPUT_DIR_PROPERTY_NAME, + dir.toAbsolutePath().toString())); + launcher.execute(discoveryRequestBuilder.build()); + } + + private Optional createCustomClassLoader() { + List additionalClasspathEntries = discoveryOptions.getExistingAdditionalClasspathEntries(); + if (!additionalClasspathEntries.isEmpty()) { + URL[] urls = additionalClasspathEntries.stream().map(this::toURL).toArray(URL[]::new); + ClassLoader parentClassLoader = ClassLoaderUtils.getDefaultClassLoader(); + ClassLoader customClassLoader = URLClassLoader.newInstance(urls, parentClassLoader); + return Optional.of(customClassLoader); + } + return Optional.empty(); + } + + private URL toURL(Path path) { + try { + return path.toUri().toURL(); + } + catch (Exception ex) { + throw new JUnitException("Invalid classpath entry: " + path, ex); + } + } + + private SummaryGeneratingListener registerListeners(PrintWriter out, Optional reportsDir, Launcher launcher) { + // always register summary generating listener + SummaryGeneratingListener summaryListener = new SummaryGeneratingListener(); + launcher.registerTestExecutionListeners(summaryListener); + // optionally, register test plan execution details printing listener + createDetailsPrintingListener(out).ifPresent(launcher::registerTestExecutionListeners); + // optionally, register XML reports writing listener + createXmlWritingListener(out, reportsDir).ifPresent(launcher::registerTestExecutionListeners); + return summaryListener; + } + + private Optional createDetailsPrintingListener(PrintWriter out) { + ColorPalette colorPalette = getColorPalette(); + Theme theme = outputOptions.getTheme(); + switch (outputOptions.getDetails()) { + case SUMMARY: + // summary listener is always created and registered + return Optional.empty(); + case FLAT: + return Optional.of(new FlatPrintingListener(out, colorPalette)); + case TREE: + return Optional.of(new TreePrintingListener(out, colorPalette, theme)); + case VERBOSE: + return Optional.of(new VerboseTreePrintingListener(out, colorPalette, 16, theme)); + case TESTFEED: + return Optional.of(new TestFeedPrintingListener(out, colorPalette)); + default: + return Optional.empty(); + } + } + + private ColorPalette getColorPalette() { + if (outputOptions.isAnsiColorOutputDisabled()) { + return ColorPalette.NONE; + } + if (outputOptions.getColorPalettePath() != null) { + return new ColorPalette(outputOptions.getColorPalettePath()); + } + if (outputOptions.isSingleColorPalette()) { + return ColorPalette.SINGLE_COLOR; + } + return ColorPalette.DEFAULT; + } + + private Optional createXmlWritingListener(PrintWriter out, Optional reportsDir) { + return reportsDir.map(it -> new LegacyXmlReportGeneratingListener(it, out)); + } + + private void printSummary(TestExecutionSummary summary, PrintWriter out) { + // Otherwise the failures have already been printed in detail + if (EnumSet.of(Details.NONE, Details.SUMMARY, Details.TREE).contains(outputOptions.getDetails())) { + summary.printFailuresTo(out); + } + summary.printTo(out); + } + + @FunctionalInterface + public interface Factory { + ConsoleTestExecutor create(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomClassLoaderCloseStrategy.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomClassLoaderCloseStrategy.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomClassLoaderCloseStrategy.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomClassLoaderCloseStrategy.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import org.apiguardian.api.API; +import org.junit.platform.commons.JUnitException; + +/** + * Defines the strategy for closing custom class loaders created for test + * discovery and execution. + */ +@API(status = INTERNAL, since = "1.13") +public enum CustomClassLoaderCloseStrategy { + + /** + * Close the custom class loader after calling the + * {@link org.junit.platform.launcher.Launcher} for test discovery or + * execution. + */ + CLOSE_AFTER_CALLING_LAUNCHER { + + @Override + public void handle(ClassLoader customClassLoader) { + if (customClassLoader instanceof AutoCloseable) { + close((AutoCloseable) customClassLoader); + } + } + + private void close(AutoCloseable customClassLoader) { + try { + customClassLoader.close(); + } + catch (Exception e) { + throw new JUnitException("Failed to close custom class loader", e); + } + } + }, + + /** + * Rely on the JVM to release resources held by the custom class loader when + * it terminates. + * + *

    This mode is only safe to use when calling {@link System#exit(int)} + * afterward. + */ + KEEP_OPEN { + @Override + public void handle(ClassLoader customClassLoader) { + // do nothing + } + }; + + /** + * Handle the class loader according to the strategy. + */ + public abstract void handle(ClassLoader classLoader); + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomContextClassLoaderExecutor.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomContextClassLoaderExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomContextClassLoaderExecutor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/CustomContextClassLoaderExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.util.Optional; +import java.util.function.Supplier; + +/** + * @since 1.0 + */ +class CustomContextClassLoaderExecutor { + + private final Optional customClassLoader; + private final CustomClassLoaderCloseStrategy closeStrategy; + + CustomContextClassLoaderExecutor(Optional customClassLoader) { + this(customClassLoader, CustomClassLoaderCloseStrategy.CLOSE_AFTER_CALLING_LAUNCHER); + } + + CustomContextClassLoaderExecutor(Optional customClassLoader, + CustomClassLoaderCloseStrategy closeStrategy) { + this.customClassLoader = customClassLoader; + this.closeStrategy = closeStrategy; + } + + T invoke(Supplier supplier) { + if (customClassLoader.isPresent()) { + // Only get/set context class loader when necessary to prevent problems with + // security managers + return replaceThreadContextClassLoaderAndInvoke(customClassLoader.get(), supplier); + } + return supplier.get(); + } + + private T replaceThreadContextClassLoaderAndInvoke(ClassLoader customClassLoader, Supplier supplier) { + ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(customClassLoader); + return supplier.get(); + } + finally { + Thread.currentThread().setContextClassLoader(originalClassLoader); + closeStrategy.handle(customClassLoader); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoverTestsCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoverTestsCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoverTestsCommand.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoverTestsCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.io.PrintWriter; + +import org.junit.platform.console.options.TestConsoleOutputOptions; +import org.junit.platform.console.options.TestConsoleOutputOptionsMixin; +import org.junit.platform.console.options.TestDiscoveryOptions; +import org.junit.platform.console.options.TestDiscoveryOptionsMixin; + +import picocli.CommandLine.Command; +import picocli.CommandLine.Mixin; + +@Command(// + name = "discover", // + description = "Discover tests" // +) +class DiscoverTestsCommand extends BaseCommand { + + private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; + + @Mixin + TestDiscoveryOptionsMixin discoveryOptions; + + @Mixin + TestConsoleOutputOptionsMixin testOutputOptions; + + DiscoverTestsCommand(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { + this.consoleTestExecutorFactory = consoleTestExecutorFactory; + } + + @Override + protected Void execute(PrintWriter out) { + TestDiscoveryOptions discoveryOptions = this.discoveryOptions.toTestDiscoveryOptions(); + TestConsoleOutputOptions testOutputOptions = this.testOutputOptions.toTestConsoleOutputOptions(); + testOutputOptions.setAnsiColorOutputDisabled(this.ansiColorOption.isDisableAnsiColors()); + this.consoleTestExecutorFactory.create(discoveryOptions, testOutputOptions).discover(out); + return null; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoveryRequestCreator.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoveryRequestCreator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoveryRequestCreator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/DiscoveryRequestCreator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,182 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.junit.platform.engine.discovery.ClassNameFilter.excludeClassNamePatterns; +import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathRoots; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectModules; +import static org.junit.platform.engine.discovery.PackageNameFilter.excludePackageNames; +import static org.junit.platform.engine.discovery.PackageNameFilter.includePackageNames; +import static org.junit.platform.launcher.EngineFilter.excludeEngines; +import static org.junit.platform.launcher.EngineFilter.includeEngines; +import static org.junit.platform.launcher.MethodFilter.excludeMethodNamePatterns; +import static org.junit.platform.launcher.MethodFilter.includeMethodNamePatterns; +import static org.junit.platform.launcher.TagFilter.excludeTags; +import static org.junit.platform.launcher.TagFilter.includeTags; +import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.util.ModuleUtils; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.console.options.TestDiscoveryOptions; +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.discovery.ClassNameFilter; +import org.junit.platform.engine.discovery.ClassSelector; +import org.junit.platform.engine.discovery.ClasspathRootSelector; +import org.junit.platform.engine.discovery.IterationSelector; +import org.junit.platform.engine.discovery.MethodSelector; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; + +/** + * @since 1.0 + */ +class DiscoveryRequestCreator { + + private static final Logger logger = LoggerFactory.getLogger(DiscoveryRequestCreator.class); + + static LauncherDiscoveryRequestBuilder toDiscoveryRequestBuilder(TestDiscoveryOptions options) { + LauncherDiscoveryRequestBuilder requestBuilder = request(); + List selectors = createDiscoverySelectors(options); + requestBuilder.selectors(selectors); + addFilters(requestBuilder, options, selectors); + requestBuilder.configurationParameters(options.getConfigurationParameters()); + requestBuilder.configurationParametersResources( + options.getConfigurationParametersResources().toArray(new String[0])); + return requestBuilder; + } + + private static List createDiscoverySelectors(TestDiscoveryOptions options) { + List explicitSelectors = options.getExplicitSelectors(); + if (options.isScanClasspath()) { + Preconditions.condition(explicitSelectors.isEmpty(), + "Scanning the classpath and using explicit selectors at the same time is not supported"); + return createClasspathRootSelectors(options); + } + if (options.isScanModulepath()) { + Preconditions.condition(explicitSelectors.isEmpty(), + "Scanning the module-path and using explicit selectors at the same time is not supported"); + return selectModules(ModuleUtils.findAllNonSystemBootModuleNames()); + } + return Preconditions.notEmpty(explicitSelectors, + "Please specify an explicit selector option or use --scan-class-path or --scan-modules"); + } + + private static List createClasspathRootSelectors(TestDiscoveryOptions options) { + Set classpathRoots = validateAndLogInvalidRoots(determineClasspathRoots(options)); + return selectClasspathRoots(classpathRoots); + } + + private static Set determineClasspathRoots(TestDiscoveryOptions options) { + if (options.getSelectedClasspathEntries().isEmpty()) { + Set rootDirs = new LinkedHashSet<>(ReflectionUtils.getAllClasspathRootDirectories()); + rootDirs.addAll(options.getAdditionalClasspathEntries()); + return rootDirs; + } + return new LinkedHashSet<>(options.getSelectedClasspathEntries()); + } + + private static Set validateAndLogInvalidRoots(Set roots) { + LinkedHashSet valid = new LinkedHashSet<>(); + HashSet seen = new HashSet<>(); + + for (Path root : roots) { + if (!seen.add(root)) { + continue; + } + if (Files.exists(root)) { + valid.add(root); + } + else { + logger.warn(() -> String.format("Ignoring nonexistent classpath root: %s", root)); + } + } + + return valid; + } + + private static void addFilters(LauncherDiscoveryRequestBuilder requestBuilder, TestDiscoveryOptions options, + List selectors) { + requestBuilder.filters(includedClassNamePatterns(options, selectors)); + + if (!options.getExcludedClassNamePatterns().isEmpty()) { + requestBuilder.filters( + excludeClassNamePatterns(options.getExcludedClassNamePatterns().toArray(new String[0]))); + } + + if (!options.getIncludedPackages().isEmpty()) { + requestBuilder.filters(includePackageNames(options.getIncludedPackages())); + } + + if (!options.getExcludedPackages().isEmpty()) { + requestBuilder.filters(excludePackageNames(options.getExcludedPackages())); + } + + if (!options.getIncludedMethodNamePatterns().isEmpty()) { + requestBuilder.filters(includeMethodNamePatterns(options.getIncludedMethodNamePatterns())); + } + + if (!options.getExcludedMethodNamePatterns().isEmpty()) { + requestBuilder.filters(excludeMethodNamePatterns(options.getExcludedMethodNamePatterns())); + } + + if (!options.getIncludedTagExpressions().isEmpty()) { + requestBuilder.filters(includeTags(options.getIncludedTagExpressions())); + } + + if (!options.getExcludedTagExpressions().isEmpty()) { + requestBuilder.filters(excludeTags(options.getExcludedTagExpressions())); + } + + if (!options.getIncludedEngines().isEmpty()) { + requestBuilder.filters(includeEngines(options.getIncludedEngines())); + } + + if (!options.getExcludedEngines().isEmpty()) { + requestBuilder.filters(excludeEngines(options.getExcludedEngines())); + } + } + + private static ClassNameFilter includedClassNamePatterns(TestDiscoveryOptions options, + List selectors) { + Stream patternStreams = Stream.concat( // + options.getIncludedClassNamePatterns().stream(), // + selectors.stream() // + .map(selector -> selector instanceof IterationSelector + ? ((IterationSelector) selector).getParentSelector() + : selector) // + .map(selector -> { + if (selector instanceof ClassSelector) { + return ((ClassSelector) selector).getClassName(); + } + if (selector instanceof MethodSelector) { + return ((MethodSelector) selector).getClassName(); + } + return null; + }) // + .filter(Objects::nonNull) // + .map(Pattern::quote)); + return includeClassNamePatterns(patternStreams.toArray(String[]::new)); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ExecuteTestsCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ExecuteTestsCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ExecuteTestsCommand.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ExecuteTestsCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.junit.platform.console.command.CommandResult.SUCCESS; + +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.Optional; + +import org.junit.platform.console.options.TestConsoleOutputOptions; +import org.junit.platform.console.options.TestConsoleOutputOptionsMixin; +import org.junit.platform.console.options.TestDiscoveryOptions; +import org.junit.platform.console.options.TestDiscoveryOptionsMixin; +import org.junit.platform.launcher.listeners.TestExecutionSummary; + +import picocli.CommandLine; +import picocli.CommandLine.ArgGroup; +import picocli.CommandLine.Command; +import picocli.CommandLine.Mixin; + +@Command(// + name = "execute", // + description = "Execute tests" // +) +class ExecuteTestsCommand extends BaseCommand implements CommandLine.IExitCodeGenerator { + + /** + * Exit code indicating test failure(s) + */ + private static final int TEST_FAILED = 1; + + /** + * Exit code indicating no tests found + */ + private static final int NO_TESTS_FOUND = 2; + + private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; + + @Mixin + TestDiscoveryOptionsMixin discoveryOptions; + + @Mixin + TestConsoleOutputOptionsMixin testOutputOptions; + + @ArgGroup(validate = false, order = 6, heading = "%n@|bold REPORTING|@%n%n") + ReportingOptions reportingOptions; + + ExecuteTestsCommand(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { + this.consoleTestExecutorFactory = consoleTestExecutorFactory; + } + + @Override + protected TestExecutionSummary execute(PrintWriter out) { + return consoleTestExecutorFactory.create(toTestDiscoveryOptions(), toTestConsoleOutputOptions()) // + .execute(out, getReportsDir()); + } + + Optional getReportsDir() { + return getReportingOptions().flatMap(ReportingOptions::getReportsDir); + } + + private Optional getReportingOptions() { + return Optional.ofNullable(reportingOptions); + } + + TestDiscoveryOptions toTestDiscoveryOptions() { + return this.discoveryOptions == null // + ? new TestDiscoveryOptions() // + : this.discoveryOptions.toTestDiscoveryOptions(); + } + + TestConsoleOutputOptions toTestConsoleOutputOptions() { + TestConsoleOutputOptions testOutputOptions = this.testOutputOptions.toTestConsoleOutputOptions(); + testOutputOptions.setAnsiColorOutputDisabled(this.ansiColorOption.isDisableAnsiColors()); + return testOutputOptions; + } + + @Override + public int getExitCode() { + TestExecutionSummary executionResult = commandSpec.commandLine().getExecutionResult(); + boolean failIfNoTests = getReportingOptions().map(it -> it.failIfNoTests).orElse(false); + if (failIfNoTests && executionResult.getTestsFoundCount() == 0) { + return NO_TESTS_FOUND; + } + return executionResult.getTotalFailureCount() == 0 ? SUCCESS : TEST_FAILED; + } + + static class ReportingOptions { + + @CommandLine.Option(names = "--fail-if-no-tests", description = "Fail and return exit status code 2 if no tests are found.") + private boolean failIfNoTests; // no single-dash equivalent: was introduced in 5.3-M1 + + @CommandLine.Option(names = "--reports-dir", paramLabel = "DIR", description = "Enable report output into a specified local directory (will be created if it does not exist).") + private Path reportsDir; + + @CommandLine.Option(names = "-reports-dir", hidden = true) + private Path reportsDir2; + + Optional getReportsDir() { + return reportsDir == null ? Optional.ofNullable(reportsDir2) : Optional.of(reportsDir); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ListTestEnginesCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ListTestEnginesCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ListTestEnginesCommand.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ListTestEnginesCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.io.PrintWriter; +import java.util.Comparator; +import java.util.StringJoiner; +import java.util.stream.StreamSupport; + +import org.junit.platform.engine.TestEngine; +import org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry; + +import picocli.CommandLine.Command; + +@Command(// + name = "engines", // + description = "List available test engines" // +) +class ListTestEnginesCommand extends BaseCommand { + + @Override + protected Void execute(PrintWriter out) { + displayEngines(out); + return null; + } + + void displayEngines(PrintWriter out) { + ServiceLoaderTestEngineRegistry registry = new ServiceLoaderTestEngineRegistry(); + Iterable engines = registry.loadTestEngines(); + StreamSupport.stream(engines.spliterator(), false) // + .sorted(Comparator.comparing(TestEngine::getId)) // + .forEach(engine -> displayEngine(out, engine)); + out.flush(); + } + + private void displayEngine(PrintWriter out, TestEngine engine) { + StringJoiner details = new StringJoiner(":", " (", ")"); + engine.getGroupId().ifPresent(details::add); + engine.getArtifactId().ifPresent(details::add); + engine.getVersion().ifPresent(details::add); + out.println(getColorScheme().string(String.format("@|bold %s|@%s", engine.getId(), details))); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/MainCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/MainCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/MainCommand.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/MainCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,160 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.Callable; + +import org.junit.platform.console.options.AnsiColorOptionMixin; + +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Help.ColorScheme; +import picocli.CommandLine.IExitCodeGenerator; +import picocli.CommandLine.Mixin; +import picocli.CommandLine.Model.CommandSpec; +import picocli.CommandLine.Option; +import picocli.CommandLine.Spec; +import picocli.CommandLine.Unmatched; + +@Command(// + name = "junit", // + abbreviateSynopsis = true, // + sortOptions = false, // + usageHelpWidth = 95, // + showAtFileInUsageHelp = true, // + usageHelpAutoWidth = true, // + description = "Launches the JUnit Platform for test discovery and execution.", // + footerHeading = "%n", // + footer = "For more information, please refer to the JUnit User Guide at%n" // + + "@|underline https://docs.junit.org/${junit.docs.version}/user-guide/|@", // + scope = CommandLine.ScopeType.INHERIT, // + exitCodeOnInvalidInput = CommandResult.FAILURE, // + exitCodeOnExecutionException = CommandResult.FAILURE, // + versionProvider = ManifestVersionProvider.class // +) +class MainCommand implements Callable, IExitCodeGenerator { + + private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; + + @Option(names = { "-h", "--help" }, help = true, description = "Display help information.") + private boolean helpRequested; + + @Option(names = { "--h", "-help" }, help = true, hidden = true) + private boolean helpRequested2; + + @Option(names = "--version", versionHelp = true, description = "Display version information.") + private boolean versionHelpRequested; + + @Mixin + AnsiColorOptionMixin ansiColorOption; + + @Unmatched + private List allParameters = new ArrayList<>(); + + @Spec + CommandSpec commandSpec; + + CommandResult commandResult; + + MainCommand(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { + this.consoleTestExecutorFactory = consoleTestExecutorFactory; + } + + @Override + public Object call() { + if (helpRequested || helpRequested2) { + commandSpec.commandLine().usage(commandSpec.commandLine().getOut()); + commandResult = CommandResult.success(); + return null; + } + if (versionHelpRequested) { + commandSpec.commandLine().printVersionHelp(commandSpec.commandLine().getOut()); + commandResult = CommandResult.success(); + return null; + } + if (allParameters.contains("--list-engines")) { + return runCommand("engines", Optional.of("--list-engines")); + } + return runCommand("execute", Optional.empty()); + } + + @Override + public int getExitCode() { + return commandResult.getExitCode(); + } + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + private Object runCommand(String subcommand, Optional triggeringOption) { + CommandLine commandLine = commandSpec.commandLine(); + commandLine.setUnmatchedArgumentsAllowed(false); + Object command = commandLine.getSubcommands().get(subcommand).getCommandSpec().userObject(); + + List args = new ArrayList<>(commandLine.getParseResult().expandedArgs()); + triggeringOption.ifPresent(args::remove); + CommandResult result = runCommand( // + new CommandLine(command), // + args.toArray(new String[0]), // + Optional.of(new OutputStreamConfig(commandLine)) // + ); + this.commandResult = result; + + printDeprecationWarning(subcommand, triggeringOption, commandLine); + + return result.getValue().orElse(null); + } + + private static void printDeprecationWarning(String subcommand, Optional triggeringOption, + CommandLine commandLine) { + PrintWriter err = commandLine.getErr(); + String reason = triggeringOption.map(it -> " due to use of '" + it + "'").orElse(""); + + commandLine.getOut().flush(); + err.println(); + ColorScheme colorScheme = commandLine.getColorScheme(); + err.println(colorScheme.string( + String.format("@|yellow,bold WARNING:|@ Delegated to the '%s' command%s.", subcommand, reason))); + err.println( + colorScheme.string(" This behaviour has been deprecated and will be removed in a future release.")); + err.println(colorScheme.string(" Please use the '" + subcommand + "' command directly.")); + err.flush(); + } + + CommandResult run(String[] args, Optional outputStreamConfig) { + CommandLine commandLine = new CommandLine(this) // + .addSubcommand(new DiscoverTestsCommand(consoleTestExecutorFactory)) // + .addSubcommand(new ExecuteTestsCommand(consoleTestExecutorFactory)) // + .addSubcommand(new ListTestEnginesCommand()); + return runCommand(commandLine, args, outputStreamConfig); + } + + private static CommandResult runCommand(CommandLine commandLine, String[] args, + Optional outputStreamConfig) { + BaseCommand.initialize(commandLine); + outputStreamConfig.ifPresent(it -> it.applyTo(commandLine)); + int exitCode = commandLine.execute(args); + return CommandResult.create(exitCode, getLikelyExecutedCommand(commandLine).getExecutionResult()); + } + + /** + * Get the most likely executed subcommand, if any, or the main command otherwise. + * @see Executing Commands with Subcommands + */ + private static CommandLine getLikelyExecutedCommand(final CommandLine commandLine) { + return Optional.ofNullable(commandLine.getParseResult().subcommand()) // + .map(parseResult -> parseResult.commandSpec().commandLine()) // + .orElse(commandLine); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ManifestVersionProvider.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ManifestVersionProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ManifestVersionProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/ManifestVersionProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.util.Optional; + +import org.junit.platform.commons.util.PackageUtils; + +import picocli.CommandLine; + +class ManifestVersionProvider implements CommandLine.IVersionProvider { + + public static Optional getImplementationVersion() { + return PackageUtils.getModuleOrImplementationVersion(ManifestVersionProvider.class); + } + + @Override + public String[] getVersion() { + return new String[] { // + String.format("@|bold JUnit Platform Console Launcher %s|@", + getImplementationVersion().orElse("")), // + "JVM: ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})", // + "OS: ${os.name} ${os.version} ${os.arch}" // + }; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/OutputStreamConfig.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/OutputStreamConfig.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/OutputStreamConfig.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/OutputStreamConfig.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.io.PrintWriter; + +import picocli.CommandLine; + +class OutputStreamConfig { + + private final PrintWriter out; + private final PrintWriter err; + + OutputStreamConfig(CommandLine commandLine) { + this(commandLine.getOut(), commandLine.getErr()); + } + + OutputStreamConfig(PrintWriter out, PrintWriter err) { + this.out = out; + this.err = err; + } + + void applyTo(CommandLine commandLine) { + commandLine.setOut(this.out).setErr(this.err); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/StandardStreamsHandler.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/StandardStreamsHandler.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/StandardStreamsHandler.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/StandardStreamsHandler.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,102 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.platform.commons.JUnitException; + +class StandardStreamsHandler implements AutoCloseable { + + private PrintStream stdout; + + private PrintStream stderr; + + public StandardStreamsHandler() { + } + + /** + * Redirect standard output (stdout) and standard error (stderr) to the specified + * file paths. + * + *

    If the paths are the same, both streams are redirected to the same file. + * + *

    The default charset is used for writing to the files. + * + * @param stdoutPath the file path for standard output, or {@code null} to + * indicate no redirection + * @param stderrPath the file path for standard error, or {@code null} to + * indicate no redirection + */ + public void redirectStandardStreams(Path stdoutPath, Path stderrPath) { + if (isSameFile(stdoutPath, stderrPath)) { + try { + PrintStream commonStream = new PrintStream(Files.newOutputStream(stdoutPath), true); + this.stdout = commonStream; + this.stderr = commonStream; + } + catch (IOException ex) { + throw new JUnitException("Error redirecting stdout and stderr to file: " + stdoutPath, ex); + } + } + else { + if (stdoutPath != null) { + try { + this.stdout = new PrintStream(Files.newOutputStream(stdoutPath), true); + } + catch (IOException ex) { + throw new JUnitException("Error redirecting stdout to file: " + stdoutPath, ex); + } + } + + if (stderrPath != null) { + try { + this.stderr = new PrintStream(Files.newOutputStream(stderrPath), true); + } + catch (IOException ex) { + throw new JUnitException("Error redirecting stderr to file: " + stderrPath, ex); + } + } + } + + if (this.stdout != null) { + System.setOut(this.stdout); + } + if (this.stderr != null) { + System.setErr(this.stderr); + } + } + + @Override + public void close() { + try { + if (this.stdout != null) { + this.stdout.close(); + } + } + finally { + if (this.stderr != null) { + this.stderr.close(); + } + } + } + + private static boolean isSameFile(Path path1, Path path2) { + if (path1 == null || path2 == null) { + return false; + } + return path1.normalize().toAbsolutePath().equals(path2.normalize().toAbsolutePath()); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/command/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,5 @@ +/** + * Commands of JUnit's console launcher. + */ + +package org.junit.platform.console.command; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/AnsiColorOptionMixin.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/AnsiColorOptionMixin.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/AnsiColorOptionMixin.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/AnsiColorOptionMixin.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,15 +10,19 @@ package org.junit.platform.console.options; +import static org.apiguardian.api.API.Status.INTERNAL; import static picocli.CommandLine.Help.defaultColorScheme; import static picocli.CommandLine.Spec.Target.MIXEE; +import org.apiguardian.api.API; + import picocli.CommandLine.Help.Ansi; import picocli.CommandLine.Model.CommandSpec; import picocli.CommandLine.Option; import picocli.CommandLine.Spec; -class AnsiColorOptionMixin { +@API(status = INTERNAL, since = "1.14") +public class AnsiColorOptionMixin { @Spec(MIXEE) CommandSpec commandSpec; @@ -28,13 +32,13 @@ private boolean disableAnsiColors = System.getenv("NO_COLOR") != null; public boolean isDisableAnsiColors() { - return disableAnsiColors; + return this.disableAnsiColors; } @Option(names = "--disable-ansi-colors", description = "Disable ANSI colors in output (not supported by all terminals).") public void setDisableAnsiColors(boolean disableAnsiColors) { if (disableAnsiColors) { - commandSpec.commandLine().setColorScheme(defaultColorScheme(Ansi.OFF)); + this.commandSpec.commandLine().setColorScheme(defaultColorScheme(Ansi.OFF)); } this.disableAnsiColors = disableAnsiColors; } @@ -43,4 +47,5 @@ public void setDisableAnsiColors2(boolean disableAnsiColors) { setDisableAnsiColors(disableAnsiColors); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BannerOptionMixin.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BannerOptionMixin.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BannerOptionMixin.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BannerOptionMixin.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import picocli.CommandLine.Option; - -class BannerOptionMixin { - - @Option(names = "--disable-banner", description = "Disable print out of the welcome message.") - private boolean disableBanner; - - @Option(names = "-disable-banner", hidden = true) - private boolean disableBanner2; - - public boolean isDisableBanner() { - return disableBanner || disableBanner2; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BaseCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BaseCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BaseCommand.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/BaseCommand.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import java.io.PrintWriter; -import java.util.concurrent.Callable; - -import org.junit.platform.commons.PreconditionViolationException; - -import picocli.CommandLine; -import picocli.CommandLine.Mixin; -import picocli.CommandLine.Model.CommandSpec; -import picocli.CommandLine.Option; -import picocli.CommandLine.ParameterException; -import picocli.CommandLine.Spec; - -abstract class BaseCommand implements Callable { - - @Spec - CommandSpec commandSpec; - - @Mixin - AnsiColorOptionMixin ansiColorOption; - - @Mixin - BannerOptionMixin bannerOption; - - @SuppressWarnings("unused") - @Option(names = { "-h", "--help" }, usageHelp = true, description = "Display help information.") - private boolean helpRequested; - - @SuppressWarnings("unused") - @Option(names = "--version", versionHelp = true, description = "Display version information.") - private boolean versionHelpRequested; - - void execute(String... args) { - toCommandLine().execute(args); - } - - void parseArgs(String... args) { - toCommandLine().parseArgs(args); - } - - private CommandLine toCommandLine() { - return BaseCommand.initialize(new CommandLine(this)); - } - - static CommandLine initialize(CommandLine commandLine) { - CommandLine.IParameterExceptionHandler defaultParameterExceptionHandler = commandLine.getParameterExceptionHandler(); - return commandLine // - .setParameterExceptionHandler((ex, args) -> { - defaultParameterExceptionHandler.handleParseException(ex, args); - return CommandResult.FAILURE; - }) // - .setExecutionExceptionHandler((ex, cmd, __) -> { - commandLine.getErr().println(cmd.getColorScheme().richStackTraceString(ex)); - commandLine.getErr().println(); - commandLine.getErr().flush(); - cmd.usage(commandLine.getOut()); - return CommandResult.FAILURE; - }) // - .setCaseInsensitiveEnumValuesAllowed(true) // - .setAtFileCommentChar(null); - } - - @Override - public final T call() { - PrintWriter out = getOut(); - if (!bannerOption.isDisableBanner()) { - displayBanner(out); - } - try { - return execute(out); - } - catch (PreconditionViolationException e) { - throw new ParameterException(commandSpec.commandLine(), e.getMessage(), e.getCause()); - } - } - - private PrintWriter getOut() { - return commandSpec.commandLine().getOut(); - } - - private void displayBanner(PrintWriter out) { - out.println(); - CommandLine.Help.ColorScheme colorScheme = getColorScheme(); - if (colorScheme.ansi().enabled()) { - out.print("💚 "); - } - out.println(colorScheme.string( - "@|italic Thanks for using JUnit!|@ Support its development at @|underline https://junit.org/sponsoring|@")); - out.println(); - out.flush(); - } - - protected final CommandLine.Help.ColorScheme getColorScheme() { - return commandSpec.commandLine().getColorScheme(); - } - - protected abstract T execute(PrintWriter out); -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ClasspathEntriesConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ClasspathEntriesConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ClasspathEntriesConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ClasspathEntriesConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,8 +20,10 @@ import picocli.CommandLine; class ClasspathEntriesConverter implements CommandLine.ITypeConverter> { + @Override public List convert(String value) { return Stream.of(value.split(File.pathSeparator)).map(Paths::get).collect(Collectors.toList()); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandFacade.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandFacade.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandFacade.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandFacade.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.io.PrintWriter; -import java.util.Optional; - -import org.apiguardian.api.API; -import org.junit.platform.console.tasks.ConsoleTestExecutor; - -/** - * Internal facade to run a CLI command that exists to hide implementation - * details such as the used library. - * - * @since 1.10 - */ -@API(status = INTERNAL, since = "1.10") -public class CommandFacade { - - private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; - - public CommandFacade(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { - this.consoleTestExecutorFactory = consoleTestExecutorFactory; - } - - public CommandResult run(String[] args) { - return run(args, Optional.empty()); - } - - public CommandResult run(String[] args, PrintWriter out, PrintWriter err) { - try { - return run(args, Optional.of(new OutputStreamConfig(out, err))); - } - finally { - out.flush(); - err.flush(); - } - } - - private CommandResult run(String[] args, Optional outputStreamConfig) { - Optional version = ManifestVersionProvider.getImplementationVersion(); - System.setProperty("junit.docs.version", - version.map(it -> it.endsWith("-SNAPSHOT") ? "snapshot" : it).orElse("current")); - return new MainCommand(consoleTestExecutorFactory).run(args, outputStreamConfig); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/CommandResult.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.util.Optional; - -import org.apiguardian.api.API; - -/** - * @since 1.10 - */ -@API(status = INTERNAL, since = "1.10") -public class CommandResult { - - /** - * Exit code indicating successful execution - */ - public static final int SUCCESS = 0; - - /** - * Exit code indicating any failure(s) - */ - protected static final int FAILURE = -1; - - public static CommandResult success() { - return create(SUCCESS, null); - } - - public static CommandResult failure() { - return create(FAILURE, null); - } - - public static CommandResult create(int exitCode, T value) { - return new CommandResult<>(exitCode, value); - } - - private final int exitCode; - private final T value; - - private CommandResult(int exitCode, T value) { - this.exitCode = exitCode; - this.value = value; - } - - public int getExitCode() { - return exitCode; - } - - public Optional getValue() { - return Optional.ofNullable(value); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ConsoleUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ConsoleUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ConsoleUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ConsoleUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -37,4 +37,5 @@ public static Charset charset() { return Charset.defaultCharset(); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Details.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Details.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Details.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Details.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/DiscoverTestsCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/DiscoverTestsCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/DiscoverTestsCommand.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/DiscoverTestsCommand.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import java.io.PrintWriter; - -import org.junit.platform.console.tasks.ConsoleTestExecutor; - -import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; - -@Command(// - name = "discover", // - description = "Discover tests" // -) -class DiscoverTestsCommand extends BaseCommand { - - private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; - - @Mixin - TestDiscoveryOptionsMixin discoveryOptions; - - @Mixin - TestConsoleOutputOptionsMixin testOutputOptions; - - DiscoverTestsCommand(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { - this.consoleTestExecutorFactory = consoleTestExecutorFactory; - } - - @Override - protected Void execute(PrintWriter out) { - TestDiscoveryOptions discoveryOptions = this.discoveryOptions.toTestDiscoveryOptions(); - TestConsoleOutputOptions testOutputOptions = this.testOutputOptions.toTestConsoleOutputOptions(); - testOutputOptions.setAnsiColorOutputDisabled(this.ansiColorOption.isDisableAnsiColors()); - this.consoleTestExecutorFactory.create(discoveryOptions, testOutputOptions).discover(out); - return null; - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ExecuteTestsCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ExecuteTestsCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ExecuteTestsCommand.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ExecuteTestsCommand.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.junit.platform.console.options.CommandResult.SUCCESS; - -import java.io.PrintWriter; -import java.nio.file.Path; -import java.util.Optional; - -import org.junit.platform.console.tasks.ConsoleTestExecutor; -import org.junit.platform.launcher.listeners.TestExecutionSummary; - -import picocli.CommandLine; -import picocli.CommandLine.ArgGroup; -import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; - -@Command(// - name = "execute", // - description = "Execute tests" // -) -class ExecuteTestsCommand extends BaseCommand implements CommandLine.IExitCodeGenerator { - - /** - * Exit code indicating test failure(s) - */ - private static final int TEST_FAILED = 1; - - /** - * Exit code indicating no tests found - */ - private static final int NO_TESTS_FOUND = 2; - - private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; - - @Mixin - TestDiscoveryOptionsMixin discoveryOptions; - - @Mixin - TestConsoleOutputOptionsMixin testOutputOptions; - - @ArgGroup(validate = false, order = 6, heading = "%n@|bold REPORTING|@%n%n") - ReportingOptions reportingOptions; - - ExecuteTestsCommand(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { - this.consoleTestExecutorFactory = consoleTestExecutorFactory; - } - - @Override - protected TestExecutionSummary execute(PrintWriter out) { - return consoleTestExecutorFactory.create(toTestDiscoveryOptions(), toTestConsoleOutputOptions()) // - .execute(out, getReportsDir()); - } - - Optional getReportsDir() { - return getReportingOptions().flatMap(ReportingOptions::getReportsDir); - } - - private Optional getReportingOptions() { - return Optional.ofNullable(reportingOptions); - } - - TestDiscoveryOptions toTestDiscoveryOptions() { - return this.discoveryOptions == null // - ? new TestDiscoveryOptions() // - : this.discoveryOptions.toTestDiscoveryOptions(); - } - - TestConsoleOutputOptions toTestConsoleOutputOptions() { - TestConsoleOutputOptions testOutputOptions = this.testOutputOptions.toTestConsoleOutputOptions(); - testOutputOptions.setAnsiColorOutputDisabled(this.ansiColorOption.isDisableAnsiColors()); - return testOutputOptions; - } - - @Override - public int getExitCode() { - TestExecutionSummary executionResult = commandSpec.commandLine().getExecutionResult(); - boolean failIfNoTests = getReportingOptions().map(it -> it.failIfNoTests).orElse(false); - if (failIfNoTests && executionResult.getTestsFoundCount() == 0) { - return NO_TESTS_FOUND; - } - return executionResult.getTotalFailureCount() == 0 ? SUCCESS : TEST_FAILED; - } - - static class ReportingOptions { - - @CommandLine.Option(names = "--fail-if-no-tests", description = "Fail and return exit status code 2 if no tests are found.") - private boolean failIfNoTests; // no single-dash equivalent: was introduced in 5.3-M1 - - @CommandLine.Option(names = "--reports-dir", paramLabel = "DIR", description = "Enable report output into a specified local directory (will be created if it does not exist).") - private Path reportsDir; - - @CommandLine.Option(names = "-reports-dir", hidden = true) - private Path reportsDir2; - - Optional getReportsDir() { - return reportsDir == null ? Optional.ofNullable(reportsDir2) : Optional.of(reportsDir); - } - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ListTestEnginesCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ListTestEnginesCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ListTestEnginesCommand.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ListTestEnginesCommand.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import java.io.PrintWriter; -import java.util.Comparator; -import java.util.StringJoiner; -import java.util.stream.StreamSupport; - -import org.junit.platform.engine.TestEngine; -import org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry; - -import picocli.CommandLine.Command; - -@Command(// - name = "engines", // - description = "List available test engines" // -) -class ListTestEnginesCommand extends BaseCommand { - - @Override - protected Void execute(PrintWriter out) { - displayEngines(out); - return null; - } - - void displayEngines(PrintWriter out) { - ServiceLoaderTestEngineRegistry registry = new ServiceLoaderTestEngineRegistry(); - Iterable engines = registry.loadTestEngines(); - StreamSupport.stream(engines.spliterator(), false) // - .sorted(Comparator.comparing(TestEngine::getId)) // - .forEach(engine -> displayEngine(out, engine)); - out.flush(); - } - - private void displayEngine(PrintWriter out, TestEngine engine) { - StringJoiner details = new StringJoiner(":", " (", ")"); - engine.getGroupId().ifPresent(details::add); - engine.getArtifactId().ifPresent(details::add); - engine.getVersion().ifPresent(details::add); - out.println(getColorScheme().string(String.format("@|bold %s|@%s", engine.getId(), details))); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.Callable; - -import org.junit.platform.console.tasks.ConsoleTestExecutor; - -import picocli.CommandLine; -import picocli.CommandLine.Command; -import picocli.CommandLine.Help.ColorScheme; -import picocli.CommandLine.IExitCodeGenerator; -import picocli.CommandLine.Mixin; -import picocli.CommandLine.Model.CommandSpec; -import picocli.CommandLine.Option; -import picocli.CommandLine.Spec; -import picocli.CommandLine.Unmatched; - -@Command(// - name = "junit", // - abbreviateSynopsis = true, // - sortOptions = false, // - usageHelpWidth = 95, // - showAtFileInUsageHelp = true, // - usageHelpAutoWidth = true, // - description = "Launches the JUnit Platform for test discovery and execution.", // - footerHeading = "%n", // - footer = "For more information, please refer to the JUnit User Guide at%n" // - + "@|underline https://junit.org/junit5/docs/${junit.docs.version}/user-guide/|@", // - scope = CommandLine.ScopeType.INHERIT, // - exitCodeOnInvalidInput = CommandResult.FAILURE, // - exitCodeOnExecutionException = CommandResult.FAILURE, // - versionProvider = ManifestVersionProvider.class // -) -class MainCommand implements Callable, IExitCodeGenerator { - - private final ConsoleTestExecutor.Factory consoleTestExecutorFactory; - - @Option(names = { "-h", "--help" }, help = true, description = "Display help information.") - private boolean helpRequested; - - @Option(names = { "--h", "-help" }, help = true, hidden = true) - private boolean helpRequested2; - - @Option(names = "--version", versionHelp = true, description = "Display version information.") - private boolean versionHelpRequested; - - @Mixin - AnsiColorOptionMixin ansiColorOption; - - @Unmatched - private final List allParameters = new ArrayList<>(); - - @Spec - CommandSpec commandSpec; - - CommandResult commandResult; - - MainCommand(ConsoleTestExecutor.Factory consoleTestExecutorFactory) { - this.consoleTestExecutorFactory = consoleTestExecutorFactory; - } - - @Override - public Object call() { - if (helpRequested || helpRequested2) { - commandSpec.commandLine().usage(commandSpec.commandLine().getOut()); - commandResult = CommandResult.success(); - return null; - } - if (versionHelpRequested) { - commandSpec.commandLine().printVersionHelp(commandSpec.commandLine().getOut()); - commandResult = CommandResult.success(); - return null; - } - if (allParameters.contains("--list-engines")) { - return runCommand("engines", Optional.of("--list-engines")); - } - return runCommand("execute", Optional.empty()); - } - - @Override - public int getExitCode() { - return commandResult.getExitCode(); - } - - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - private Object runCommand(String subcommand, Optional triggeringOption) { - CommandLine commandLine = commandSpec.commandLine(); - commandLine.setUnmatchedArgumentsAllowed(false); - Object command = commandLine.getSubcommands().get(subcommand).getCommandSpec().userObject(); - - List args = new ArrayList<>(commandLine.getParseResult().expandedArgs()); - triggeringOption.ifPresent(args::remove); - CommandResult result = runCommand( // - new CommandLine(command), // - args.toArray(new String[0]), // - Optional.of(new OutputStreamConfig(commandLine)) // - ); - this.commandResult = result; - - printDeprecationWarning(subcommand, triggeringOption, commandLine); - - return result.getValue().orElse(null); - } - - private static void printDeprecationWarning(String subcommand, Optional triggeringOption, - CommandLine commandLine) { - PrintWriter err = commandLine.getErr(); - String reason = triggeringOption.map(it -> " due to use of '" + it + "'").orElse(""); - - commandLine.getOut().flush(); - err.println(); - ColorScheme colorScheme = commandLine.getColorScheme(); - err.println(colorScheme.string( - String.format("@|yellow,bold WARNING:|@ Delegated to the '%s' command%s.", subcommand, reason))); - err.println( - colorScheme.string(" This behaviour has been deprecated and will be removed in a future release.")); - err.println(colorScheme.string(" Please use the '" + subcommand + "' command directly.")); - err.flush(); - } - - CommandResult run(String[] args, Optional outputStreamConfig) { - CommandLine commandLine = new CommandLine(this) // - .addSubcommand(new DiscoverTestsCommand(consoleTestExecutorFactory)) // - .addSubcommand(new ExecuteTestsCommand(consoleTestExecutorFactory)) // - .addSubcommand(new ListTestEnginesCommand()); - return runCommand(commandLine, args, outputStreamConfig); - } - - private static CommandResult runCommand(CommandLine commandLine, String[] args, - Optional outputStreamConfig) { - BaseCommand.initialize(commandLine); - outputStreamConfig.ifPresent(it -> it.applyTo(commandLine)); - int exitCode = commandLine.execute(args); - return CommandResult.create(exitCode, getLikelyExecutedCommand(commandLine).getExecutionResult()); - } - - /** - * Get the most likely executed subcommand, if any, or the main command otherwise. - * @see Executing Commands with Subcommands - */ - private static CommandLine getLikelyExecutedCommand(final CommandLine commandLine) { - return Optional.ofNullable(commandLine.getParseResult().subcommand()) // - .map(parseResult -> parseResult.commandSpec().commandLine()) // - .orElse(commandLine); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ManifestVersionProvider.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ManifestVersionProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ManifestVersionProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/ManifestVersionProvider.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import java.util.Optional; - -import org.junit.platform.commons.util.PackageUtils; - -import picocli.CommandLine; - -class ManifestVersionProvider implements CommandLine.IVersionProvider { - - public static Optional getImplementationVersion() { - return PackageUtils.getModuleOrImplementationVersion(ManifestVersionProvider.class); - } - - @Override - public String[] getVersion() { - return new String[] { // - String.format("@|bold JUnit Platform Console Launcher %s|@", - getImplementationVersion().orElse("")), // - "JVM: ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})", // - "OS: ${os.name} ${os.version} ${os.arch}" // - }; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/OutputStreamConfig.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/OutputStreamConfig.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/OutputStreamConfig.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/OutputStreamConfig.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import java.io.PrintWriter; - -import picocli.CommandLine; - -class OutputStreamConfig { - - private final PrintWriter out; - private final PrintWriter err; - - OutputStreamConfig(CommandLine commandLine) { - this(commandLine.getOut(), commandLine.getErr()); - } - - OutputStreamConfig(PrintWriter out, PrintWriter err) { - this.out = out; - this.err = err; - } - - void applyTo(CommandLine commandLine) { - commandLine.setOut(out).setErr(err); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/SelectorConverter.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/SelectorConverter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/SelectorConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/SelectorConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,19 +17,25 @@ import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectModule; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUri; +import java.net.URI; + import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.ResourceUtils; import org.junit.platform.engine.DiscoverySelectorIdentifier; import org.junit.platform.engine.discovery.ClassSelector; import org.junit.platform.engine.discovery.ClasspathResourceSelector; import org.junit.platform.engine.discovery.DirectorySelector; import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.engine.discovery.FilePosition; import org.junit.platform.engine.discovery.FileSelector; import org.junit.platform.engine.discovery.IterationSelector; import org.junit.platform.engine.discovery.MethodSelector; import org.junit.platform.engine.discovery.ModuleSelector; import org.junit.platform.engine.discovery.PackageSelector; +import org.junit.platform.engine.discovery.UniqueIdSelector; import org.junit.platform.engine.discovery.UriSelector; import picocli.CommandLine.ITypeConverter; @@ -53,7 +59,10 @@ static class File implements ITypeConverter { @Override public FileSelector convert(String value) { - return selectFile(value); + URI uri = URI.create(value); + String path = ResourceUtils.stripQueryComponent(uri).getPath(); + FilePosition filePosition = FilePosition.fromQuery(uri.getQuery()).orElse(null); + return selectFile(path, filePosition); } } @@ -88,12 +97,14 @@ static class ClasspathResource implements ITypeConverter { @Override public ClasspathResourceSelector convert(String value) { - return selectClasspathResource(value); + URI uri = URI.create(value); + String path = ResourceUtils.stripQueryComponent(uri).getPath(); + FilePosition filePosition = FilePosition.fromQuery(uri.getQuery()).orElse(null); + return selectClasspathResource(path, filePosition); } } static class Iteration implements ITypeConverter { - @Override public IterationSelector convert(String value) { DiscoverySelectorIdentifier identifier = DiscoverySelectorIdentifier.create( @@ -101,11 +112,16 @@ return (IterationSelector) DiscoverySelectors.parse(identifier) // .orElseThrow(() -> new PreconditionViolationException("Invalid format: Failed to parse selector")); } + } + static class UniqueId implements ITypeConverter { + @Override + public UniqueIdSelector convert(String value) { + return selectUniqueId(value); + } } static class Identifier implements ITypeConverter { - @Override public DiscoverySelectorIdentifier convert(String value) { return DiscoverySelectorIdentifier.parse(value); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptions.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,7 @@ import java.util.Locale; import org.apiguardian.api.API; +import org.junit.platform.console.output.Theme; /** * @since 1.10 @@ -24,7 +25,7 @@ public class TestConsoleOutputOptions { static final String DEFAULT_DETAILS_NAME = "tree"; - static final Details DEFAULT_DETAILS = Details.valueOf(DEFAULT_DETAILS_NAME.toUpperCase(Locale.ROOT)); + public static final Details DEFAULT_DETAILS = Details.valueOf(DEFAULT_DETAILS_NAME.toUpperCase(Locale.ROOT)); static final Theme DEFAULT_THEME = Theme.valueOf(ConsoleUtils.charset()); private boolean ansiColorOutputDisabled; @@ -32,6 +33,8 @@ private boolean isSingleColorPalette; private Details details = DEFAULT_DETAILS; private Theme theme = DEFAULT_THEME; + private Path stdoutPath; + private Path stderrPath; public boolean isAnsiColorOutputDisabled() { return this.ansiColorOutputDisabled; @@ -73,4 +76,24 @@ this.theme = theme; } + @API(status = INTERNAL, since = "1.13") + public Path getStdoutPath() { + return this.stdoutPath; + } + + @API(status = INTERNAL, since = "1.13") + public void setStdoutPath(Path stdoutPath) { + this.stdoutPath = stdoutPath; + } + + @API(status = INTERNAL, since = "1.13") + public Path getStderrPath() { + return this.stderrPath; + } + + @API(status = INTERNAL, since = "1.13") + public void setStderrPath(Path stderrPath) { + this.stderrPath = stderrPath; + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptionsMixin.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptionsMixin.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptionsMixin.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestConsoleOutputOptionsMixin.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,21 +10,26 @@ package org.junit.platform.console.options; +import static org.apiguardian.api.API.Status.INTERNAL; import static org.junit.platform.console.options.TestConsoleOutputOptions.DEFAULT_DETAILS; import static org.junit.platform.console.options.TestConsoleOutputOptions.DEFAULT_DETAILS_NAME; import static org.junit.platform.console.options.TestConsoleOutputOptions.DEFAULT_THEME; import java.nio.file.Path; +import org.apiguardian.api.API; +import org.junit.platform.console.output.Theme; + import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Option; -class TestConsoleOutputOptionsMixin { +@API(status = INTERNAL, since = "1.14") +public class TestConsoleOutputOptionsMixin { @ArgGroup(validate = false, order = 5, heading = "%n@|bold CONSOLE OUTPUT|@%n%n") ConsoleOutputOptions consoleOutputOptions = new ConsoleOutputOptions(); - static class ConsoleOutputOptions { + public static class ConsoleOutputOptions { @Option(names = "--color-palette", paramLabel = "FILE", description = "Specify a path to a properties file to customize ANSI style of output (not supported by all terminals).") private Path colorPalette; @@ -39,27 +44,35 @@ @Option(names = "--details", paramLabel = "MODE", defaultValue = DEFAULT_DETAILS_NAME, description = "Select an output details mode for when tests are executed. " // + "Use one of: ${COMPLETION-CANDIDATES}. If 'none' is selected, " // + "then only the summary and test failures are shown. Default: ${DEFAULT-VALUE}.") - private final Details details = DEFAULT_DETAILS; + private Details details = DEFAULT_DETAILS; @Option(names = "-details", hidden = true, defaultValue = DEFAULT_DETAILS_NAME) - private final Details details2 = DEFAULT_DETAILS; + private Details details2 = DEFAULT_DETAILS; @Option(names = "--details-theme", paramLabel = "THEME", description = "Select an output details tree theme for when tests are executed. " + "Use one of: ${COMPLETION-CANDIDATES}. Default is detected based on default character encoding.") - private final Theme theme = DEFAULT_THEME; + private Theme theme = DEFAULT_THEME; @Option(names = "-details-theme", hidden = true) - private final Theme theme2 = DEFAULT_THEME; + private Theme theme2 = DEFAULT_THEME; + + @Option(names = "--redirect-stdout", paramLabel = "FILE", description = "Redirect test output to stdout to a file.") + private Path stdout; + + @Option(names = "--redirect-stderr", paramLabel = "FILE", description = "Redirect test output to stderr to a file.") + private Path stderr; private void applyTo(TestConsoleOutputOptions result) { result.setColorPalettePath(choose(colorPalette, colorPalette2, null)); result.setSingleColorPalette(singleColorPalette || singleColorPalette2); result.setDetails(choose(details, details2, DEFAULT_DETAILS)); result.setTheme(choose(theme, theme2, DEFAULT_THEME)); + result.setStdoutPath(stdout); + result.setStderrPath(stderr); } } - TestConsoleOutputOptions toTestConsoleOutputOptions() { + public TestConsoleOutputOptions toTestConsoleOutputOptions() { TestConsoleOutputOptions result = new TestConsoleOutputOptions(); if (this.consoleOutputOptions != null) { this.consoleOutputOptions.applyTo(result); @@ -70,4 +83,5 @@ private static T choose(T left, T right, T defaultValue) { return left == right ? left : (left == defaultValue ? right : left); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -35,6 +35,7 @@ import org.junit.platform.engine.discovery.MethodSelector; import org.junit.platform.engine.discovery.ModuleSelector; import org.junit.platform.engine.discovery.PackageSelector; +import org.junit.platform.engine.discovery.UniqueIdSelector; import org.junit.platform.engine.discovery.UriSelector; /** @@ -58,12 +59,15 @@ private List selectedMethods = emptyList(); private List selectedClasspathResources = emptyList(); private List selectedIterations = emptyList(); + private List selectedUniqueIds = emptyList(); private List selectorIdentifiers = emptyList(); private List includedClassNamePatterns = singletonList(STANDARD_INCLUDE_PATTERN); private List excludedClassNamePatterns = emptyList(); private List includedPackages = emptyList(); private List excludedPackages = emptyList(); + private List includedMethodNamePatterns = emptyList(); + private List excludedMethodNamePatterns = emptyList(); private List includedEngines = emptyList(); private List excludedEngines = emptyList(); private List includedTagExpressions = emptyList(); @@ -180,6 +184,14 @@ this.selectedIterations = selectedIterations; } + public List getSelectedUniqueIds() { + return selectedUniqueIds; + } + + public void setSelectedUniqueId(List selectedUniqueIds) { + this.selectedUniqueIds = selectedUniqueIds; + } + public List getSelectorIdentifiers() { return selectorIdentifiers; } @@ -190,6 +202,7 @@ public List getExplicitSelectors() { List selectors = new ArrayList<>(); + selectors.addAll(getSelectedUniqueIds()); selectors.addAll(getSelectedUris()); selectors.addAll(getSelectedFiles()); selectors.addAll(getSelectedDirectories()); @@ -235,6 +248,22 @@ this.excludedPackages = excludedPackages; } + public List getIncludedMethodNamePatterns() { + return includedMethodNamePatterns; + } + + public void setIncludedMethodNamePatterns(List includedMethodNamePatterns) { + this.includedMethodNamePatterns = includedMethodNamePatterns; + } + + public List getExcludedMethodNamePatterns() { + return excludedMethodNamePatterns; + } + + public void setExcludedMethodNamePatterns(List excludedMethodNamePatterns) { + this.excludedMethodNamePatterns = excludedMethodNamePatterns; + } + public List getIncludedEngines() { return this.includedEngines; } @@ -283,4 +312,5 @@ this.configurationParametersResources = configurationParametersResources; return this; } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptionsMixin.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptionsMixin.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptionsMixin.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptionsMixin.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,8 @@ package org.junit.platform.console.options; +import static org.apiguardian.api.API.Status.INTERNAL; + import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -17,6 +19,7 @@ import java.util.List; import java.util.Map; +import org.apiguardian.api.API; import org.junit.platform.engine.DiscoverySelectorIdentifier; import org.junit.platform.engine.discovery.ClassNameFilter; import org.junit.platform.engine.discovery.ClassSelector; @@ -27,13 +30,15 @@ import org.junit.platform.engine.discovery.MethodSelector; import org.junit.platform.engine.discovery.ModuleSelector; import org.junit.platform.engine.discovery.PackageSelector; +import org.junit.platform.engine.discovery.UniqueIdSelector; import org.junit.platform.engine.discovery.UriSelector; import picocli.CommandLine; import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Option; -class TestDiscoveryOptionsMixin { +@API(status = INTERNAL, since = "1.14") +public class TestDiscoveryOptionsMixin { private static final String CP_OPTION = "cp"; @@ -41,14 +46,14 @@ SelectorOptions selectorOptions; @ArgGroup(validate = false, order = 3, heading = "%n For more information on selectors including syntax examples, see" - + "%n @|underline https://junit.org/junit5/docs/current/user-guide/#running-tests-discovery-selectors|@" + + "%n @|underline https://docs.junit.org/${junit.docs.version}/user-guide/#running-tests-discovery-selectors|@" + "%n%n@|bold FILTERS|@%n%n") FilterOptions filterOptions; @ArgGroup(validate = false, order = 4, heading = "%n@|bold RUNTIME CONFIGURATION|@%n%n") RuntimeConfigurationOptions runtimeConfigurationOptions; - static class SelectorOptions { + public static class SelectorOptions { @Option(names = { "--scan-classpath", "--scan-class-path" }, converter = ClasspathEntriesConverter.class, paramLabel = "PATH", arity = "0..1", description = "Scan all directories on the classpath or explicit classpath roots. " // @@ -69,82 +74,92 @@ private boolean scanModulepath2; @Option(names = { "-u", - "--select-uri" }, paramLabel = "URI", arity = "1", converter = SelectorConverter.Uri.class, description = "Select a URI for test discovery. This option can be repeated.") - private final List selectedUris = new ArrayList<>(); + "--select-uri" }, paramLabel = "URI", arity = "1..*", converter = SelectorConverter.Uri.class, description = "Select a URI for test discovery. This option can be repeated.") + private List selectedUris = new ArrayList<>(); - @Option(names = { "--u", "-select-uri" }, arity = "1", hidden = true, converter = SelectorConverter.Uri.class) - private final List selectedUris2 = new ArrayList<>(); + @Option(names = { "--u", + "-select-uri" }, arity = "1..*", hidden = true, converter = SelectorConverter.Uri.class) + private List selectedUris2 = new ArrayList<>(); @Option(names = { "-f", - "--select-file" }, paramLabel = "FILE", arity = "1", converter = SelectorConverter.File.class, description = "Select a file for test discovery. This option can be repeated.") - private final List selectedFiles = new ArrayList<>(); + "--select-file" }, paramLabel = "FILE", arity = "1..*", converter = SelectorConverter.File.class, // + description = "Select a file for test discovery. " + + "The line and column numbers can be provided as URI query parameters (e.g. foo.txt?line=12&column=34). " + + "This option can be repeated.") + private List selectedFiles = new ArrayList<>(); - @Option(names = { "--f", "-select-file" }, arity = "1", hidden = true, converter = SelectorConverter.File.class) - private final List selectedFiles2 = new ArrayList<>(); + @Option(names = { "--f", + "-select-file" }, arity = "1..*", hidden = true, converter = SelectorConverter.File.class) + private List selectedFiles2 = new ArrayList<>(); @Option(names = { "-d", - "--select-directory" }, paramLabel = "DIR", arity = "1", converter = SelectorConverter.Directory.class, description = "Select a directory for test discovery. This option can be repeated.") - private final List selectedDirectories = new ArrayList<>(); + "--select-directory" }, paramLabel = "DIR", arity = "1..*", converter = SelectorConverter.Directory.class, description = "Select a directory for test discovery. This option can be repeated.") + private List selectedDirectories = new ArrayList<>(); @Option(names = { "--d", - "-select-directory" }, arity = "1", hidden = true, converter = SelectorConverter.Directory.class) - private final List selectedDirectories2 = new ArrayList<>(); + "-select-directory" }, arity = "1..*", hidden = true, converter = SelectorConverter.Directory.class) + private List selectedDirectories2 = new ArrayList<>(); @Option(names = { "-o", - "--select-module" }, paramLabel = "NAME", arity = "1", converter = SelectorConverter.Module.class, description = "Select single module for test discovery. This option can be repeated.") - private final List selectedModules = new ArrayList<>(); + "--select-module" }, paramLabel = "NAME", arity = "1..*", converter = SelectorConverter.Module.class, description = "Select single module for test discovery. This option can be repeated.") + private List selectedModules = new ArrayList<>(); @Option(names = { "--o", - "-select-module" }, arity = "1", converter = SelectorConverter.Module.class, hidden = true) - private final List selectedModules2 = new ArrayList<>(); + "-select-module" }, arity = "1..*", converter = SelectorConverter.Module.class, hidden = true) + private List selectedModules2 = new ArrayList<>(); @Option(names = { "-p", - "--select-package" }, paramLabel = "PKG", arity = "1", converter = SelectorConverter.Package.class, description = "Select a package for test discovery. This option can be repeated.") - private final List selectedPackages = new ArrayList<>(); + "--select-package" }, paramLabel = "PKG", arity = "1..*", converter = SelectorConverter.Package.class, description = "Select a package for test discovery. This option can be repeated.") + private List selectedPackages = new ArrayList<>(); @Option(names = { "--p", - "-select-package" }, arity = "1", hidden = true, converter = SelectorConverter.Package.class) - private final List selectedPackages2 = new ArrayList<>(); + "-select-package" }, arity = "1..*", hidden = true, converter = SelectorConverter.Package.class) + private List selectedPackages2 = new ArrayList<>(); @Option(names = { "-c", - "--select-class" }, paramLabel = "CLASS", arity = "1", converter = SelectorConverter.Class.class, description = "Select a class for test discovery. This option can be repeated.") - private final List selectedClasses = new ArrayList<>(); + "--select-class" }, paramLabel = "CLASS", arity = "1..*", converter = SelectorConverter.Class.class, description = "Select a class for test discovery. This option can be repeated.") + private List selectedClasses = new ArrayList<>(); @Option(names = { "--c", - "-select-class" }, arity = "1", hidden = true, converter = SelectorConverter.Class.class) - private final List selectedClasses2 = new ArrayList<>(); + "-select-class" }, arity = "1..*", hidden = true, converter = SelectorConverter.Class.class) + private List selectedClasses2 = new ArrayList<>(); @Option(names = { "-m", - "--select-method" }, paramLabel = "NAME", arity = "1", converter = SelectorConverter.Method.class, description = "Select a method for test discovery. This option can be repeated.") - private final List selectedMethods = new ArrayList<>(); + "--select-method" }, paramLabel = "NAME", arity = "1..*", converter = SelectorConverter.Method.class, description = "Select a method for test discovery. This option can be repeated.") + private List selectedMethods = new ArrayList<>(); @Option(names = { "--m", - "-select-method" }, arity = "1", hidden = true, converter = SelectorConverter.Method.class) - private final List selectedMethods2 = new ArrayList<>(); + "-select-method" }, arity = "1..*", hidden = true, converter = SelectorConverter.Method.class) + private List selectedMethods2 = new ArrayList<>(); @Option(names = { "-r", - "--select-resource" }, paramLabel = "RESOURCE", arity = "1", converter = SelectorConverter.ClasspathResource.class, description = "Select a classpath resource for test discovery. This option can be repeated.") - private final List selectedClasspathResources = new ArrayList<>(); + "--select-resource" }, paramLabel = "RESOURCE", arity = "1..*", converter = SelectorConverter.ClasspathResource.class, description = "Select a classpath resource for test discovery. This option can be repeated.") + private List selectedClasspathResources = new ArrayList<>(); @Option(names = { "--r", - "-select-resource" }, arity = "1", hidden = true, converter = SelectorConverter.ClasspathResource.class) - private final List selectedClasspathResources2 = new ArrayList<>(); + "-select-resource" }, arity = "1..*", hidden = true, converter = SelectorConverter.ClasspathResource.class) + private List selectedClasspathResources2 = new ArrayList<>(); @Option(names = { "-i", - "--select-iteration" }, paramLabel = "PREFIX:VALUE[INDEX(..INDEX)?(,INDEX(..INDEX)?)*]", arity = "1", converter = SelectorConverter.Iteration.class, // + "--select-iteration" }, paramLabel = "PREFIX:VALUE[INDEX(..INDEX)?(,INDEX(..INDEX)?)*]", arity = "1..*", converter = SelectorConverter.Iteration.class, // description = "Select iterations for test discovery via a prefixed identifier and a list of indexes or index ranges " + "(e.g. method:com.acme.Foo#m()[1..2] selects the first and second iteration of the m() method in the com.acme.Foo class). " + "This option can be repeated.") - private final List selectedIterations = new ArrayList<>(); + private List selectedIterations = new ArrayList<>(); @Option(names = { "--i", - "-select-iteration" }, arity = "1", hidden = true, converter = SelectorConverter.Iteration.class) - private final List selectedIterations2 = new ArrayList<>(); + "-select-iteration" }, arity = "1..*", hidden = true, converter = SelectorConverter.Iteration.class) + private List selectedIterations2 = new ArrayList<>(); + + @Option(names = { "--select-unique-id", + "--uid" }, paramLabel = "UNIQUE-ID", arity = "1..*", converter = SelectorConverter.UniqueId.class, // + description = "Select a unique id for test discovery. This option can be repeated.") + private List selectedUniqueIds = new ArrayList<>(); - @Option(names = "--select", paramLabel = "PREFIX:VALUE", arity = "1", converter = SelectorConverter.Identifier.class, // + @Option(names = "--select", paramLabel = "PREFIX:VALUE", arity = "1..*", converter = SelectorConverter.Identifier.class, // description = "Select via a prefixed identifier (e.g. method:com.acme.Foo#m selects the m() method in the com.acme.Foo class). " + "This option can be repeated.") - private final List selectorIdentifiers = new ArrayList<>(); + private List selectorIdentifiers = new ArrayList<>(); SelectorOptions() { } @@ -163,11 +178,12 @@ result.setSelectedClasspathResources( merge(this.selectedClasspathResources, this.selectedClasspathResources2)); result.setSelectedIterations(merge(this.selectedIterations, this.selectedIterations2)); + result.setSelectedUniqueId(this.selectedUniqueIds); result.setSelectorIdentifiers(this.selectorIdentifiers); } } - static class FilterOptions { + public static class FilterOptions { @Option(names = { "-n", "--include-classname" }, paramLabel = "PATTERN", defaultValue = ClassNameFilter.STANDARD_INCLUDE_PATTERN, arity = "1", description = "Provide a regular expression to include only classes whose fully qualified names match. " // @@ -175,70 +191,82 @@ + "names that begin with \"Test\" or end with \"Test\" or \"Tests\". " // + "When this option is repeated, all patterns will be combined using OR semantics. " // + "Default: ${DEFAULT-VALUE}") - private final List includeClassNamePatterns = new ArrayList<>(); + private List includeClassNamePatterns = new ArrayList<>(); @Option(names = { "--n", "-include-classname" }, arity = "1", hidden = true) - private final List includeClassNamePatterns2 = new ArrayList<>(); + private List includeClassNamePatterns2 = new ArrayList<>(); @Option(names = { "-N", "--exclude-classname" }, paramLabel = "PATTERN", arity = "1", description = "Provide a regular expression to exclude those classes whose fully qualified names match. " // + "When this option is repeated, all patterns will be combined using OR semantics.") - private final List excludeClassNamePatterns = new ArrayList<>(); + private List excludeClassNamePatterns = new ArrayList<>(); @Option(names = { "--N", "-exclude-classname" }, arity = "1", hidden = true) - private final List excludeClassNamePatterns2 = new ArrayList<>(); + private List excludeClassNamePatterns2 = new ArrayList<>(); @Option(names = { "--include-package" }, paramLabel = "PKG", arity = "1", description = "Provide a package to be included in the test run. This option can be repeated.") - private final List includePackages = new ArrayList<>(); + private List includePackages = new ArrayList<>(); @Option(names = { "-include-package" }, arity = "1", hidden = true) - private final List includePackages2 = new ArrayList<>(); + private List includePackages2 = new ArrayList<>(); @Option(names = { "--exclude-package" }, paramLabel = "PKG", arity = "1", description = "Provide a package to be excluded from the test run. This option can be repeated.") - private final List excludePackages = new ArrayList<>(); + private List excludePackages = new ArrayList<>(); @Option(names = { "-exclude-package" }, arity = "1", hidden = true) - private final List excludePackages2 = new ArrayList<>(); + private List excludePackages2 = new ArrayList<>(); + + @Option(names = { + "--include-methodname" }, paramLabel = "PATTERN", arity = "1", description = "Provide a regular expression to include only methods whose fully qualified names without parameters match. " // + + "When this option is repeated, all patterns will be combined using OR semantics.") + private List includeMethodNamePatterns = new ArrayList<>(); + + @Option(names = { + "--exclude-methodname" }, paramLabel = "PATTERN", arity = "1", description = "Provide a regular expression to exclude those methods whose fully qualified names without parameters match. " // + + "When this option is repeated, all patterns will be combined using OR semantics.") + private List excludeMethodNamePatterns = new ArrayList<>(); @Option(names = { "-t", "--include-tag" }, paramLabel = "TAG", arity = "1", description = "Provide a tag or tag expression to include only tests whose tags match. " + // "When this option is repeated, all patterns will be combined using OR semantics.") - private final List includedTags = new ArrayList<>(); + private List includedTags = new ArrayList<>(); @Option(names = { "--t", "-include-tag" }, arity = "1", hidden = true) - private final List includedTags2 = new ArrayList<>(); + private List includedTags2 = new ArrayList<>(); @Option(names = { "-T", "--exclude-tag" }, paramLabel = "TAG", arity = "1", description = "Provide a tag or tag expression to exclude those tests whose tags match. " + // "When this option is repeated, all patterns will be combined using OR semantics.") - private final List excludedTags = new ArrayList<>(); + private List excludedTags = new ArrayList<>(); @Option(names = { "--T", "-exclude-tag" }, arity = "1", hidden = true) - private final List excludedTags2 = new ArrayList<>(); + private List excludedTags2 = new ArrayList<>(); @Option(names = { "-e", "--include-engine" }, paramLabel = "ID", arity = "1", description = "Provide the ID of an engine to be included in the test run. This option can be repeated.") - private final List includedEngines = new ArrayList<>(); + private List includedEngines = new ArrayList<>(); @Option(names = { "--e", "-include-engine" }, arity = "1", hidden = true) - private final List includedEngines2 = new ArrayList<>(); + private List includedEngines2 = new ArrayList<>(); @Option(names = { "-E", "--exclude-engine" }, paramLabel = "ID", arity = "1", description = "Provide the ID of an engine to be excluded from the test run. This option can be repeated.") - private final List excludedEngines = new ArrayList<>(); + private List excludedEngines = new ArrayList<>(); @Option(names = { "--E", "-exclude-engine" }, arity = "1", hidden = true) - private final List excludedEngines2 = new ArrayList<>(); + private List excludedEngines2 = new ArrayList<>(); private void applyTo(TestDiscoveryOptions result) { result.setIncludedClassNamePatterns(merge(this.includeClassNamePatterns, this.includeClassNamePatterns2)); result.setExcludedClassNamePatterns(merge(this.excludeClassNamePatterns, this.excludeClassNamePatterns2)); result.setIncludedPackages(merge(this.includePackages, this.includePackages2)); result.setExcludedPackages(merge(this.excludePackages, this.excludePackages2)); + result.setIncludedMethodNamePatterns(new ArrayList<>(this.includeMethodNamePatterns)); + result.setExcludedMethodNamePatterns(new ArrayList<>(this.excludeMethodNamePatterns)); result.setIncludedTagExpressions(merge(this.includedTags, this.includedTags2)); result.setExcludedTagExpressions(merge(this.excludedTags, this.excludedTags2)); result.setIncludedEngines(merge(this.includedEngines, this.includedEngines2)); @@ -246,19 +274,19 @@ } } - static class RuntimeConfigurationOptions { + public static class RuntimeConfigurationOptions { @Option(names = { "-" + CP_OPTION, "--classpath", "--class-path" }, converter = ClasspathEntriesConverter.class, paramLabel = "PATH", arity = "1", description = "Provide additional classpath entries " + "-- for example, for adding engines and their dependencies. This option can be repeated.") - private final List additionalClasspathEntries = new ArrayList<>(); + private List additionalClasspathEntries = new ArrayList<>(); @Option(names = { "--cp", "-classpath", "-class-path" }, converter = ClasspathEntriesConverter.class, hidden = true) - private final List additionalClasspathEntries2 = new ArrayList<>(); + private List additionalClasspathEntries2 = new ArrayList<>(); // Implementation note: the @Option annotation is on a setter method to allow validation. - private final Map configurationParameters = new LinkedHashMap<>(); + private Map configurationParameters = new LinkedHashMap<>(); @Option(names = { "--config-resource" }, paramLabel = "PATH", arity = "1", description = "Set configuration parameters for test discovery and execution via a classpath resource. This option can be repeated.") @@ -279,7 +307,7 @@ * * @param map the key-value pairs to add * @throws CommandLine.ParameterException if the map already contains this key - * @see #1308 + * @see #1308 */ @Option(names = "--config", paramLabel = "KEY=VALUE", arity = "1", description = "Set a configuration parameter for test discovery and execution. This option can be repeated.") public void setConfigurationParameters(Map map) { @@ -305,7 +333,7 @@ } } - TestDiscoveryOptions toTestDiscoveryOptions() { + public TestDiscoveryOptions toTestDiscoveryOptions() { TestDiscoveryOptions result = new TestDiscoveryOptions(); if (this.selectorOptions != null) { this.selectorOptions.applyTo(result); @@ -324,4 +352,5 @@ result.addAll(list2 == null ? Collections.emptyList() : list2); return result; } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Theme.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Theme.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Theme.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/Theme.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import org.apiguardian.api.API; -import org.junit.platform.engine.TestExecutionResult; - -/** - * @since 1.0 - */ -@API(status = INTERNAL, since = "1.0") -public enum Theme { - - /** - * ASCII 7-bit characters form the tree branch. - * - *

    Example test plan execution tree: - *

    -	 * +-- engine alpha
    -	 * | '-- container BEGIN
    -	 * |   +-- test 00 [OK]
    -	 * |   '-- test 01 [OK]
    -	 * '-- engine omega
    -	 *   +-- container END
    -	 *   | +-- test 10 [OK]
    -	 *   | '-- test 11 [A] aborted
    -	 *   '-- container FINAL
    -	 *     +-- skipped [S] because
    -	 *     '-- failing [X] BäMM
    -	 * 
    - */ - ASCII(".", "| ", "+--", "'--", "[OK]", "[A]", "[X]", "[S]"), - - /** - * Unicode (extended ASCII) characters are used to display the test execution tree. - * - *

    Example test plan execution tree: - *

    -	 * ├─ engine alpha ✔
    -	 * │  └─ container BEGIN ✔
    -	 * │     ├─ test 00 ✔
    -	 * │     └─ test 01 ✔
    -	 * └─ engine omega ✔
    -	 *    ├─ container END ✔
    -	 *    │  ├─ test 10 ✔
    -	 *    │  └─ test 11 ■ aborted
    -	 *    └─ container FINAL ✔
    -	 *       ├─ skipped ↷ because
    -	 *       └─ failing ✘ BäMM
    -	 * 
    - */ - UNICODE("╷", "│ ", "├─", "└─", "✔", "■", "✘", "↷"); - - public static Theme valueOf(Charset charset) { - if (StandardCharsets.UTF_8.equals(charset)) { - return UNICODE; - } - return ASCII; - } - - private final String[] tiles; - private final String blank; - - Theme(String... tiles) { - this.tiles = tiles; - this.blank = new String(new char[vertical().length()]).replace('\0', ' '); - } - - public final String root() { - return tiles[0]; - } - - public final String vertical() { - return tiles[1]; - } - - public final String blank() { - return blank; - } - - public final String entry() { - return tiles[2]; - } - - public final String end() { - return tiles[3]; - } - - public final String successful() { - return tiles[4]; - } - - public final String aborted() { - return tiles[5]; - } - - public final String failed() { - return tiles[6]; - } - - public final String skipped() { - return tiles[7]; - } - - public final String status(TestExecutionResult result) { - switch (result.getStatus()) { - case SUCCESSFUL: - return successful(); - case ABORTED: - return aborted(); - case FAILED: - return failed(); - default: - return result.getStatus().name(); - } - } - - /** - * Return lower case {@link #name()} for easier usage in help text for - * available options. - */ - @Override - public final String toString() { - return name().toLowerCase(); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/package-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/options/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /** - * Configuration options for JUnit's console launcher. + * Command-line option utility classes of JUnit's console launcher. */ package org.junit.platform.console.options; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/ColorPalette.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/ColorPalette.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/ColorPalette.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/ColorPalette.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; +import java.util.Properties; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apiguardian.api.API; + +/** + * @since 1.9 + */ +@API(status = INTERNAL, since = "1.14") +public class ColorPalette { + + public static final ColorPalette SINGLE_COLOR = new ColorPalette(singleColorPalette(), false); + public static final ColorPalette DEFAULT = new ColorPalette(defaultPalette(), false); + public static final ColorPalette NONE = new ColorPalette(new EnumMap<>(Style.class), true); + + private final Map colorsToAnsiSequences; + private final boolean disableAnsiColors; + + // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters + private static Map defaultPalette() { + Map colorsToAnsiSequences = new EnumMap<>(Style.class); + colorsToAnsiSequences.put(Style.NONE, "0"); + colorsToAnsiSequences.put(Style.SUCCESSFUL, "32"); + colorsToAnsiSequences.put(Style.ABORTED, "33"); + colorsToAnsiSequences.put(Style.FAILED, "31"); + colorsToAnsiSequences.put(Style.SKIPPED, "35"); + colorsToAnsiSequences.put(Style.CONTAINER, "36"); + colorsToAnsiSequences.put(Style.TEST, "34"); + colorsToAnsiSequences.put(Style.DYNAMIC, "35"); + colorsToAnsiSequences.put(Style.REPORTED, "37"); + return colorsToAnsiSequences; + } + + private static Map singleColorPalette() { + Map colorsToAnsiSequences = new EnumMap<>(Style.class); + colorsToAnsiSequences.put(Style.NONE, "0"); + colorsToAnsiSequences.put(Style.SUCCESSFUL, "1"); + colorsToAnsiSequences.put(Style.ABORTED, "4"); + colorsToAnsiSequences.put(Style.FAILED, "7"); + colorsToAnsiSequences.put(Style.SKIPPED, "9"); + colorsToAnsiSequences.put(Style.CONTAINER, "1"); + colorsToAnsiSequences.put(Style.TEST, "0"); + colorsToAnsiSequences.put(Style.DYNAMIC, "0"); + colorsToAnsiSequences.put(Style.REPORTED, "2"); + return colorsToAnsiSequences; + } + + public ColorPalette(Map overrides) { + this(defaultPalette(), false); + + if (overrides.containsKey(Style.NONE)) { + throw new IllegalArgumentException("Cannot override the standard style 'NONE'"); + } + this.colorsToAnsiSequences.putAll(overrides); + } + + public ColorPalette(Properties properties) { + this(toOverrideMap(properties)); + } + + public ColorPalette(Reader reader) { + this(getProperties(reader)); + } + + public ColorPalette(Path path) { + this(getProperties(path)); + } + + private ColorPalette(Map colorsToAnsiSequences, boolean disableAnsiColors) { + this.colorsToAnsiSequences = colorsToAnsiSequences; + this.disableAnsiColors = disableAnsiColors; + } + + private static Map toOverrideMap(Properties properties) { + Map upperCaseProperties = properties.entrySet().stream().collect( + Collectors.toMap(entry -> ((String) entry.getKey()).toUpperCase(), entry -> (String) entry.getValue())); + + return Arrays.stream(Style.values()).filter(style -> upperCaseProperties.containsKey(style.name())).collect( + Collectors.toMap(Function.identity(), style -> upperCaseProperties.get(style.name()))); + } + + private static Properties getProperties(Reader reader) { + Properties properties = new Properties(); + try { + properties.load(reader); + } + catch (IOException e) { + throw new IllegalArgumentException("Could not read color palette properties", e); + } + return properties; + } + + private static Properties getProperties(Path path) { + try (FileReader fileReader = new FileReader(path.toFile())) { + return getProperties(fileReader); + } + catch (IOException e) { + throw new IllegalArgumentException("Could not open color palette properties file", e); + } + } + + public String paint(Style style, String text) { + return this.disableAnsiColors || style == Style.NONE ? text + : getAnsiFormatter(style) + text + getAnsiFormatter(Style.NONE); + } + + private String getAnsiFormatter(Style style) { + return String.format("\u001B[%sm", this.colorsToAnsiSequences.get(style)); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/DetailsPrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/DetailsPrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/DetailsPrintingListener.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/DetailsPrintingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.regex.Pattern; + +import org.apiguardian.api.API; +import org.junit.platform.launcher.TestExecutionListener; +import org.junit.platform.launcher.TestPlan; + +/** + * @since 1.0 + */ +@API(status = INTERNAL, since = "1.14") +public interface DetailsPrintingListener extends TestExecutionListener { + + Pattern LINE_START_PATTERN = Pattern.compile("(?m)^"); + + void listTests(TestPlan testPlan); + + static String indented(String message, String indentation) { + return LINE_START_PATTERN.matcher(message).replaceAll(indentation).trim(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/FlatPrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/FlatPrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/FlatPrintingListener.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/FlatPrintingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,126 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.io.PrintWriter; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.ExceptionUtils; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +/** + * @since 1.0 + */ +@API(status = INTERNAL, since = "1.14") +public class FlatPrintingListener implements DetailsPrintingListener { + + static final String INDENTATION = " "; + + private final PrintWriter out; + private final ColorPalette colorPalette; + + public FlatPrintingListener(PrintWriter out, ColorPalette colorPalette) { + this.out = out; + this.colorPalette = colorPalette; + } + + @Override + public void testPlanExecutionStarted(TestPlan testPlan) { + this.out.printf("Test execution started. Number of static tests: %d%n", + testPlan.countTestIdentifiers(TestIdentifier::isTest)); + } + + @Override + public void testPlanExecutionFinished(TestPlan testPlan) { + this.out.println("Test execution finished."); + } + + @Override + public void dynamicTestRegistered(TestIdentifier testIdentifier) { + printlnTestDescriptor(Style.DYNAMIC, "Registered:", testIdentifier); + } + + @Override + public void executionSkipped(TestIdentifier testIdentifier, String reason) { + printlnTestDescriptor(Style.SKIPPED, "Skipped:", testIdentifier); + printlnMessage(Style.SKIPPED, "Reason", reason); + } + + @Override + public void executionStarted(TestIdentifier testIdentifier) { + printlnTestDescriptor(Style.valueOf(testIdentifier), "Started:", testIdentifier); + } + + @Override + public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { + Style style = Style.valueOf(testExecutionResult); + printlnTestDescriptor(style, "Finished:", testIdentifier); + testExecutionResult.getThrowable().ifPresent(t -> printlnException(style, t)); + } + + @Override + public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry entry) { + printlnTestDescriptor(Style.REPORTED, "Reported:", testIdentifier); + printlnMessage(Style.REPORTED, "Reported values", entry.toString()); + } + + @Override + public void fileEntryPublished(TestIdentifier testIdentifier, FileEntry file) { + printlnTestDescriptor(Style.REPORTED, "Reported:", testIdentifier); + printlnMessage(Style.REPORTED, "Reported file", file.toString()); + } + + private void printlnTestDescriptor(Style style, String message, TestIdentifier testIdentifier) { + println(style, "%-10s %s (%s)", message, testIdentifier.getDisplayName(), testIdentifier.getUniqueId()); + } + + private void printlnException(Style style, Throwable throwable) { + printlnMessage(style, "Exception", ExceptionUtils.readStackTrace(throwable)); + } + + private void printlnMessage(Style style, String message, String detail) { + println(style, INDENTATION + "=> " + message + ": %s", indented(detail)); + } + + private void println(Style style, String format, Object... args) { + this.out.println(colorPalette.paint(style, String.format(format, args))); + } + + /** + * Indent the given message if it is a multi-line string. + * + *

    {@link #INDENTATION} is used to prefix the start of each new line + * except the first one. + * + * @param message the message to indent + * @return indented message + */ + private static String indented(String message) { + return DetailsPrintingListener.indented(message, INDENTATION); + } + + @Override + public void listTests(TestPlan testPlan) { + testPlan.accept(new TestPlan.Visitor() { + @Override + public void visit(TestIdentifier testIdentifier) { + println(Style.valueOf(testIdentifier), "%s (%s)", testIdentifier.getDisplayName(), + testIdentifier.getUniqueId()); + } + }); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Style.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Style.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Style.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Style.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.launcher.TestIdentifier; + +/** + * @since 1.9 + */ +enum Style { + + NONE, SUCCESSFUL, ABORTED, FAILED, SKIPPED, CONTAINER, TEST, DYNAMIC, REPORTED; + + static Style valueOf(TestExecutionResult result) { + switch (result.getStatus()) { + case SUCCESSFUL: + return Style.SUCCESSFUL; + case ABORTED: + return Style.ABORTED; + case FAILED: + return Style.FAILED; + default: + return Style.NONE; + } + } + + static Style valueOf(TestIdentifier testIdentifier) { + return testIdentifier.isContainer() ? CONTAINER : TEST; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TestFeedPrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TestFeedPrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TestFeedPrintingListener.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TestFeedPrintingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.engine.TestExecutionResult.Status.SUCCESSFUL; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.ExceptionUtils; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +@API(status = INTERNAL, since = "1.14") +public class TestFeedPrintingListener implements DetailsPrintingListener { + + private static final String INDENTATION = "\t"; + private static final String STATUS_SEPARATOR = " :: "; + + private final PrintWriter out; + private final ColorPalette colorPalette; + private TestPlan testPlan; + + public TestFeedPrintingListener(PrintWriter out, ColorPalette colorPalette) { + this.out = out; + this.colorPalette = colorPalette; + } + + @Override + public void testPlanExecutionStarted(TestPlan testPlan) { + this.testPlan = testPlan; + } + + @Override + public void testPlanExecutionFinished(TestPlan testPlan) { + this.testPlan = null; + } + + @Override + public void executionSkipped(TestIdentifier testIdentifier, String reason) { + if (shouldPrint(testIdentifier)) { + String msg = formatTestIdentifier(testIdentifier); + String indentedReason = indented(String.format("Reason: %s", reason)); + println(Style.SKIPPED, + String.format("%s" + STATUS_SEPARATOR + "SKIPPED%n" + INDENTATION + "%s", msg, indentedReason)); + } + } + + @Override + public void executionStarted(TestIdentifier testIdentifier) { + if (shouldPrint(testIdentifier)) { + String msg = formatTestIdentifier(testIdentifier); + println(Style.NONE, String.format("%s" + STATUS_SEPARATOR + "STARTED", msg)); + } + } + + @Override + public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { + TestExecutionResult.Status status = testExecutionResult.getStatus(); + if (testExecutionResult.getThrowable().isPresent()) { + Style style = Style.valueOf(testExecutionResult); + String msg = formatTestIdentifier(testIdentifier); + Throwable throwable = testExecutionResult.getThrowable().get(); + String stacktrace = indented(ExceptionUtils.readStackTrace(throwable)); + println(style, + String.format("%s" + STATUS_SEPARATOR + "%s%n" + INDENTATION + "%s", msg, status, stacktrace)); + } + else if (shouldPrint(testIdentifier) || testExecutionResult.getStatus() != SUCCESSFUL) { + Style style = Style.valueOf(testExecutionResult); + String msg = formatTestIdentifier(testIdentifier); + println(style, String.format("%s" + STATUS_SEPARATOR + "%s", msg, status)); + } + } + + private String formatTestIdentifier(TestIdentifier testIdentifier) { + return String.join(" > ", collectDisplayNames(testIdentifier.getUniqueIdObject())); + } + + private void println(Style style, String message) { + this.out.println(colorPalette.paint(style, message)); + } + + private List collectDisplayNames(UniqueId uniqueId) { + int size = uniqueId.getSegments().size(); + List displayNames = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + displayNames.add(0, testPlan.getTestIdentifier(uniqueId).getDisplayName()); + if (i < size - 1) { + uniqueId = uniqueId.removeLastSegment(); + } + } + return displayNames; + } + + private static String indented(String message) { + return DetailsPrintingListener.indented(message, INDENTATION); + } + + @Override + public void listTests(TestPlan testPlan) { + this.testPlan = testPlan; + try { + testPlan.accept(new TestPlan.Visitor() { + @Override + public void visit(TestIdentifier testIdentifier) { + if (shouldPrint(testIdentifier)) { + println(Style.NONE, formatTestIdentifier(testIdentifier)); + } + } + }); + } + finally { + this.testPlan = null; + } + } + + private static boolean shouldPrint(TestIdentifier testIdentifier) { + return testIdentifier.isTest(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Theme.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Theme.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Theme.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/Theme.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import org.apiguardian.api.API; +import org.junit.platform.engine.TestExecutionResult; + +/** + * @since 1.0 + */ +@API(status = INTERNAL, since = "1.0") +public enum Theme { + + /** + * ASCII 7-bit characters form the tree branch. + * + *

    Example test plan execution tree: + *

    +	 * +-- engine alpha
    +	 * | '-- container BEGIN
    +	 * |   +-- test 00 [OK]
    +	 * |   '-- test 01 [OK]
    +	 * '-- engine omega
    +	 *   +-- container END
    +	 *   | +-- test 10 [OK]
    +	 *   | '-- test 11 [A] aborted
    +	 *   '-- container FINAL
    +	 *     +-- skipped [S] because
    +	 *     '-- failing [X] BäMM
    +	 * 
    + */ + ASCII(".", "| ", "+--", "'--", "[OK]", "[A]", "[X]", "[S]"), + + /** + * Unicode (extended ASCII) characters are used to display the test execution tree. + * + *

    Example test plan execution tree: + *

    +	 * ├─ engine alpha ✔
    +	 * │  └─ container BEGIN ✔
    +	 * │     ├─ test 00 ✔
    +	 * │     └─ test 01 ✔
    +	 * └─ engine omega ✔
    +	 *    ├─ container END ✔
    +	 *    │  ├─ test 10 ✔
    +	 *    │  └─ test 11 ■ aborted
    +	 *    └─ container FINAL ✔
    +	 *       ├─ skipped ↷ because
    +	 *       └─ failing ✘ BäMM
    +	 * 
    + */ + UNICODE("╷", "│ ", "├─", "└─", "✔", "■", "✘", "↷"); + + public static Theme valueOf(Charset charset) { + if (StandardCharsets.UTF_8.equals(charset)) { + return UNICODE; + } + return ASCII; + } + + private final String[] tiles; + private final String blank; + + Theme(String... tiles) { + this.tiles = tiles; + this.blank = new String(new char[vertical().length()]).replace('\0', ' '); + } + + public final String root() { + return tiles[0]; + } + + public final String vertical() { + return tiles[1]; + } + + public final String blank() { + return blank; + } + + public final String entry() { + return tiles[2]; + } + + public final String end() { + return tiles[3]; + } + + public final String successful() { + return tiles[4]; + } + + public final String aborted() { + return tiles[5]; + } + + public final String failed() { + return tiles[6]; + } + + public final String skipped() { + return tiles[7]; + } + + public final String status(TestExecutionResult result) { + switch (result.getStatus()) { + case SUCCESSFUL: + return successful(); + case ABORTED: + return aborted(); + case FAILED: + return failed(); + default: + return result.getStatus().name(); + } + } + + /** + * Return lower case {@link #name()} for easier usage in help text for + * available options. + */ + @Override + public final String toString() { + return name().toLowerCase(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreeNode.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreeNode.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreeNode.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreeNode.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import java.util.Optional; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.junit.platform.commons.util.StringUtils; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.launcher.TestIdentifier; + +/** + * @since 1.0 + */ +class TreeNode { + + private final String caption; + private final long creation; + long duration; + private String reason; + private TestIdentifier identifier; + private TestExecutionResult result; + final Queue reports = new ConcurrentLinkedQueue<>(); + final Queue files = new ConcurrentLinkedQueue<>(); + final Queue children = new ConcurrentLinkedQueue<>(); + boolean visible; + + TreeNode(String caption) { + this.caption = caption; + this.creation = System.currentTimeMillis(); + this.visible = false; + } + + TreeNode(TestIdentifier identifier) { + this(createCaption(identifier.getDisplayName())); + this.identifier = identifier; + this.visible = true; + } + + TreeNode(TestIdentifier identifier, String reason) { + this(identifier); + this.reason = reason; + } + + TreeNode addChild(TreeNode node) { + children.add(node); + return this; + } + + TreeNode addReportEntry(ReportEntry reportEntry) { + reports.add(reportEntry); + return this; + } + + TreeNode addFileEntry(FileEntry file) { + files.add(file); + return this; + } + + TreeNode setResult(TestExecutionResult result) { + this.result = result; + this.duration = System.currentTimeMillis() - creation; + return this; + } + + public String caption() { + return caption; + } + + Optional reason() { + return Optional.ofNullable(reason); + } + + Optional result() { + return Optional.ofNullable(result); + } + + Optional identifier() { + return Optional.ofNullable(identifier); + } + + static String createCaption(String displayName) { + boolean normal = displayName.length() <= 80; + String caption = normal ? displayName : displayName.substring(0, 80) + "..."; + String whites = StringUtils.replaceWhitespaceCharacters(caption, " "); + return StringUtils.replaceIsoControlCharacters(whites, "."); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrinter.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrinter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrinter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrinter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,184 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; + +import java.io.PrintWriter; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.junit.platform.commons.util.StringUtils; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.TestExecutionResult.Status; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; + +/** + * @since 1.0 + */ +class TreePrinter { + + private final PrintWriter out; + private final Theme theme; + private final ColorPalette colorPalette; + + TreePrinter(PrintWriter out, Theme theme, ColorPalette colorPalette) { + this.out = out; + this.theme = theme; + this.colorPalette = colorPalette; + } + + void print(TreeNode node) { + out.println(color(Style.CONTAINER, theme.root())); + print(node, "", true); + out.flush(); + } + + private void print(TreeNode node, String indent, boolean continuous) { + if (node.visible) { + printVisible(node, indent, continuous); + } + if (node.children.isEmpty()) { + return; + } + if (node.visible) { + indent += continuous ? theme.vertical() : theme.blank(); + } + Iterator iterator = node.children.iterator(); + while (iterator.hasNext()) { + print(iterator.next(), indent, iterator.hasNext()); + } + } + + private void printVisible(TreeNode node, String indent, boolean continuous) { + String bullet = continuous ? theme.entry() : theme.end(); + String prefix = color(Style.CONTAINER, indent + bullet); + String tabbed = color(Style.CONTAINER, indent + tab(node, continuous)); + String caption = colorCaption(node); + String duration = color(Style.CONTAINER, node.duration + " ms"); + String icon = color(Style.SKIPPED, theme.skipped()); + if (node.result().isPresent()) { + TestExecutionResult result = node.result().get(); + Style resultStyle = Style.valueOf(result); + icon = color(resultStyle, theme.status(result)); + } + out.print(prefix); + out.print(" "); + out.print(caption); + if (node.duration > 10000 && node.children.isEmpty()) { + out.print(" "); + out.print(duration); + } + boolean nodeIsBeingListed = node.duration == 0 && !node.result().isPresent() && !node.reason().isPresent(); + if (!nodeIsBeingListed) { + out.print(" "); + out.print(icon); + } + node.result().ifPresent(result -> printThrowable(tabbed, result)); + node.reason().ifPresent(reason -> printMessage(Style.SKIPPED, tabbed, reason)); + node.reports.forEach(e -> printReportEntry(tabbed, e)); + out.println(); + node.files.forEach(e -> printFileEntry(tabbed, e)); + } + + private String tab(TreeNode node, boolean continuous) { + // We might be the "last" node in this level, that means + // `continuous == false`, but still need to include a vertical + // bar for printing stack traces, messages and reports. + // See https://github.com/junit-team/junit-framework/issues/1531 + if (node.children.size() > 0) { + return theme.blank() + theme.vertical(); + } + return (continuous ? theme.vertical() : theme.blank()) + theme.blank(); + } + + private String colorCaption(TreeNode node) { + String caption = node.caption(); + if (node.result().isPresent()) { + TestExecutionResult result = node.result().get(); + Style resultStyle = Style.valueOf(result); + if (result.getStatus() != Status.SUCCESSFUL) { + return color(resultStyle, caption); + } + } + if (node.reason().isPresent()) { + return color(Style.SKIPPED, caption); + } + Style style = node.identifier().map(Style::valueOf).orElse(Style.NONE); + return color(style, caption); + } + + private void printThrowable(String indent, TestExecutionResult result) { + if (!result.getThrowable().isPresent()) { + return; + } + Throwable throwable = result.getThrowable().get(); + String message = throwable.getMessage(); + if (StringUtils.isBlank(message)) { + message = throwable.toString(); + } + printMessage(Style.FAILED, indent, message); + } + + private void printReportEntry(String indent, ReportEntry reportEntry) { + out.println(); + out.print(indent); + out.print(reportEntry.getTimestamp()); + Set> entries = reportEntry.getKeyValuePairs().entrySet(); + if (entries.size() == 1) { + printReportEntry(" ", getOnlyElement(entries)); + return; + } + for (Map.Entry entry : entries) { + out.println(); + printReportEntry(indent + theme.blank(), entry); + } + } + + private void printReportEntry(String indent, Map.Entry mapEntry) { + out.print(indent); + out.print(color(Style.ABORTED, mapEntry.getKey())); + out.print(" = `"); + out.print(color(Style.SUCCESSFUL, mapEntry.getValue())); + out.print("`"); + } + + private void printFileEntry(String indent, FileEntry fileEntry) { + out.print(indent); + out.print(fileEntry.getTimestamp()); + out.print(" "); + out.print(color(Style.SUCCESSFUL, fileEntry.getPath().toUri().toString())); + out.println(); + } + + private void printMessage(Style style, String indent, String message) { + String[] lines = message.split("\\R"); + out.print(" "); + out.print(color(style, lines[0])); + if (lines.length > 1) { + for (int i = 1; i < lines.length; i++) { + out.println(); + out.print(indent); + if (StringUtils.isNotBlank(lines[i])) { + String extra = theme.blank(); + out.print(color(style, extra + lines[i])); + } + } + } + } + + private String color(Style style, String text) { + return colorPalette.paint(style, text); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrintingListener.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/TreePrintingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.io.PrintWriter; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apiguardian.api.API; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +/** + * @since 1.0 + */ +@API(status = INTERNAL, since = "1.14") +public class TreePrintingListener implements DetailsPrintingListener { + + private final Map nodesByUniqueId = new ConcurrentHashMap<>(); + private TreeNode root; + private final TreePrinter treePrinter; + + public TreePrintingListener(PrintWriter out, ColorPalette colorPalette, Theme theme) { + this.treePrinter = new TreePrinter(out, theme, colorPalette); + } + + private void addNode(TestIdentifier testIdentifier, TreeNode node) { + nodesByUniqueId.put(testIdentifier.getUniqueIdObject(), node); + testIdentifier.getParentIdObject().map(nodesByUniqueId::get).orElse(root).addChild(node); + } + + private TreeNode getNode(TestIdentifier testIdentifier) { + return nodesByUniqueId.get(testIdentifier.getUniqueIdObject()); + } + + @Override + public void testPlanExecutionStarted(TestPlan testPlan) { + root = new TreeNode(testPlan.toString()); + } + + @Override + public void testPlanExecutionFinished(TestPlan testPlan) { + treePrinter.print(root); + } + + @Override + public void executionStarted(TestIdentifier testIdentifier) { + addNode(testIdentifier, new TreeNode(testIdentifier)); + } + + @Override + public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { + getNode(testIdentifier).setResult(testExecutionResult); + } + + @Override + public void executionSkipped(TestIdentifier testIdentifier, String reason) { + addNode(testIdentifier, new TreeNode(testIdentifier, reason)); + } + + @Override + public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry entry) { + getNode(testIdentifier).addReportEntry(entry); + } + + @Override + public void fileEntryPublished(TestIdentifier testIdentifier, FileEntry file) { + getNode(testIdentifier).addFileEntry(file); + } + + @Override + public void listTests(TestPlan testPlan) { + root = new TreeNode(testPlan.toString()); + testPlan.accept(new TestPlan.Visitor() { + @Override + public void visit(TestIdentifier testIdentifier) { + addNode(testIdentifier, new TreeNode(testIdentifier)); + } + }); + treePrinter.print(root); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/VerboseTreePrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/VerboseTreePrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/VerboseTreePrintingListener.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/VerboseTreePrintingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,234 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.util.ExceptionUtils.readStackTrace; +import static org.junit.platform.console.output.Style.NONE; + +import java.io.PrintWriter; +import java.util.ArrayDeque; +import java.util.Deque; + +import org.apiguardian.api.API; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +/** + * @since 1.0 + */ +@API(status = INTERNAL, since = "1.14") +public class VerboseTreePrintingListener implements DetailsPrintingListener { + + private final PrintWriter out; + private final Theme theme; + private final ColorPalette colorPalette; + private final Deque frames; + private final String[] verticals; + private long executionStartedMillis; + + public VerboseTreePrintingListener(PrintWriter out, ColorPalette colorPalette, int maxContainerNestingLevel, + Theme theme) { + this.out = out; + this.colorPalette = colorPalette; + this.theme = theme; + + // create frame stack and push initial root frame + this.frames = new ArrayDeque<>(); + this.frames.push(0L); + + // create and populate vertical indentation lookup table + this.verticals = new String[Math.max(10, maxContainerNestingLevel) + 1]; + this.verticals[0] = ""; // no frame + this.verticals[1] = ""; // synthetic root "/" level + this.verticals[2] = ""; // "engine" level + + for (int i = 3; i < verticals.length; i++) { + verticals[i] = verticals[i - 1] + theme.vertical(); + } + } + + @Override + public void testPlanExecutionStarted(TestPlan testPlan) { + frames.push(System.currentTimeMillis()); + + String prefix = "Test plan execution started. Number of static tests: "; + printNumberOfTests(testPlan, prefix); + printf(Style.CONTAINER, "%s%n", theme.root()); + } + + @Override + public void testPlanExecutionFinished(TestPlan testPlan) { + frames.pop(); + + printNumberOfTests(testPlan, "Test plan execution finished. Number of all tests: "); + } + + private void printNumberOfTests(TestPlan testPlan, String prefix) { + long tests = testPlan.countTestIdentifiers(TestIdentifier::isTest); + printf(NONE, "%s", prefix); + printf(Style.TEST, "%d%n", tests); + } + + @Override + public void executionStarted(TestIdentifier testIdentifier) { + this.executionStartedMillis = System.currentTimeMillis(); + if (testIdentifier.isContainer()) { + printVerticals(theme.entry()); + printf(Style.CONTAINER, " %s", testIdentifier.getDisplayName()); + printf(NONE, "%n"); + frames.push(System.currentTimeMillis()); + } + if (testIdentifier.isContainer()) { + return; + } + printVerticals(theme.entry()); + printf(Style.valueOf(testIdentifier), " %s%n", testIdentifier.getDisplayName()); + printDetails(testIdentifier); + } + + @Override + public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { + testExecutionResult.getThrowable().ifPresent(t -> printDetail(Style.FAILED, "caught", readStackTrace(t))); + if (testIdentifier.isContainer()) { + Long creationMillis = frames.pop(); + printVerticals(theme.end()); + printf(Style.CONTAINER, " %s", testIdentifier.getDisplayName()); + printf(NONE, " finished after %d ms.%n", System.currentTimeMillis() - creationMillis); + return; + } + printDetail(NONE, "duration", "%d ms%n", System.currentTimeMillis() - executionStartedMillis); + String status = theme.status(testExecutionResult) + " " + testExecutionResult.getStatus(); + printDetail(Style.valueOf(testExecutionResult), "status", "%s%n", status); + } + + @Override + public void executionSkipped(TestIdentifier testIdentifier, String reason) { + printVerticals(theme.entry()); + printf(Style.valueOf(testIdentifier), " %s%n", testIdentifier.getDisplayName()); + printDetails(testIdentifier); + printDetail(Style.SKIPPED, "reason", reason); + printDetail(Style.SKIPPED, "status", theme.skipped() + " SKIPPED"); + } + + @Override + public void dynamicTestRegistered(TestIdentifier testIdentifier) { + printVerticals(theme.entry()); + printf(Style.DYNAMIC, " %s", testIdentifier.getDisplayName()); + printf(NONE, "%s%n", " dynamically registered"); + } + + @Override + public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry entry) { + printDetail(Style.REPORTED, "reports", entry.toString()); + } + + @Override + public void fileEntryPublished(TestIdentifier testIdentifier, FileEntry file) { + printDetail(Style.REPORTED, "reports", file.toString()); + } + + /** + * Print static information about the test identifier. + */ + private void printDetails(TestIdentifier testIdentifier) { + printDetail(NONE, "tags", "%s%n", testIdentifier.getTags()); + printDetail(NONE, "uniqueId", "%s%n", testIdentifier.getUniqueId()); + printDetail(NONE, "parent", "%s%n", testIdentifier.getParentId().orElse("[]")); + testIdentifier.getSource().ifPresent(source -> printDetail(NONE, "source", "%s%n", source)); + } + + private String verticals() { + return verticals(frames.size()); + } + + private String verticals(int index) { + return verticals[Math.min(index, verticals.length - 1)]; + } + + private void printVerticals(String tile) { + printf(NONE, verticals()); + printf(NONE, tile); + } + + private void printf(Style style, String message, Object... args) { + out.printf(colorPalette.paint(style, message), args); + out.flush(); + } + + /** + * Print single detail with a potential multi-line message. + */ + private void printDetail(Style style, String detail, String format, Object... args) { + // print initial verticals - expecting to be at start of the line + String verticals = verticals(frames.size() + 1); + printf(NONE, verticals); + String detailFormat = "%9s"; + // omit detail string if it's empty + if (!detail.isEmpty()) { + printf(NONE, "%s", String.format(detailFormat + ": ", detail)); + } + // trivial case: at least one arg is given? Let printf do the entire work + if (args.length > 0) { + printf(style, format, args); + return; + } + // still here? Split format into separate lines and indent them from the second line on + String[] lines = format.split("\\R"); + printf(style, "%s", lines[0]); + if (lines.length > 1) { + String delimiter = System.lineSeparator() + verticals + String.format(detailFormat + " ", ""); + for (int i = 1; i < lines.length; i++) { + printf(NONE, "%s", delimiter); + printf(style, "%s", lines[i]); + } + } + printf(NONE, "%n"); + } + + @Override + public void listTests(TestPlan testPlan) { + frames.push(0L); + testPlan.accept(new TestPlan.Visitor() { + @Override + public void preVisitContainer(TestIdentifier testIdentifier) { + if (!testPlan.getChildren(testIdentifier).isEmpty()) { + printVerticals(theme.entry()); + printf(Style.CONTAINER, " %s", testIdentifier.getDisplayName()); + printf(NONE, "%n"); + frames.push(0L); + } + } + + @Override + public void visit(TestIdentifier testIdentifier) { + if (testPlan.getChildren(testIdentifier).isEmpty()) { + printVerticals(theme.entry()); + printf(Style.valueOf(testIdentifier), " %s%n", testIdentifier.getDisplayName()); + printDetails(testIdentifier); + } + } + + @Override + public void postVisitContainer(TestIdentifier testIdentifier) { + if (!testPlan.getChildren(testIdentifier).isEmpty()) { + frames.pop(); + printVerticals(theme.end()); + printf(Style.CONTAINER, " %s%n", testIdentifier.getDisplayName()); + } + } + }); + frames.pop(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/output/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,5 @@ +/** + * Output printing utility classes of JUnit's console launcher. + */ + +package org.junit.platform.console.output; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ColorPalette.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ColorPalette.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ColorPalette.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ColorPalette.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.EnumMap; -import java.util.Map; -import java.util.Properties; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * @since 1.9 - */ -class ColorPalette { - - public static final ColorPalette SINGLE_COLOR = new ColorPalette(singleColorPalette(), false); - public static final ColorPalette DEFAULT = new ColorPalette(defaultPalette(), false); - public static final ColorPalette NONE = new ColorPalette(new EnumMap<>(Style.class), true); - - private final Map colorsToAnsiSequences; - private final boolean disableAnsiColors; - - // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters - private static Map defaultPalette() { - Map colorsToAnsiSequences = new EnumMap<>(Style.class); - colorsToAnsiSequences.put(Style.NONE, "0"); - colorsToAnsiSequences.put(Style.SUCCESSFUL, "32"); - colorsToAnsiSequences.put(Style.ABORTED, "33"); - colorsToAnsiSequences.put(Style.FAILED, "31"); - colorsToAnsiSequences.put(Style.SKIPPED, "35"); - colorsToAnsiSequences.put(Style.CONTAINER, "36"); - colorsToAnsiSequences.put(Style.TEST, "34"); - colorsToAnsiSequences.put(Style.DYNAMIC, "35"); - colorsToAnsiSequences.put(Style.REPORTED, "37"); - return colorsToAnsiSequences; - } - - private static Map singleColorPalette() { - Map colorsToAnsiSequences = new EnumMap<>(Style.class); - colorsToAnsiSequences.put(Style.NONE, "0"); - colorsToAnsiSequences.put(Style.SUCCESSFUL, "1"); - colorsToAnsiSequences.put(Style.ABORTED, "4"); - colorsToAnsiSequences.put(Style.FAILED, "7"); - colorsToAnsiSequences.put(Style.SKIPPED, "9"); - colorsToAnsiSequences.put(Style.CONTAINER, "1"); - colorsToAnsiSequences.put(Style.TEST, "0"); - colorsToAnsiSequences.put(Style.DYNAMIC, "0"); - colorsToAnsiSequences.put(Style.REPORTED, "2"); - return colorsToAnsiSequences; - } - - public ColorPalette(Map overrides) { - this(defaultPalette(), false); - - if (overrides.containsKey(Style.NONE)) { - throw new IllegalArgumentException("Cannot override the standard style 'NONE'"); - } - this.colorsToAnsiSequences.putAll(overrides); - } - - public ColorPalette(Properties properties) { - this(toOverrideMap(properties)); - } - - public ColorPalette(Reader reader) { - this(getProperties(reader)); - } - - public ColorPalette(Path path) { - this(getProperties(path)); - } - - private ColorPalette(Map colorsToAnsiSequences, boolean disableAnsiColors) { - this.colorsToAnsiSequences = colorsToAnsiSequences; - this.disableAnsiColors = disableAnsiColors; - } - - private static Map toOverrideMap(Properties properties) { - Map upperCaseProperties = properties.entrySet().stream().collect( - Collectors.toMap(entry -> ((String) entry.getKey()).toUpperCase(), entry -> (String) entry.getValue())); - - return Arrays.stream(Style.values()).filter(style -> upperCaseProperties.containsKey(style.name())).collect( - Collectors.toMap(Function.identity(), style -> upperCaseProperties.get(style.name()))); - } - - private static Properties getProperties(Reader reader) { - Properties properties = new Properties(); - try { - properties.load(reader); - } - catch (IOException e) { - throw new IllegalArgumentException("Could not read color palette properties", e); - } - return properties; - } - - private static Properties getProperties(Path path) { - try (FileReader fileReader = new FileReader(path.toFile())) { - return getProperties(fileReader); - } - catch (IOException e) { - throw new IllegalArgumentException("Could not open color palette properties file", e); - } - } - - public String paint(Style style, String text) { - return this.disableAnsiColors || style == Style.NONE ? text - : getAnsiFormatter(style) + text + getAnsiFormatter(Style.NONE); - } - - private String getAnsiFormatter(Style style) { - return String.format("\u001B[%sm", this.colorsToAnsiSequences.get(style)); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ConsoleTestExecutor.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ConsoleTestExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ConsoleTestExecutor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/ConsoleTestExecutor.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.io.PrintWriter; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.util.EnumSet; -import java.util.List; -import java.util.Optional; -import java.util.function.Supplier; - -import org.apiguardian.api.API; -import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.util.ClassLoaderUtils; -import org.junit.platform.console.options.Details; -import org.junit.platform.console.options.TestConsoleOutputOptions; -import org.junit.platform.console.options.TestDiscoveryOptions; -import org.junit.platform.console.options.Theme; -import org.junit.platform.launcher.Launcher; -import org.junit.platform.launcher.LauncherDiscoveryRequest; -import org.junit.platform.launcher.TestExecutionListener; -import org.junit.platform.launcher.TestPlan; -import org.junit.platform.launcher.core.LauncherFactory; -import org.junit.platform.launcher.listeners.SummaryGeneratingListener; -import org.junit.platform.launcher.listeners.TestExecutionSummary; -import org.junit.platform.reporting.legacy.xml.LegacyXmlReportGeneratingListener; - -/** - * @since 1.0 - */ -@API(status = INTERNAL, since = "1.0") -public class ConsoleTestExecutor { - - private final TestDiscoveryOptions discoveryOptions; - private final TestConsoleOutputOptions outputOptions; - private final Supplier launcherSupplier; - - public ConsoleTestExecutor(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions) { - this(discoveryOptions, outputOptions, LauncherFactory::create); - } - - // for tests only - ConsoleTestExecutor(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions, - Supplier launcherSupplier) { - this.discoveryOptions = discoveryOptions; - this.outputOptions = outputOptions; - this.launcherSupplier = launcherSupplier; - } - - public void discover(PrintWriter out) { - new CustomContextClassLoaderExecutor(createCustomClassLoader()).invoke(() -> { - discoverTests(out); - return null; - }); - } - - public TestExecutionSummary execute(PrintWriter out, Optional reportsDir) { - return new CustomContextClassLoaderExecutor(createCustomClassLoader()) // - .invoke(() -> executeTests(out, reportsDir)); - } - - private void discoverTests(PrintWriter out) { - Launcher launcher = launcherSupplier.get(); - Optional commandLineTestPrinter = createDetailsPrintingListener(out); - - LauncherDiscoveryRequest discoveryRequest = new DiscoveryRequestCreator().toDiscoveryRequest(discoveryOptions); - TestPlan testPlan = launcher.discover(discoveryRequest); - - commandLineTestPrinter.ifPresent(printer -> printer.listTests(testPlan)); - if (outputOptions.getDetails() != Details.NONE) { - printFoundTestsSummary(out, testPlan); - } - } - - private static void printFoundTestsSummary(PrintWriter out, TestPlan testPlan) { - SummaryGeneratingListener summaryListener = new SummaryGeneratingListener(); - summaryListener.testPlanExecutionStarted(testPlan); - TestExecutionSummary summary = summaryListener.getSummary(); - - out.printf("%n[%10d containers found ]%n[%10d tests found ]%n%n", summary.getContainersFoundCount(), - summary.getTestsFoundCount()); - out.flush(); - } - - private TestExecutionSummary executeTests(PrintWriter out, Optional reportsDir) { - Launcher launcher = launcherSupplier.get(); - SummaryGeneratingListener summaryListener = registerListeners(out, reportsDir, launcher); - - LauncherDiscoveryRequest discoveryRequest = new DiscoveryRequestCreator().toDiscoveryRequest(discoveryOptions); - launcher.execute(discoveryRequest); - - TestExecutionSummary summary = summaryListener.getSummary(); - if (summary.getTotalFailureCount() > 0 || outputOptions.getDetails() != Details.NONE) { - printSummary(summary, out); - } - - return summary; - } - - private Optional createCustomClassLoader() { - List additionalClasspathEntries = discoveryOptions.getExistingAdditionalClasspathEntries(); - if (!additionalClasspathEntries.isEmpty()) { - URL[] urls = additionalClasspathEntries.stream().map(this::toURL).toArray(URL[]::new); - ClassLoader parentClassLoader = ClassLoaderUtils.getDefaultClassLoader(); - ClassLoader customClassLoader = URLClassLoader.newInstance(urls, parentClassLoader); - return Optional.of(customClassLoader); - } - return Optional.empty(); - } - - private URL toURL(Path path) { - try { - return path.toUri().toURL(); - } - catch (Exception ex) { - throw new JUnitException("Invalid classpath entry: " + path, ex); - } - } - - private SummaryGeneratingListener registerListeners(PrintWriter out, Optional reportsDir, Launcher launcher) { - // always register summary generating listener - SummaryGeneratingListener summaryListener = new SummaryGeneratingListener(); - launcher.registerTestExecutionListeners(summaryListener); - // optionally, register test plan execution details printing listener - createDetailsPrintingListener(out).ifPresent(launcher::registerTestExecutionListeners); - // optionally, register XML reports writing listener - createXmlWritingListener(out, reportsDir).ifPresent(launcher::registerTestExecutionListeners); - return summaryListener; - } - - private Optional createDetailsPrintingListener(PrintWriter out) { - ColorPalette colorPalette = getColorPalette(); - Theme theme = outputOptions.getTheme(); - switch (outputOptions.getDetails()) { - case SUMMARY: - // summary listener is always created and registered - return Optional.empty(); - case FLAT: - return Optional.of(new FlatPrintingListener(out, colorPalette)); - case TREE: - return Optional.of(new TreePrintingListener(out, colorPalette, theme)); - case VERBOSE: - return Optional.of(new VerboseTreePrintingListener(out, colorPalette, 16, theme)); - case TESTFEED: - return Optional.of(new TestFeedPrintingListener(out, colorPalette)); - default: - return Optional.empty(); - } - } - - private ColorPalette getColorPalette() { - if (outputOptions.isAnsiColorOutputDisabled()) { - return ColorPalette.NONE; - } - if (outputOptions.getColorPalettePath() != null) { - return new ColorPalette(outputOptions.getColorPalettePath()); - } - if (outputOptions.isSingleColorPalette()) { - return ColorPalette.SINGLE_COLOR; - } - return ColorPalette.DEFAULT; - } - - private Optional createXmlWritingListener(PrintWriter out, Optional reportsDir) { - return reportsDir.map(it -> new LegacyXmlReportGeneratingListener(it, out)); - } - - private void printSummary(TestExecutionSummary summary, PrintWriter out) { - // Otherwise the failures have already been printed in detail - if (EnumSet.of(Details.NONE, Details.SUMMARY, Details.TREE).contains(outputOptions.getDetails())) { - summary.printFailuresTo(out); - } - summary.printTo(out); - } - - @FunctionalInterface - public interface Factory { - ConsoleTestExecutor create(TestDiscoveryOptions discoveryOptions, TestConsoleOutputOptions outputOptions); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutor.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutor.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import java.util.Optional; -import java.util.function.Supplier; - -import org.junit.platform.commons.JUnitException; - -/** - * @since 1.0 - */ -class CustomContextClassLoaderExecutor { - - private final Optional customClassLoader; - - CustomContextClassLoaderExecutor(Optional customClassLoader) { - this.customClassLoader = customClassLoader; - } - - T invoke(Supplier supplier) { - if (customClassLoader.isPresent()) { - // Only get/set context class loader when necessary to prevent problems with - // security managers - return replaceThreadContextClassLoaderAndInvoke(customClassLoader.get(), supplier); - } - return supplier.get(); - } - - private T replaceThreadContextClassLoaderAndInvoke(ClassLoader customClassLoader, Supplier supplier) { - ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(customClassLoader); - return supplier.get(); - } - finally { - Thread.currentThread().setContextClassLoader(originalClassLoader); - if (customClassLoader instanceof AutoCloseable) { - close((AutoCloseable) customClassLoader); - } - } - } - - private static void close(AutoCloseable customClassLoader) { - try { - customClassLoader.close(); - } - catch (Exception e) { - throw new JUnitException("Failed to close custom class loader", e); - } - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DetailsPrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DetailsPrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DetailsPrintingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DetailsPrintingListener.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import java.util.regex.Pattern; - -import org.junit.platform.launcher.TestExecutionListener; -import org.junit.platform.launcher.TestPlan; - -interface DetailsPrintingListener extends TestExecutionListener { - - Pattern LINE_START_PATTERN = Pattern.compile("(?m)^"); - - void listTests(TestPlan testPlan); - - static String indented(String message, String indentation) { - return LINE_START_PATTERN.matcher(message).replaceAll(indentation).trim(); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.platform.engine.discovery.ClassNameFilter.excludeClassNamePatterns; -import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathRoots; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectModules; -import static org.junit.platform.engine.discovery.PackageNameFilter.excludePackageNames; -import static org.junit.platform.engine.discovery.PackageNameFilter.includePackageNames; -import static org.junit.platform.launcher.EngineFilter.excludeEngines; -import static org.junit.platform.launcher.EngineFilter.includeEngines; -import static org.junit.platform.launcher.TagFilter.excludeTags; -import static org.junit.platform.launcher.TagFilter.includeTags; -import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; - -import java.nio.file.Path; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Stream; - -import org.junit.platform.commons.util.ModuleUtils; -import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.console.options.TestDiscoveryOptions; -import org.junit.platform.engine.DiscoverySelector; -import org.junit.platform.engine.discovery.ClassNameFilter; -import org.junit.platform.engine.discovery.ClassSelector; -import org.junit.platform.engine.discovery.ClasspathRootSelector; -import org.junit.platform.engine.discovery.IterationSelector; -import org.junit.platform.engine.discovery.MethodSelector; -import org.junit.platform.launcher.LauncherDiscoveryRequest; -import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; - -/** - * @since 1.0 - */ -class DiscoveryRequestCreator { - - LauncherDiscoveryRequest toDiscoveryRequest(TestDiscoveryOptions options) { - LauncherDiscoveryRequestBuilder requestBuilder = request(); - List selectors = createDiscoverySelectors(options); - requestBuilder.selectors(selectors); - addFilters(requestBuilder, options, selectors); - requestBuilder.configurationParameters(options.getConfigurationParameters()); - requestBuilder.configurationParametersResources( - options.getConfigurationParametersResources().toArray(new String[0])); - return requestBuilder.build(); - } - - private List createDiscoverySelectors(TestDiscoveryOptions options) { - List explicitSelectors = options.getExplicitSelectors(); - if (options.isScanClasspath()) { - Preconditions.condition(explicitSelectors.isEmpty(), - "Scanning the classpath and using explicit selectors at the same time is not supported"); - return createClasspathRootSelectors(options); - } - if (options.isScanModulepath()) { - Preconditions.condition(explicitSelectors.isEmpty(), - "Scanning the module-path and using explicit selectors at the same time is not supported"); - return selectModules(ModuleUtils.findAllNonSystemBootModuleNames()); - } - return Preconditions.notEmpty(explicitSelectors, - "Please specify an explicit selector option or use --scan-class-path or --scan-modules"); - } - - private List createClasspathRootSelectors(TestDiscoveryOptions options) { - Set classpathRoots = determineClasspathRoots(options); - return selectClasspathRoots(classpathRoots); - } - - private Set determineClasspathRoots(TestDiscoveryOptions options) { - if (options.getSelectedClasspathEntries().isEmpty()) { - Set rootDirs = new LinkedHashSet<>(ReflectionUtils.getAllClasspathRootDirectories()); - rootDirs.addAll(options.getExistingAdditionalClasspathEntries()); - return rootDirs; - } - return new LinkedHashSet<>(options.getSelectedClasspathEntries()); - } - - private void addFilters(LauncherDiscoveryRequestBuilder requestBuilder, TestDiscoveryOptions options, - List selectors) { - requestBuilder.filters(includedClassNamePatterns(options, selectors)); - - if (!options.getExcludedClassNamePatterns().isEmpty()) { - requestBuilder.filters( - excludeClassNamePatterns(options.getExcludedClassNamePatterns().toArray(new String[0]))); - } - - if (!options.getIncludedPackages().isEmpty()) { - requestBuilder.filters(includePackageNames(options.getIncludedPackages())); - } - - if (!options.getExcludedPackages().isEmpty()) { - requestBuilder.filters(excludePackageNames(options.getExcludedPackages())); - } - - if (!options.getIncludedTagExpressions().isEmpty()) { - requestBuilder.filters(includeTags(options.getIncludedTagExpressions())); - } - - if (!options.getExcludedTagExpressions().isEmpty()) { - requestBuilder.filters(excludeTags(options.getExcludedTagExpressions())); - } - - if (!options.getIncludedEngines().isEmpty()) { - requestBuilder.filters(includeEngines(options.getIncludedEngines())); - } - - if (!options.getExcludedEngines().isEmpty()) { - requestBuilder.filters(excludeEngines(options.getExcludedEngines())); - } - } - - private ClassNameFilter includedClassNamePatterns(TestDiscoveryOptions options, - List selectors) { - Stream patternStreams = Stream.concat( // - options.getIncludedClassNamePatterns().stream(), // - selectors.stream() // - .map(selector -> selector instanceof IterationSelector - ? ((IterationSelector) selector).getParentSelector() - : selector) // - .map(selector -> { - if (selector instanceof ClassSelector) { - return ((ClassSelector) selector).getClassName(); - } - if (selector instanceof MethodSelector) { - return ((MethodSelector) selector).getClassName(); - } - return null; - }) // - .filter(Objects::nonNull) // - .map(Pattern::quote)); - return includeClassNamePatterns(patternStreams.toArray(String[]::new)); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/FlatPrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/FlatPrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/FlatPrintingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/FlatPrintingListener.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import java.io.PrintWriter; - -import org.junit.platform.commons.util.ExceptionUtils; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.launcher.TestPlan; - -/** - * @since 1.0 - */ -class FlatPrintingListener implements DetailsPrintingListener { - - static final String INDENTATION = " "; - - private final PrintWriter out; - private final ColorPalette colorPalette; - - FlatPrintingListener(PrintWriter out, ColorPalette colorPalette) { - this.out = out; - this.colorPalette = colorPalette; - } - - @Override - public void testPlanExecutionStarted(TestPlan testPlan) { - this.out.printf("Test execution started. Number of static tests: %d%n", - testPlan.countTestIdentifiers(TestIdentifier::isTest)); - } - - @Override - public void testPlanExecutionFinished(TestPlan testPlan) { - this.out.println("Test execution finished."); - } - - @Override - public void dynamicTestRegistered(TestIdentifier testIdentifier) { - printlnTestDescriptor(Style.DYNAMIC, "Registered:", testIdentifier); - } - - @Override - public void executionSkipped(TestIdentifier testIdentifier, String reason) { - printlnTestDescriptor(Style.SKIPPED, "Skipped:", testIdentifier); - printlnMessage(Style.SKIPPED, "Reason", reason); - } - - @Override - public void executionStarted(TestIdentifier testIdentifier) { - printlnTestDescriptor(Style.valueOf(testIdentifier), "Started:", testIdentifier); - } - - @Override - public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { - Style style = Style.valueOf(testExecutionResult); - printlnTestDescriptor(style, "Finished:", testIdentifier); - testExecutionResult.getThrowable().ifPresent(t -> printlnException(style, t)); - } - - @Override - public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry entry) { - printlnTestDescriptor(Style.REPORTED, "Reported:", testIdentifier); - printlnMessage(Style.REPORTED, "Reported values", entry.toString()); - } - - private void printlnTestDescriptor(Style style, String message, TestIdentifier testIdentifier) { - println(style, "%-10s %s (%s)", message, testIdentifier.getDisplayName(), testIdentifier.getUniqueId()); - } - - private void printlnException(Style style, Throwable throwable) { - printlnMessage(style, "Exception", ExceptionUtils.readStackTrace(throwable)); - } - - private void printlnMessage(Style style, String message, String detail) { - println(style, INDENTATION + "=> " + message + ": %s", indented(detail)); - } - - private void println(Style style, String format, Object... args) { - this.out.println(colorPalette.paint(style, String.format(format, args))); - } - - /** - * Indent the given message if it is a multi-line string. - * - *

    {@link #INDENTATION} is used to prefix the start of each new line - * except the first one. - * - * @param message the message to indent - * @return indented message - */ - private static String indented(String message) { - return DetailsPrintingListener.indented(message, INDENTATION); - } - - @Override - public void listTests(TestPlan testPlan) { - testPlan.accept(new TestPlan.Visitor() { - @Override - public void visit(TestIdentifier testIdentifier) { - println(Style.valueOf(testIdentifier), "%s (%s)", testIdentifier.getDisplayName(), - testIdentifier.getUniqueId()); - } - }); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/Style.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/Style.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/Style.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/Style.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.launcher.TestIdentifier; - -/** - * @since 1.9 - */ -enum Style { - - NONE, SUCCESSFUL, ABORTED, FAILED, SKIPPED, CONTAINER, TEST, DYNAMIC, REPORTED; - - static Style valueOf(TestExecutionResult result) { - switch (result.getStatus()) { - case SUCCESSFUL: - return Style.SUCCESSFUL; - case ABORTED: - return Style.ABORTED; - case FAILED: - return Style.FAILED; - default: - return Style.NONE; - } - } - - static Style valueOf(TestIdentifier testIdentifier) { - return testIdentifier.isContainer() ? CONTAINER : TEST; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TestFeedPrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TestFeedPrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TestFeedPrintingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TestFeedPrintingListener.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.platform.engine.TestExecutionResult.Status.SUCCESSFUL; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; - -import org.junit.platform.commons.util.ExceptionUtils; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.launcher.TestPlan; - -class TestFeedPrintingListener implements DetailsPrintingListener { - - private static final String INDENTATION = "\t"; - private static final String STATUS_SEPARATOR = " :: "; - - private final PrintWriter out; - private final ColorPalette colorPalette; - private TestPlan testPlan; - - TestFeedPrintingListener(PrintWriter out, ColorPalette colorPalette) { - this.out = out; - this.colorPalette = colorPalette; - } - - @Override - public void testPlanExecutionStarted(TestPlan testPlan) { - this.testPlan = testPlan; - } - - @Override - public void testPlanExecutionFinished(TestPlan testPlan) { - this.testPlan = null; - } - - @Override - public void executionSkipped(TestIdentifier testIdentifier, String reason) { - if (shouldPrint(testIdentifier)) { - String msg = formatTestIdentifier(testIdentifier); - String indentedReason = indented(String.format("Reason: %s", reason)); - println(Style.SKIPPED, - String.format("%s" + STATUS_SEPARATOR + "SKIPPED%n" + INDENTATION + "%s", msg, indentedReason)); - } - } - - @Override - public void executionStarted(TestIdentifier testIdentifier) { - if (shouldPrint(testIdentifier)) { - String msg = formatTestIdentifier(testIdentifier); - println(Style.NONE, String.format("%s" + STATUS_SEPARATOR + "STARTED", msg)); - } - } - - @Override - public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { - TestExecutionResult.Status status = testExecutionResult.getStatus(); - if (testExecutionResult.getThrowable().isPresent()) { - Style style = Style.valueOf(testExecutionResult); - String msg = formatTestIdentifier(testIdentifier); - Throwable throwable = testExecutionResult.getThrowable().get(); - String stacktrace = indented(ExceptionUtils.readStackTrace(throwable)); - println(style, - String.format("%s" + STATUS_SEPARATOR + "%s%n" + INDENTATION + "%s", msg, status, stacktrace)); - } - else if (shouldPrint(testIdentifier) || testExecutionResult.getStatus() != SUCCESSFUL) { - Style style = Style.valueOf(testExecutionResult); - String msg = formatTestIdentifier(testIdentifier); - println(style, String.format("%s" + STATUS_SEPARATOR + "%s", msg, status)); - } - } - - private String formatTestIdentifier(TestIdentifier testIdentifier) { - return String.join(" > ", collectDisplayNames(testIdentifier.getUniqueIdObject())); - } - - private void println(Style style, String message) { - this.out.println(colorPalette.paint(style, message)); - } - - private List collectDisplayNames(UniqueId uniqueId) { - int size = uniqueId.getSegments().size(); - List displayNames = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - displayNames.add(0, testPlan.getTestIdentifier(uniqueId).getDisplayName()); - if (i < size - 1) { - uniqueId = uniqueId.removeLastSegment(); - } - } - return displayNames; - } - - private static String indented(String message) { - return DetailsPrintingListener.indented(message, INDENTATION); - } - - @Override - public void listTests(TestPlan testPlan) { - this.testPlan = testPlan; - try { - testPlan.accept(new TestPlan.Visitor() { - @Override - public void visit(TestIdentifier testIdentifier) { - if (shouldPrint(testIdentifier)) { - println(Style.NONE, formatTestIdentifier(testIdentifier)); - } - } - }); - } - finally { - this.testPlan = null; - } - } - - private static boolean shouldPrint(TestIdentifier testIdentifier) { - return testIdentifier.isTest(); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreeNode.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreeNode.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreeNode.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreeNode.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import java.util.Optional; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.junit.platform.commons.util.StringUtils; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.launcher.TestIdentifier; - -/** - * @since 1.0 - */ -class TreeNode { - - private final String caption; - private final long creation; - long duration; - private String reason; - private TestIdentifier identifier; - private TestExecutionResult result; - final Queue reports = new ConcurrentLinkedQueue<>(); - final Queue children = new ConcurrentLinkedQueue<>(); - boolean visible; - - TreeNode(String caption) { - this.caption = caption; - this.creation = System.currentTimeMillis(); - this.visible = false; - } - - TreeNode(TestIdentifier identifier) { - this(createCaption(identifier.getDisplayName())); - this.identifier = identifier; - this.visible = true; - } - - TreeNode(TestIdentifier identifier, String reason) { - this(identifier); - this.reason = reason; - } - - TreeNode addChild(TreeNode node) { - children.add(node); - return this; - } - - TreeNode addReportEntry(ReportEntry reportEntry) { - reports.add(reportEntry); - return this; - } - - TreeNode setResult(TestExecutionResult result) { - this.result = result; - this.duration = System.currentTimeMillis() - creation; - return this; - } - - public String caption() { - return caption; - } - - Optional reason() { - return Optional.ofNullable(reason); - } - - Optional result() { - return Optional.ofNullable(result); - } - - Optional identifier() { - return Optional.ofNullable(identifier); - } - - static String createCaption(String displayName) { - boolean normal = displayName.length() <= 80; - String caption = normal ? displayName : displayName.substring(0, 80) + "..."; - String whites = StringUtils.replaceWhitespaceCharacters(caption, " "); - return StringUtils.replaceIsoControlCharacters(whites, "."); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrinter.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrinter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrinter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrinter.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; - -import java.io.PrintWriter; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import org.junit.platform.commons.util.StringUtils; -import org.junit.platform.console.options.Theme; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.TestExecutionResult.Status; -import org.junit.platform.engine.reporting.ReportEntry; - -/** - * @since 1.0 - */ -class TreePrinter { - - private final PrintWriter out; - private final Theme theme; - private final ColorPalette colorPalette; - - TreePrinter(PrintWriter out, Theme theme, ColorPalette colorPalette) { - this.out = out; - this.theme = theme; - this.colorPalette = colorPalette; - } - - void print(TreeNode node) { - out.println(color(Style.CONTAINER, theme.root())); - print(node, "", true); - out.flush(); - } - - private void print(TreeNode node, String indent, boolean continuous) { - if (node.visible) { - printVisible(node, indent, continuous); - } - if (node.children.isEmpty()) { - return; - } - if (node.visible) { - indent += continuous ? theme.vertical() : theme.blank(); - } - Iterator iterator = node.children.iterator(); - while (iterator.hasNext()) { - print(iterator.next(), indent, iterator.hasNext()); - } - } - - private void printVisible(TreeNode node, String indent, boolean continuous) { - String bullet = continuous ? theme.entry() : theme.end(); - String prefix = color(Style.CONTAINER, indent + bullet); - String tabbed = color(Style.CONTAINER, indent + tab(node, continuous)); - String caption = colorCaption(node); - String duration = color(Style.CONTAINER, node.duration + " ms"); - String icon = color(Style.SKIPPED, theme.skipped()); - if (node.result().isPresent()) { - TestExecutionResult result = node.result().get(); - Style resultStyle = Style.valueOf(result); - icon = color(resultStyle, theme.status(result)); - } - out.print(prefix); - out.print(" "); - out.print(caption); - if (node.duration > 10000 && node.children.isEmpty()) { - out.print(" "); - out.print(duration); - } - boolean nodeIsBeingListed = node.duration == 0 && !node.result().isPresent() && !node.reason().isPresent(); - if (!nodeIsBeingListed) { - out.print(" "); - out.print(icon); - } - node.result().ifPresent(result -> printThrowable(tabbed, result)); - node.reason().ifPresent(reason -> printMessage(Style.SKIPPED, tabbed, reason)); - node.reports.forEach(e -> printReportEntry(tabbed, e)); - out.println(); - } - - private String tab(TreeNode node, boolean continuous) { - // We might be the "last" node in this level, that means - // `continuous == false`, but still need to include a vertical - // bar for printing stack traces, messages and reports. - // See https://github.com/junit-team/junit5/issues/1531 - if (node.children.size() > 0) { - return theme.blank() + theme.vertical(); - } - return (continuous ? theme.vertical() : theme.blank()) + theme.blank(); - } - - private String colorCaption(TreeNode node) { - String caption = node.caption(); - if (node.result().isPresent()) { - TestExecutionResult result = node.result().get(); - Style resultStyle = Style.valueOf(result); - if (result.getStatus() != Status.SUCCESSFUL) { - return color(resultStyle, caption); - } - } - if (node.reason().isPresent()) { - return color(Style.SKIPPED, caption); - } - Style style = node.identifier().map(Style::valueOf).orElse(Style.NONE); - return color(style, caption); - } - - private void printThrowable(String indent, TestExecutionResult result) { - if (!result.getThrowable().isPresent()) { - return; - } - Throwable throwable = result.getThrowable().get(); - String message = throwable.getMessage(); - if (StringUtils.isBlank(message)) { - message = throwable.toString(); - } - printMessage(Style.FAILED, indent, message); - } - - private void printReportEntry(String indent, ReportEntry reportEntry) { - out.println(); - out.print(indent); - out.print(reportEntry.getTimestamp()); - Set> entries = reportEntry.getKeyValuePairs().entrySet(); - if (entries.size() == 1) { - printReportEntry(" ", getOnlyElement(entries)); - return; - } - for (Map.Entry entry : entries) { - out.println(); - printReportEntry(indent + theme.blank(), entry); - } - } - - private void printReportEntry(String indent, Map.Entry mapEntry) { - out.print(indent); - out.print(color(Style.ABORTED, mapEntry.getKey())); - out.print(" = `"); - out.print(color(Style.SUCCESSFUL, mapEntry.getValue())); - out.print("`"); - } - - private void printMessage(Style style, String indent, String message) { - String[] lines = message.split("\\R"); - out.print(" "); - out.print(color(style, lines[0])); - if (lines.length > 1) { - for (int i = 1; i < lines.length; i++) { - out.println(); - out.print(indent); - if (StringUtils.isNotBlank(lines[i])) { - String extra = theme.blank(); - out.print(color(style, extra + lines[i])); - } - } - } - } - - private String color(Style style, String text) { - return colorPalette.paint(style, text); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrintingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/TreePrintingListener.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import java.io.PrintWriter; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.junit.platform.console.options.Theme; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.launcher.TestPlan; - -/** - * @since 1.0 - */ -class TreePrintingListener implements DetailsPrintingListener { - - private final Map nodesByUniqueId = new ConcurrentHashMap<>(); - private TreeNode root; - private final TreePrinter treePrinter; - - TreePrintingListener(PrintWriter out, ColorPalette colorPalette, Theme theme) { - this.treePrinter = new TreePrinter(out, theme, colorPalette); - } - - private void addNode(TestIdentifier testIdentifier, TreeNode node) { - nodesByUniqueId.put(testIdentifier.getUniqueIdObject(), node); - testIdentifier.getParentIdObject().map(nodesByUniqueId::get).orElse(root).addChild(node); - } - - private TreeNode getNode(TestIdentifier testIdentifier) { - return nodesByUniqueId.get(testIdentifier.getUniqueIdObject()); - } - - @Override - public void testPlanExecutionStarted(TestPlan testPlan) { - root = new TreeNode(testPlan.toString()); - } - - @Override - public void testPlanExecutionFinished(TestPlan testPlan) { - treePrinter.print(root); - } - - @Override - public void executionStarted(TestIdentifier testIdentifier) { - addNode(testIdentifier, new TreeNode(testIdentifier)); - } - - @Override - public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { - getNode(testIdentifier).setResult(testExecutionResult); - } - - @Override - public void executionSkipped(TestIdentifier testIdentifier, String reason) { - addNode(testIdentifier, new TreeNode(testIdentifier, reason)); - } - - @Override - public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry entry) { - getNode(testIdentifier).addReportEntry(entry); - } - - @Override - public void listTests(TestPlan testPlan) { - root = new TreeNode(testPlan.toString()); - testPlan.accept(new TestPlan.Visitor() { - @Override - public void visit(TestIdentifier testIdentifier) { - addNode(testIdentifier, new TreeNode(testIdentifier)); - } - }); - treePrinter.print(root); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/VerboseTreePrintingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/VerboseTreePrintingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/VerboseTreePrintingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/VerboseTreePrintingListener.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.platform.commons.util.ExceptionUtils.readStackTrace; -import static org.junit.platform.console.tasks.Style.NONE; - -import java.io.PrintWriter; -import java.util.ArrayDeque; -import java.util.Deque; - -import org.junit.platform.console.options.Theme; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.launcher.TestPlan; - -/** - * @since 1.0 - */ -class VerboseTreePrintingListener implements DetailsPrintingListener { - - private final PrintWriter out; - private final Theme theme; - private final ColorPalette colorPalette; - private final Deque frames; - private final String[] verticals; - private long executionStartedMillis; - - VerboseTreePrintingListener(PrintWriter out, ColorPalette colorPalette, int maxContainerNestingLevel, Theme theme) { - this.out = out; - this.colorPalette = colorPalette; - this.theme = theme; - - // create frame stack and push initial root frame - this.frames = new ArrayDeque<>(); - this.frames.push(0L); - - // create and populate vertical indentation lookup table - this.verticals = new String[Math.max(10, maxContainerNestingLevel) + 1]; - this.verticals[0] = ""; // no frame - this.verticals[1] = ""; // synthetic root "/" level - this.verticals[2] = ""; // "engine" level - - for (int i = 3; i < verticals.length; i++) { - verticals[i] = verticals[i - 1] + theme.vertical(); - } - } - - @Override - public void testPlanExecutionStarted(TestPlan testPlan) { - frames.push(System.currentTimeMillis()); - - String prefix = "Test plan execution started. Number of static tests: "; - printNumberOfTests(testPlan, prefix); - printf(Style.CONTAINER, "%s%n", theme.root()); - } - - @Override - public void testPlanExecutionFinished(TestPlan testPlan) { - frames.pop(); - - printNumberOfTests(testPlan, "Test plan execution finished. Number of all tests: "); - } - - private void printNumberOfTests(TestPlan testPlan, String prefix) { - long tests = testPlan.countTestIdentifiers(TestIdentifier::isTest); - printf(NONE, "%s", prefix); - printf(Style.TEST, "%d%n", tests); - } - - @Override - public void executionStarted(TestIdentifier testIdentifier) { - this.executionStartedMillis = System.currentTimeMillis(); - if (testIdentifier.isContainer()) { - printVerticals(theme.entry()); - printf(Style.CONTAINER, " %s", testIdentifier.getDisplayName()); - printf(NONE, "%n"); - frames.push(System.currentTimeMillis()); - } - if (testIdentifier.isContainer()) { - return; - } - printVerticals(theme.entry()); - printf(Style.valueOf(testIdentifier), " %s%n", testIdentifier.getDisplayName()); - printDetails(testIdentifier); - } - - @Override - public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { - testExecutionResult.getThrowable().ifPresent(t -> printDetail(Style.FAILED, "caught", readStackTrace(t))); - if (testIdentifier.isContainer()) { - Long creationMillis = frames.pop(); - printVerticals(theme.end()); - printf(Style.CONTAINER, " %s", testIdentifier.getDisplayName()); - printf(NONE, " finished after %d ms.%n", System.currentTimeMillis() - creationMillis); - return; - } - printDetail(NONE, "duration", "%d ms%n", System.currentTimeMillis() - executionStartedMillis); - String status = theme.status(testExecutionResult) + " " + testExecutionResult.getStatus(); - printDetail(Style.valueOf(testExecutionResult), "status", "%s%n", status); - } - - @Override - public void executionSkipped(TestIdentifier testIdentifier, String reason) { - printVerticals(theme.entry()); - printf(Style.valueOf(testIdentifier), " %s%n", testIdentifier.getDisplayName()); - printDetails(testIdentifier); - printDetail(Style.SKIPPED, "reason", reason); - printDetail(Style.SKIPPED, "status", theme.skipped() + " SKIPPED"); - } - - @Override - public void dynamicTestRegistered(TestIdentifier testIdentifier) { - printVerticals(theme.entry()); - printf(Style.DYNAMIC, " %s", testIdentifier.getDisplayName()); - printf(NONE, "%s%n", " dynamically registered"); - } - - @Override - public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry entry) { - printDetail(Style.REPORTED, "reports", entry.toString()); - } - - /** - * Print static information about the test identifier. - */ - private void printDetails(TestIdentifier testIdentifier) { - printDetail(NONE, "tags", "%s%n", testIdentifier.getTags()); - printDetail(NONE, "uniqueId", "%s%n", testIdentifier.getUniqueId()); - printDetail(NONE, "parent", "%s%n", testIdentifier.getParentId().orElse("[]")); - testIdentifier.getSource().ifPresent(source -> printDetail(NONE, "source", "%s%n", source)); - } - - private String verticals() { - return verticals(frames.size()); - } - - private String verticals(int index) { - return verticals[Math.min(index, verticals.length - 1)]; - } - - private void printVerticals(String tile) { - printf(NONE, verticals()); - printf(NONE, tile); - } - - private void printf(Style style, String message, Object... args) { - out.printf(colorPalette.paint(style, message), args); - out.flush(); - } - - /** - * Print single detail with a potential multi-line message. - */ - private void printDetail(Style style, String detail, String format, Object... args) { - // print initial verticals - expecting to be at start of the line - String verticals = verticals(frames.size() + 1); - printf(NONE, verticals); - String detailFormat = "%9s"; - // omit detail string if it's empty - if (!detail.isEmpty()) { - printf(NONE, "%s", String.format(detailFormat + ": ", detail)); - } - // trivial case: at least one arg is given? Let printf do the entire work - if (args.length > 0) { - printf(style, format, args); - return; - } - // still here? Split format into separate lines and indent them from the second line on - String[] lines = format.split("\\R"); - printf(style, "%s", lines[0]); - if (lines.length > 1) { - String delimiter = System.lineSeparator() + verticals + String.format(detailFormat + " ", ""); - for (int i = 1; i < lines.length; i++) { - printf(NONE, "%s", delimiter); - printf(style, "%s", lines[i]); - } - } - printf(NONE, "%n"); - } - - @Override - public void listTests(TestPlan testPlan) { - frames.push(0L); - testPlan.accept(new TestPlan.Visitor() { - @Override - public void preVisitContainer(TestIdentifier testIdentifier) { - if (!testPlan.getChildren(testIdentifier).isEmpty()) { - printVerticals(theme.entry()); - printf(Style.CONTAINER, " %s", testIdentifier.getDisplayName()); - printf(NONE, "%n"); - frames.push(0L); - } - } - - @Override - public void visit(TestIdentifier testIdentifier) { - if (testPlan.getChildren(testIdentifier).isEmpty()) { - printVerticals(theme.entry()); - printf(Style.valueOf(testIdentifier), " %s%n", testIdentifier.getDisplayName()); - printDetails(testIdentifier); - } - } - - @Override - public void postVisitContainer(TestIdentifier testIdentifier) { - if (!testPlan.getChildren(testIdentifier).isEmpty()) { - frames.pop(); - printVerticals(theme.end()); - printf(Style.CONTAINER, " %s%n", testIdentifier.getDisplayName()); - } - } - }); - frames.pop(); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/package-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/package-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/package-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java/org/junit/platform/console/tasks/package-info.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -/** - * Internal execution tasks for JUnit's console launcher. - */ - -package org.junit.platform.console.tasks; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java17/org/junit/platform/console/options/ConsoleUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java17/org/junit/platform/console/options/ConsoleUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java17/org/junit/platform/console/options/ConsoleUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java17/org/junit/platform/console/options/ConsoleUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java9/org/junit/platform/console/ConsoleLauncherToolProvider.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java9/org/junit/platform/console/ConsoleLauncherToolProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/main/java9/org/junit/platform/console/ConsoleLauncherToolProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/main/java9/org/junit/platform/console/ConsoleLauncherToolProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/module/org.junit.platform.console/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/module/org.junit.platform.console/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-console/src/module/org.junit.platform.console/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console/src/module/org.junit.platform.console/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Support for launching the JUnit Platform from the console. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-console-standalone/junit-platform-console-standalone.gradle.kts jtreg8-8.3+1+ds1/junit5/junit-platform-console-standalone/junit-platform-console-standalone.gradle.kts --- jtreg8-8.1+1+ds1/junit5/junit-platform-console-standalone/junit-platform-console-standalone.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-console-standalone/junit-platform-console-standalone.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,3 +1,4 @@ +import junitbuild.extensions.dependencyProject import junitbuild.java.WriteArtifactsFile plugins { @@ -17,14 +18,21 @@ shadowed(libs.apiguardian) { because("downstream projects need it to avoid compiler warnings") } + + osgiVerification(libs.openTestReporting.tooling.spi) } val jupiterVersion = rootProject.version val vintageVersion: String by project +japicmp { + enabled = false // already checked by individual projects +} + tasks { jar { manifest { + attributes("Automatic-Module-Name" to "org.junit.platform.console.standalone") attributes("Main-Class" to "org.junit.platform.console.ConsoleLauncher") } } @@ -33,17 +41,17 @@ outputFile = layout.buildDirectory.file("shadowed-artifacts") } shadowJar { - // https://github.com/junit-team/junit5/issues/2557 + // https://github.com/junit-team/junit-framework/issues/2557 // exclude compiled module declarations from any source (e.g. /*, /META-INF/versions/N/*) exclude("**/module-info.class") - // https://github.com/junit-team/junit5/issues/761 + // https://github.com/junit-team/junit-framework/issues/761 // prevent duplicates, add 3rd-party licenses explicitly exclude("META-INF/LICENSE*.md") - from(project.projects.junitPlatformConsole.dependencyProject.projectDir) { + from(dependencyProject(project.projects.junitPlatformConsole).projectDir) { include("LICENSE-picocli.md") into("META-INF") } - from(project.projects.junitJupiterParams.dependencyProject.projectDir) { + from(dependencyProject(project.projects.junitJupiterParams).projectDir) { include("LICENSE-univocity-parsers.md") into("META-INF") } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeTestDescriptorVisitor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeTestDescriptorVisitor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeTestDescriptorVisitor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/CompositeTestDescriptorVisitor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine; + +import java.util.Arrays; + +import org.junit.platform.commons.util.Preconditions; + +/** + * @since 1.13 + */ +final class CompositeTestDescriptorVisitor implements TestDescriptor.Visitor { + + private final TestDescriptor.Visitor[] visitors; + + static TestDescriptor.Visitor from(TestDescriptor.Visitor... visitors) { + Preconditions.notNull(visitors, "visitors must not be null"); + Preconditions.notEmpty(visitors, "visitors must not be empty"); + Preconditions.containsNoNullElements(visitors, "visitors must not contain any null elements"); + return visitors.length == 1 ? visitors[0] : new CompositeTestDescriptorVisitor(visitors); + } + + private CompositeTestDescriptorVisitor(TestDescriptor.Visitor[] visitors) { + this.visitors = Arrays.copyOf(visitors, visitors.length); + } + + @Override + public void visit(TestDescriptor descriptor) { + for (TestDescriptor.Visitor visitor : visitors) { + visitor.visit(descriptor); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ConfigurationParameters.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ConfigurationParameters.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ConfigurationParameters.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ConfigurationParameters.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DefaultDiscoveryIssue.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DefaultDiscoveryIssue.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DefaultDiscoveryIssue.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DefaultDiscoveryIssue.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,114 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine; + +import java.util.Objects; +import java.util.Optional; + +import org.junit.platform.commons.util.ToStringBuilder; + +/** + * @since 1.13 + */ +final class DefaultDiscoveryIssue implements DiscoveryIssue { + + private final Severity severity; + private final String message; + private final TestSource source; + private final Throwable cause; + + DefaultDiscoveryIssue(Builder builder) { + this.severity = builder.severity; + this.message = builder.message; + this.source = builder.source; + this.cause = builder.cause; + } + + @Override + public Severity severity() { + return this.severity; + } + + @Override + public String message() { + return this.message; + } + + @Override + public Optional source() { + return Optional.ofNullable(this.source); + } + + @Override + public Optional cause() { + return Optional.ofNullable(this.cause); + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) + return false; + DefaultDiscoveryIssue that = (DefaultDiscoveryIssue) o; + return this.severity == that.severity // + && Objects.equals(this.message, that.message) // + && Objects.equals(this.source, that.source) // + && Objects.equals(this.cause, that.cause); + } + + @Override + public int hashCode() { + return Objects.hash(this.severity, this.message, this.source, this.cause); + } + + @Override + public String toString() { + ToStringBuilder builder = new ToStringBuilder(DiscoveryIssue.class.getSimpleName()) // + .append("severity", this.severity) // + .append("message", this.message); + if (this.source != null) { + builder.append("source", this.source); + } + if (this.cause != null) { + builder.append("cause", this.cause); + } + return builder.toString(); + } + + static class Builder implements DiscoveryIssue.Builder { + + private final Severity severity; + private final String message; + private TestSource source; + public Throwable cause; + + Builder(Severity severity, String message) { + this.severity = severity; + this.message = message; + } + + @Override + public Builder source(TestSource source) { + this.source = source; + return this; + } + + @Override + public Builder cause(Throwable cause) { + this.cause = cause; + return this; + } + + @Override + public DiscoveryIssue build() { + return new DefaultDiscoveryIssue(this); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryIssue.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryIssue.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryIssue.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoveryIssue.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,168 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.Optional; +import java.util.function.UnaryOperator; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; + +/** + * {@code DiscoveryIssue} represents an issue that was encountered during test + * discovery by a {@link TestEngine}. + * + * @since 1.13 + */ +@API(status = MAINTAINED, since = "1.13.3") +public interface DiscoveryIssue { + + /** + * Create a new {@code DiscoveryIssue} with the supplied {@link Severity} and + * message. + * + * @param severity the severity of the issue; never {@code null} + * @param message the message of the issue; never blank + * @see #builder(Severity, String) + */ + static DiscoveryIssue create(Severity severity, String message) { + return builder(severity, message).build(); + } + + /** + * Create a new {@link Builder} for creating a {@code DiscoveryIssue} with + * the supplied {@link Severity} and message. + * + * @param severity the severity of the issue; never {@code null} + * @param message the message of the issue; never blank + * @see Builder + * @see #create(Severity, String) + */ + static Builder builder(Severity severity, String message) { + Preconditions.notNull(severity, "severity must not be null"); + Preconditions.notBlank(message, "message must not be blank"); + return new DefaultDiscoveryIssue.Builder(severity, message); + } + + /** + * {@return the severity of this issue} + */ + Severity severity(); + + /** + * {@return the message of this issue} + */ + String message(); + + /** + * {@return the source of this issue} + */ + Optional source(); + + /** + * {@return the cause of this issue} + */ + Optional cause(); + + /** + * Create a copy of this issue with the modified message produced by the + * supplied operator. + */ + default DiscoveryIssue withMessage(UnaryOperator messageModifier) { + String oldMessage = message(); + String newMessage = messageModifier.apply(oldMessage); + if (oldMessage.equals(newMessage)) { + return this; + } + return DiscoveryIssue.builder(severity(), newMessage) // + .source(source()) // + .cause(cause()) // + .build(); + } + + /** + * The severity of a {@code DiscoveryIssue}. + */ + enum Severity { + + /** + * Indicates that the engine encountered something that could be + * potentially problematic, but could also happen due to a valid setup + * or configuration. + */ + INFO, + + /** + * Indicates that the engine encountered something that is problematic + * and might lead to unexpected behavior or will be removed or changed + * in a future release. + */ + WARNING, + + /** + * Indicates that the engine encountered something that is definitely + * problematic and will lead to unexpected behavior. + */ + ERROR + } + + /** + * Builder for creating a {@code DiscoveryIssue}. + */ + interface Builder { + + /** + * Set the {@link TestSource} for the {@code DiscoveryIssue}. + * + * @param source the {@link TestSource} for the {@code DiscoveryIssue}; + * never {@code null} but potentially empty + */ + default Builder source(Optional source) { + source.ifPresent(this::source); + return this; + } + + /** + * Set the {@link TestSource} for the {@code DiscoveryIssue}. + * + * @param source the {@link TestSource} for the {@code DiscoveryIssue}; + * may be {@code null} + */ + Builder source(TestSource source); + + /** + * Set the {@link Throwable} that caused the {@code DiscoveryIssue}. + * + * @param cause the {@link Throwable} that caused the + * {@code DiscoveryIssue}; never {@code null} but potentially empty + */ + default Builder cause(Optional cause) { + cause.ifPresent(this::cause); + return this; + } + + /** + * Set the {@link Throwable} that caused the {@code DiscoveryIssue}. + * + * @param cause the {@link Throwable} that caused the + * {@code DiscoveryIssue}; may be {@code null} + */ + Builder cause(Throwable cause); + + /** + * Build the {@code DiscoveryIssue}. + */ + DiscoveryIssue build(); + + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.engine; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.Optional; @@ -33,15 +33,19 @@ /** * Return the {@linkplain DiscoverySelectorIdentifier identifier} of this * selector. - *

    - * The returned identifier has to be parsable by a corresponding + * + *

    The returned identifier must be parsable by a corresponding * {@link DiscoverySelectorIdentifierParser}. * - * @return the identifier of this selector or empty if it is not supported; - * never {@code null} + *

    The default implementation returns {@link Optional#empty()}. Can be + * overridden by concrete implementations. + * + * @return an {@link Optional} containing the identifier of this selector; + * never {@code null} but potentially empty if the selector does not support + * identifiers * @since 1.11 */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = MAINTAINED, since = "1.13.3") default Optional toIdentifier() { return Optional.empty(); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelectorIdentifier.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelectorIdentifier.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelectorIdentifier.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/DiscoverySelectorIdentifier.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.engine; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.util.Objects; @@ -20,24 +20,23 @@ import org.junit.platform.commons.util.StringUtils; /** - * Identifier for {@link DiscoverySelector DiscoverySelectors} with a specific - * prefix. - *

    - * The {@linkplain #toString() string representation} of an identifier is + * Identifier for a {@link DiscoverySelector} with a specific prefix. + * + *

    The {@linkplain #toString() string representation} of an identifier is * intended to be human-readable and is formatted as {@code prefix:value}. * * @since 1.11 * @see org.junit.platform.engine.discovery.DiscoverySelectors#parse(String) * @see org.junit.platform.engine.discovery.DiscoverySelectorIdentifierParser */ -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public final class DiscoverySelectorIdentifier { private final String prefix; private final String value; /** - * Create a new {@link DiscoverySelectorIdentifier} with the supplied prefix and + * Create a new {@code DiscoverySelectorIdentifier} with the supplied prefix and * value. * * @param prefix the prefix; never {@code null} or blank @@ -51,8 +50,8 @@ * Parse the supplied string representation of a * {@link DiscoverySelectorIdentifier} in the format {@code prefix:value}. * - * @param string the string representation of a {@link DiscoverySelectorIdentifier} - * @return the parsed {@link DiscoverySelectorIdentifier} + * @param string the string representation of a {@code DiscoverySelectorIdentifier} + * @return the parsed {@code DiscoverySelectorIdentifier} * @throws PreconditionViolationException if the supplied string does not * conform to the expected format */ @@ -74,7 +73,7 @@ * @return the prefix; never {@code null} or blank */ public String getPrefix() { - return prefix; + return this.prefix; } /** @@ -83,7 +82,7 @@ * @return the value; never {@code null} or blank */ public String getValue() { - return value; + return this.value; } @Override @@ -95,12 +94,12 @@ return false; } DiscoverySelectorIdentifier that = (DiscoverySelectorIdentifier) o; - return Objects.equals(prefix, that.prefix) && Objects.equals(value, that.value); + return Objects.equals(this.prefix, that.prefix) && Objects.equals(this.value, that.value); } @Override public int hashCode() { - return Objects.hash(prefix, value); + return Objects.hash(this.prefix, this.value); } /** @@ -109,6 +108,7 @@ */ @Override public String toString() { - return String.format("%s:%s", prefix, value); + return String.format("%s:%s", this.prefix, this.value); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,24 +10,22 @@ package org.junit.platform.engine; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; /** - * {@code EngineDiscoveryListener} contains {@link TestEngine} access to the - * information necessary to discover tests and containers. + * {@code EngineDiscoveryListener} defines the API which enables a {@link TestEngine} + * to publish information about events that occur during test discovery. * *

    All methods in this interface have empty default implementations. * Concrete implementations may therefore override one or more of these methods * to be notified of the selected events. * - *

    The methods declared in this interface should be called by - * each {@link TestEngine} during test discovery. However, since this interface - * was only added in 1.6, older engines might not yet do so. - * * @since 1.6 * @see EngineDiscoveryRequest#getDiscoveryListener() + * @see org.junit.platform.launcher.LauncherDiscoveryListener */ @API(status = STABLE, since = "1.10") public interface EngineDiscoveryListener { @@ -53,4 +51,17 @@ default void selectorProcessed(UniqueId engineId, DiscoverySelector selector, SelectorResolutionResult result) { } + /** + * Called when the engine with the supplied {@code engineId} encountered an + * issue during test discovery. + * + * @param engineId the unique ID of the engine descriptor + * @param issue the encountered issue + * @since 1.13 + * @see DiscoveryIssue + */ + @API(status = MAINTAINED, since = "1.13.3") + default void issueEncountered(UniqueId engineId, DiscoveryIssue issue) { + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryRequest.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryRequest.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryRequest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineDiscoveryRequest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,11 +10,14 @@ package org.junit.platform.engine; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.List; import org.apiguardian.api.API; +import org.junit.platform.commons.JUnitException; /** * {@code EngineDiscoveryRequest} provides a {@link TestEngine} access to the @@ -72,10 +75,6 @@ /** * Get the {@link EngineDiscoveryListener} for this request. * - *

    The default implementation returns a no-op listener that ignores all - * calls so that engines that call this methods can be used with an earlier - * version of the JUnit Platform that did not yet include this API. - * * @return the discovery listener; never {@code null} * @since 1.6 */ @@ -84,4 +83,31 @@ return EngineDiscoveryListener.NOOP; } + /** + * Get the + * {@link org.junit.platform.engine.reporting.OutputDirectoryProvider} for + * this request. + * + * @return the output directory provider; never {@code null} + * @since 1.12 + * @deprecated Please use {@link #getOutputDirectoryCreator()} instead + */ + @Deprecated + @API(status = DEPRECATED, since = "1.14") + default org.junit.platform.engine.reporting.OutputDirectoryProvider getOutputDirectoryProvider() { + return org.junit.platform.engine.reporting.OutputDirectoryProvider.castOrAdapt(getOutputDirectoryCreator()); + } + + /** + * Get the {@link OutputDirectoryCreator} for this request. + * + * @return the output directory creator; never {@code null} + * @since 1.14 + */ + @API(status = MAINTAINED, since = "1.14") + default OutputDirectoryCreator getOutputDirectoryCreator() { + throw new JUnitException( + "OutputDirectoryCreator not available; probably due to unaligned versions of the junit-platform-engine and junit-platform-launcher jars on the classpath/module path."); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/EngineExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,12 @@ package org.junit.platform.engine; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; import org.junit.platform.engine.TestExecutionResult.Status; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; /** @@ -55,7 +57,7 @@ * has been skipped. * *

    The {@link TestDescriptor} may represent a test or a container. In the - * case of a container, engines must not fire any additional events for its + * case of a container, an engine must not fire any additional events for its * descendants. * *

    A skipped test or subtree of tests must not be reported as @@ -74,11 +76,11 @@ * is about to be started. * *

    The {@link TestDescriptor} may represent a test or a container. In the - * case of a container, engines have to fire additional events for its + * case of a container, an engine must fire additional events for its * children. * - *

    This method may only be called if the test or container has not - * been {@linkplain #executionSkipped skipped}. + *

    This method may only be called if the test or container has not been + * {@linkplain #executionSkipped skipped}. * *

    This method must be called for a container {@code TestDescriptor} * before {@linkplain #executionStarted starting} or @@ -132,9 +134,31 @@ * * @param testDescriptor the descriptor of the test or container to which * the reporting entry belongs - * @param entry a {@code ReportEntry} instance to be published + * @param reportEntry the {@link ReportEntry} to be published + */ + default void reportingEntryPublished(TestDescriptor testDescriptor, ReportEntry reportEntry) { + } + + /** + * Can be called for any {@link TestDescriptor} in order to publish a file or + * directory by attaching it to a test or container — for example: + * + *

      + *
    • Screenshots
    • + *
    • Logs
    • + *
    • Output files written by the code under test
    • + *
    • Test output directory
    • + *
    + * + *

    The current lifecycle state of the supplied {@code TestDescriptor} is + * not relevant: file events can occur at any time. + * + * @param testDescriptor the descriptor of the test or container to which + * the file entry belongs + * @param fileEntry the {@link FileEntry} to be published */ - default void reportingEntryPublished(TestDescriptor testDescriptor, ReportEntry entry) { + @API(status = MAINTAINED, since = "1.13.3") + default void fileEntryPublished(TestDescriptor testDescriptor, FileEntry fileEntry) { } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ExecutionRequest.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ExecutionRequest.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ExecutionRequest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/ExecutionRequest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,19 +10,26 @@ package org.junit.platform.engine; +import static org.apiguardian.api.API.Status.DEPRECATED; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; /** * Provides a single {@link TestEngine} access to the information necessary to * execute its tests. * *

    A request contains an engine's root {@link TestDescriptor}, the - * {@link EngineExecutionListener} to be notified of test execution events, and + * {@link EngineExecutionListener} to be notified of test execution events, the * {@link ConfigurationParameters} that the engine may use to influence test - * execution. + * execution, and an {@link OutputDirectoryCreator} for writing reports and + * other output files. * * @since 1.0 * @see TestEngine @@ -31,17 +38,32 @@ public class ExecutionRequest { private final TestDescriptor rootTestDescriptor; - private final EngineExecutionListener engineExecutionListener; - private final ConfigurationParameters configurationParameters; + private final OutputDirectoryCreator outputDirectoryCreator; + private final NamespacedHierarchicalStore requestLevelStore; - @API(status = INTERNAL, since = "1.0") + /** + * @deprecated without replacement because it's an internal API. + */ + @Deprecated + @API(status = DEPRECATED, since = "1.11") public ExecutionRequest(TestDescriptor rootTestDescriptor, EngineExecutionListener engineExecutionListener, ConfigurationParameters configurationParameters) { - this.rootTestDescriptor = rootTestDescriptor; - this.engineExecutionListener = engineExecutionListener; - this.configurationParameters = configurationParameters; + this(rootTestDescriptor, engineExecutionListener, configurationParameters, null, null); + } + + private ExecutionRequest(TestDescriptor rootTestDescriptor, EngineExecutionListener engineExecutionListener, + ConfigurationParameters configurationParameters, OutputDirectoryCreator outputDirectoryCreator, + NamespacedHierarchicalStore requestLevelStore) { + + this.rootTestDescriptor = Preconditions.notNull(rootTestDescriptor, "rootTestDescriptor must not be null"); + this.engineExecutionListener = Preconditions.notNull(engineExecutionListener, + "engineExecutionListener must not be null"); + this.configurationParameters = Preconditions.notNull(configurationParameters, + "configurationParameters must not be null"); + this.outputDirectoryCreator = outputDirectoryCreator; + this.requestLevelStore = requestLevelStore; } /** @@ -54,16 +76,44 @@ * engine may use to influence test execution * @return a new {@code ExecutionRequest}; never {@code null} * @since 1.9 + * @deprecated without replacement */ - @API(status = STABLE, since = "1.9") + @Deprecated + @API(status = DEPRECATED, since = "1.11") public static ExecutionRequest create(TestDescriptor rootTestDescriptor, EngineExecutionListener engineExecutionListener, ConfigurationParameters configurationParameters) { return new ExecutionRequest(rootTestDescriptor, engineExecutionListener, configurationParameters); } /** - * Get the root {@link TestDescriptor} of the engine that processes this - * request. + * Factory for creating an execution request. + * + * @param rootTestDescriptor the engine's root {@link TestDescriptor}; never + * {@code null} + * @param engineExecutionListener the {@link EngineExecutionListener} to be + * notified of test execution events; never {@code null} + * @param configurationParameters {@link ConfigurationParameters} that the + * engine may use to influence test execution; never {@code null} + * @param outputDirectoryCreator {@link OutputDirectoryCreator} for + * writing reports and other output files; never {@code null} + * @param requestLevelStore {@link NamespacedHierarchicalStore} for storing + * request-scoped data; never {@code null} + * @return a new {@code ExecutionRequest}; never {@code null} + * @since 1.13 + */ + @API(status = INTERNAL, since = "1.13") + public static ExecutionRequest create(TestDescriptor rootTestDescriptor, + EngineExecutionListener engineExecutionListener, ConfigurationParameters configurationParameters, + OutputDirectoryCreator outputDirectoryCreator, NamespacedHierarchicalStore requestLevelStore) { + + return new ExecutionRequest(rootTestDescriptor, engineExecutionListener, configurationParameters, + Preconditions.notNull(outputDirectoryCreator, "outputDirectoryCreator must not be null"), + Preconditions.notNull(requestLevelStore, "requestLevelStore must not be null")); + } + + /** + * {@return the root {@link TestDescriptor} of the engine that processes this + * request} * *

    Note: the root descriptor is the * {@code TestDescriptor} returned by @@ -74,19 +124,66 @@ } /** - * Get the {@link EngineExecutionListener} to be notified of test execution - * events. + * {@return the {@link EngineExecutionListener} to be notified of test execution + * events} */ public EngineExecutionListener getEngineExecutionListener() { return this.engineExecutionListener; } /** - * Get the {@link ConfigurationParameters} that the engine may use to - * influence test execution. + * {@return the {@link ConfigurationParameters} that the engine may use to + * influence test execution} */ public ConfigurationParameters getConfigurationParameters() { return this.configurationParameters; } + /** + * {@return the + * {@link org.junit.platform.engine.reporting.OutputDirectoryProvider} for + * this request for writing reports and other output files} + * + * @throws PreconditionViolationException if the output directory provider + * is not available + * @since 1.12 + * @deprecated Please use {@link #getOutputDirectoryCreator()} instead + */ + @Deprecated + @API(status = DEPRECATED, since = "1.14") + public org.junit.platform.engine.reporting.OutputDirectoryProvider getOutputDirectoryProvider() { + return org.junit.platform.engine.reporting.OutputDirectoryProvider.castOrAdapt(getOutputDirectoryCreator()); + } + + /** + * {@return the {@link OutputDirectoryCreator} for this request for writing + * reports and other output files} + * + * @throws PreconditionViolationException if the output directory creator is + * not available + * @since 1.14 + */ + @API(status = MAINTAINED, since = "1.14") + public OutputDirectoryCreator getOutputDirectoryCreator() { + return Preconditions.notNull(this.outputDirectoryCreator, + "No OutputDirectoryCreator was configured for this request"); + } + + /** + * {@return the {@link NamespacedHierarchicalStore} for this request for + * storing request-scoped data} + * + *

    All stored values that implement {@link AutoCloseable} are notified by + * invoking their {@code close()} methods when this request has been + * executed. + * + * @since 1.13 + * @see NamespacedHierarchicalStore + */ + @API(status = MAINTAINED, since = "1.13.3") + public NamespacedHierarchicalStore getStore() { + return Preconditions.notNull(this.requestLevelStore, + "No NamespacedHierarchicalStore was configured for this request"); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/Filter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/Filter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/Filter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/Filter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/FilterResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/FilterResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/FilterResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/FilterResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/OutputDirectoryCreator.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/OutputDirectoryCreator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/OutputDirectoryCreator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/OutputDirectoryCreator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.io.IOException; +import java.nio.file.Path; + +import org.apiguardian.api.API; + +/** + * Provider of output directories for test engines to write reports and other + * output files to. + * + * @since 1.14 + * @see EngineDiscoveryRequest#getOutputDirectoryCreator() + */ +@API(status = MAINTAINED, since = "1.14") +public interface OutputDirectoryCreator { + + /** + * {@return the root directory for all output files; never {@code null}} + */ + Path getRootDirectory(); + + /** + * Create an output directory for the supplied test descriptor. + * + * @param testDescriptor the test descriptor for which to create an output + * directory; never {@code null} + * @return the output directory + * @throws IOException if the output directory could not be created + */ + Path createOutputDirectory(TestDescriptor testDescriptor) throws IOException; + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/SelectorResolutionResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/SelectorResolutionResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/SelectorResolutionResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/SelectorResolutionResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -115,11 +115,11 @@ @Override public String toString() { // @formatter:off - return new ToStringBuilder(this) - .append("status", status) - .append("throwable", throwable) - .toString(); - // @formatter:on + return new ToStringBuilder(this) + .append("status", status) + .append("throwable", throwable) + .toString(); + // @formatter:on } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,12 +10,16 @@ package org.junit.platform.engine; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; import org.junit.platform.commons.util.Preconditions; @@ -173,6 +177,39 @@ void removeFromHierarchy(); /** + * Order the children of this descriptor. + * + *

    The {@code orderer} is provided a modifiable list of child test + * descriptors of this test descriptor; never {@code null}. The + * {@code orderer} must return a list containing the same descriptors in any + * order; potentially the same list, but never {@code null}. If descriptors + * are added or removed, an exception is thrown. + * + * @param orderer a unary operator to order the children of this test descriptor + * @since 1.12 + */ + @API(status = MAINTAINED, since = "1.13.3") + default void orderChildren(UnaryOperator> orderer) { + Preconditions.notNull(orderer, "orderer must not be null"); + Set originalChildren = getChildren(); + List suggestedOrder = orderer.apply(new ArrayList<>(originalChildren)); + Preconditions.notNull(suggestedOrder, "orderer may not return null"); + + Set orderedChildren = new LinkedHashSet<>(suggestedOrder); + boolean unmodified = originalChildren.equals(orderedChildren); + Preconditions.condition(unmodified && originalChildren.size() == suggestedOrder.size(), + "orderer may not add or remove test descriptors"); + + suggestedOrder.stream() // + .distinct() // + .filter(originalChildren::contains)// + .forEach(testDescriptor -> { + removeChild(testDescriptor); + addChild(testDescriptor); + }); + } + + /** * Determine if this descriptor is a root descriptor. * *

    A root descriptor is a descriptor without a parent. @@ -283,6 +320,25 @@ interface Visitor { /** + * Combine the supplied {@code visitors} into a single {@code Visitor}. + * + *

    If the supplied array contains only a single {@code Visitor}, that + * {@code Visitor} is returned as is. + * + * @param visitors the {@code Visitor}s to combine; never {@code null} + * or empty + * @return the combined {@code Visitor} + * @throws org.junit.platform.commons.PreconditionViolationException if + * {@code visitors} is {@code null}, contains {@code null} elements, or + * is empty + * @since 1.13 + */ + @API(status = MAINTAINED, since = "1.13.3") + static Visitor composite(Visitor... visitors) { + return CompositeTestDescriptorVisitor.from(visitors); + } + + /** * Visit a {@link TestDescriptor}. * * @param descriptor the {@code TestDescriptor} to visit; never {@code null} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -67,6 +67,10 @@ * must be used to create unique IDs for children of the root's descriptor * by calling {@link UniqueId#append}. * + *

    Furthermore, implementations must publish events about test discovery + * via the supplied {@link EngineDiscoveryRequest#getDiscoveryListener() + * EngineDiscoveryListener}. + * * @param discoveryRequest the discovery request; never {@code null} * @param uniqueId the unique ID to be used for this test engine's * {@code TestDescriptor}; never {@code null} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestExecutionResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestExecutionResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestExecutionResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestExecutionResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestTag.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestTag.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestTag.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/TestTag.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueIdFormat.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueIdFormat.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueIdFormat.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueIdFormat.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/AbstractClassNameFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/AbstractClassNameFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/AbstractClassNameFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/AbstractClassNameFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassNameFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassNameFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassNameFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassNameFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClassSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,8 +10,8 @@ package org.junit.platform.engine.discovery; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.Objects; @@ -20,7 +20,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.DiscoverySelectorIdentifier; @@ -69,7 +69,7 @@ * @return the {@code ClassLoader}; potentially {@code null} * @since 1.10 */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public ClassLoader getClassLoader() { return this.classLoader; } @@ -92,8 +92,8 @@ if (this.javaClass == null) { // @formatter:off Try> tryToLoadClass = this.classLoader == null - ? ReflectionUtils.tryToLoadClass(this.className) - : ReflectionUtils.tryToLoadClass(this.className, this.classLoader); + ? ReflectionSupport.tryToLoadClass(this.className) + : ReflectionSupport.tryToLoadClass(this.className, this.classLoader); this.javaClass = tryToLoadClass.getOrThrow(cause -> new PreconditionViolationException("Could not load class with name: " + this.className, cause)); // @formatter:on @@ -162,5 +162,7 @@ public Optional parse(DiscoverySelectorIdentifier identifier, Context context) { return Optional.of(DiscoverySelectors.selectClass(identifier.getValue())); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,13 +10,24 @@ package org.junit.platform.engine.discovery; +import static java.util.Collections.unmodifiableSet; +import static java.util.stream.Collectors.toCollection; +import static org.apiguardian.api.API.Status.DEPRECATED; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; +import java.util.LinkedHashSet; import java.util.Objects; import java.util.Optional; +import java.util.Set; import org.apiguardian.api.API; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.support.ResourceSupport; +import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.DiscoverySelector; @@ -34,6 +45,10 @@ * {@linkplain Thread#getContextClassLoader() context class loader} of the * {@linkplain Thread thread} that uses it. * + *

    Note: Since Java 9, all resources are on the module path. Either in + * named or unnamed modules. These resources are also considered to be + * classpath resources. + * * @since 1.0 * @see DiscoverySelectors#selectClasspathResource(String) * @see ClasspathRootSelector @@ -44,13 +59,21 @@ private final String classpathResourceName; private final FilePosition position; + private Set resources; ClasspathResourceSelector(String classpathResourceName, FilePosition position) { boolean startsWithSlash = classpathResourceName.startsWith("/"); this.classpathResourceName = (startsWithSlash ? classpathResourceName.substring(1) : classpathResourceName); + Preconditions.notBlank(this.classpathResourceName, + "classpath resource name must not be blank after removing leading slash"); this.position = position; } + ClasspathResourceSelector(Set resources) { + this(resources.iterator().next().getName(), null); + this.resources = unmodifiableSet(new LinkedHashSet<>(resources)); + } + /** * Get the name of the selected classpath resource. * @@ -66,6 +89,51 @@ } /** + * Get the selected {@link Resource resources}. + * + *

    If the {@link Resource resources} were not provided, but only their name, + * this method attempts to lazily load the {@link Resource resources} based on + * their name and throws a {@link PreconditionViolationException} if the + * resource cannot be loaded. + * + * @since 1.12 + * @deprecated Please use {{@link #getResources()}} instead. + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + public Set getClasspathResources() { + return getResources().stream() // + .map(org.junit.platform.commons.support.Resource::of) // + .collect(toCollection(LinkedHashSet::new)); + } + + /** + * Get the selected {@link Resource resources}. + * + *

    If the {@link Resource resources} were not provided, but only their name, + * this method attempts to lazily load the {@link Resource resources} based on + * their name and throws a {@link PreconditionViolationException} if the + * resource cannot be loaded. + * + * @since 1.14 + */ + @API(status = MAINTAINED, since = "1.14") + public Set getResources() { + if (this.resources == null) { + Try> tryToGetResource = ResourceSupport.tryToGetResources(this.classpathResourceName); + Set classpathResources = tryToGetResource.getOrThrow( // + cause -> new PreconditionViolationException( // + "Could not load resource(s) with name: " + this.classpathResourceName, cause)); + if (classpathResources.isEmpty()) { + throw new PreconditionViolationException( + "Could not find any resource(s) with name: " + this.classpathResourceName); + } + this.resources = unmodifiableSet(classpathResources); + } + return this.resources; + } + + /** * Get the selected {@code FilePosition} within the classpath resource. */ public Optional getPosition() { @@ -100,8 +168,12 @@ @Override public String toString() { - return new ToStringBuilder(this).append("classpathResourceName", this.classpathResourceName).append("position", - this.position).toString(); + // @formatter:off + return new ToStringBuilder(this) + .append("classpathResourceName", this.classpathResourceName) + .append("position", this.position) + .toString(); + // @formatter:on } @Override @@ -142,5 +214,7 @@ } // )); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathRootSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathRootSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathRootSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathRootSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -117,5 +117,7 @@ Path path = Paths.get(URI.create(identifier.getValue())); return getFirstElement(DiscoverySelectors.selectClasspathRoots(singleton(path))); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DirectorySelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DirectorySelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DirectorySelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DirectorySelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -136,5 +136,7 @@ public Optional parse(DiscoverySelectorIdentifier identifier, Context context) { return Optional.of(DiscoverySelectors.selectDirectory(identifier.getValue())); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParser.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParser.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParser.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParser.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.engine.discovery; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.util.Optional; @@ -19,36 +19,36 @@ import org.junit.platform.engine.DiscoverySelectorIdentifier; /** - * Parser for {@link DiscoverySelectorIdentifier DiscoverySelectorIdentifiers} - * with a specific prefix. - *

    - * Implementations of this interface can be registered using the Java service + * Parser for a {@link DiscoverySelectorIdentifier} with a specific prefix. + * + *

    Implementations of this interface can be registered using the Java service * loader mechanism to extend the set of supported prefixes for * {@link DiscoverySelectorIdentifier DiscoverySelectorIdentifiers}. * * @since 1.11 * @see DiscoverySelectors#parse(String) */ -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public interface DiscoverySelectorIdentifierParser { /** - * Get the prefix that this parser can handle. + * Get the prefix that this parser supports. * - * @return the prefix that this parser can handle; never {@code null} + * @return the prefix that this parser supports; never {@code null} or blank */ String getPrefix(); /** * Parse the supplied {@link DiscoverySelectorIdentifier}. - *

    - * The JUnit Platform will only invoke this method if the supplied + * + *

    The JUnit Platform will only invoke this method if the supplied * {@link DiscoverySelectorIdentifier} has a prefix that matches the value * returned by {@link #getPrefix()}. * * @param identifier the {@link DiscoverySelectorIdentifier} to parse * @param context the {@link Context} to use for parsing - * @return an {@link Optional} containing the parsed {@link DiscoverySelector}; never {@code null} + * @return an {@link Optional} containing the parsed {@link DiscoverySelector}; + * never {@code null} but potentially empty */ Optional parse(DiscoverySelectorIdentifier identifier, Context context); @@ -59,8 +59,8 @@ /** * Parse the supplied selector. - *

    - * This method is intended to be used by implementations of + * + *

    This method is intended to be used by implementations of * {@link DiscoverySelectorIdentifierParser#parse} for selectors that * contain other selectors. */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParsers.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParsers.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParsers.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectorIdentifierParsers.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -75,11 +75,13 @@ for (DiscoverySelectorIdentifierParser parser : loadedParsers) { DiscoverySelectorIdentifierParser previous = parsersByPrefix.put(parser.getPrefix(), parser); Preconditions.condition(previous == null, - () -> String.format("Duplicate parser for prefix: [%s] candidate a: [%s] candidate b: [%s] ", + () -> String.format("Duplicate parser for prefix: [%s]; candidate a: [%s]; candidate b: [%s]", parser.getPrefix(), requireNonNull(previous).getClass().getName(), parser.getClass().getName())); } this.parsersByPrefix = unmodifiableMap(parsersByPrefix); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,9 @@ package org.junit.platform.engine.discovery; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static java.util.stream.Collectors.toList; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; @@ -29,6 +31,8 @@ import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.engine.DiscoverySelector; @@ -281,6 +285,7 @@ * @param classpathResourceName the name of the classpath resource; never * {@code null} or blank * @see #selectClasspathResource(String, FilePosition) + * @see #selectClasspathResourceByName(Set) * @see ClasspathResourceSelector * @see ClassLoader#getResource(String) * @see ClassLoader#getResourceAsStream(String) @@ -310,6 +315,7 @@ * {@code null} or blank * @param position the position inside the classpath resource; may be {@code null} * @see #selectClasspathResource(String) + * @see #selectClasspathResourceByName(Set) * @see ClasspathResourceSelector * @see ClassLoader#getResource(String) * @see ClassLoader#getResourceAsStream(String) @@ -317,11 +323,82 @@ */ public static ClasspathResourceSelector selectClasspathResource(String classpathResourceName, FilePosition position) { - Preconditions.notBlank(classpathResourceName, "Classpath resource name must not be null or blank"); + Preconditions.notBlank(classpathResourceName, "classpath resource name must not be null or blank"); return new ClasspathResourceSelector(classpathResourceName, position); } /** + * Create a {@code ClasspathResourceSelector} for the supplied classpath + * resources. + * + *

    Since {@linkplain org.junit.platform.engine.TestEngine engines} are not + * expected to modify the classpath, the supplied resource must be on the + * classpath of the + * {@linkplain Thread#getContextClassLoader() context class loader} of the + * {@linkplain Thread thread} that uses the resulting selector. + * + *

    Note: Since Java 9, all resources are on the module path. Either in + * named or unnamed modules. These resources are also considered to be + * classpath resources. + * + * @param classpathResources a set of classpath resources; never + * {@code null} or empty. All resources must have the same name, may not + * be {@code null} or blank. + * @since 1.12 + * @see #selectClasspathResource(String, FilePosition) + * @see #selectClasspathResource(String) + * @see ClasspathResourceSelector + * @see ReflectionSupport#tryToGetResources(String) + * @deprecated Please use {@link #selectClasspathResourceByName(Set)} instead. + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + public static ClasspathResourceSelector selectClasspathResource( + Set classpathResources) { + return selectClasspathResourceByName(classpathResources); + } + + /** + * Create a {@code ClasspathResourceSelector} for the supplied classpath + * resources. + * + *

    Since {@linkplain org.junit.platform.engine.TestEngine engines} are not + * expected to modify the classpath, the supplied resource must be on the + * classpath of the + * {@linkplain Thread#getContextClassLoader() context class loader} of the + * {@linkplain Thread thread} that uses the resulting selector. + * + *

    Note: Since Java 9, all resources are on the module path. Either in + * named or unnamed modules. These resources are also considered to be + * classpath resources. + * + *

    The {@link Set} supplied to this method should have a reliable iteration + * order to support reliable discovery and execution order. It is therefore + * recommended that the set be a {@link java.util.SequencedSet} (on Java 21 + * or higher), {@link java.util.SortedSet}, {@link java.util.LinkedHashSet}, + * or similar. Note that {@link Set#of(Object[])} and related {@code Set.of()} + * methods do not guarantee a reliable iteration order. + * + * @param classpathResources a set of classpath resources; never + * {@code null} or empty. All resources must have the same name, may not + * be {@code null} or blank. + * @since 1.14 + * @see #selectClasspathResource(String, FilePosition) + * @see #selectClasspathResource(String) + * @see ClasspathResourceSelector + * @see org.junit.platform.commons.support.ResourceSupport#tryToGetResources(String) + */ + @API(status = MAINTAINED, since = "1.14") + public static ClasspathResourceSelector selectClasspathResourceByName(Set classpathResources) { + Preconditions.notEmpty(classpathResources, "classpath resources must not be null or empty"); + Preconditions.containsNoNullElements(classpathResources, "individual classpath resources must not be null"); + List resourceNames = classpathResources.stream().map(Resource::getName).distinct().collect(toList()); + Preconditions.condition(resourceNames.size() == 1, "all classpath resources must have the same name"); + Preconditions.notBlank(resourceNames.get(0), "classpath resource names must not be null or blank"); + return new ClasspathResourceSelector(classpathResources); + } + + /** * Create a {@code ModuleSelector} for the supplied module name. * *

    The unnamed module is not supported. @@ -407,7 +484,7 @@ * @since 1.10 * @see ClassSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static ClassSelector selectClass(ClassLoader classLoader, String className) { Preconditions.notBlank(className, "Class name must not be null or blank"); return new ClassSelector(classLoader, className); @@ -475,7 +552,7 @@ * @see #selectMethod(String) * @see MethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static MethodSelector selectMethod(ClassLoader classLoader, String fullyQualifiedMethodName) throws PreconditionViolationException { String[] methodParts = ReflectionUtils.parseFullyQualifiedMethodName(fullyQualifiedMethodName); @@ -507,7 +584,7 @@ * @since 1.10 * @see MethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static MethodSelector selectMethod(ClassLoader classLoader, String className, String methodName) { return selectMethod(classLoader, className, methodName, ""); } @@ -551,7 +628,7 @@ * @since 1.10 * @see MethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static MethodSelector selectMethod(ClassLoader classLoader, String className, String methodName, String parameterTypeNames) { Preconditions.notBlank(className, "Class name must not be null or blank"); @@ -607,7 +684,7 @@ * @since 1.10 * @see MethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static MethodSelector selectMethod(String className, String methodName, Class... parameterTypes) { Preconditions.notBlank(className, "Class name must not be null or blank"); Preconditions.notBlank(methodName, "Method name must not be null or blank"); @@ -628,7 +705,7 @@ * @since 1.10 * @see MethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static MethodSelector selectMethod(Class javaClass, String methodName, Class... parameterTypes) { Preconditions.notNull(javaClass, "Class must not be null"); Preconditions.notBlank(methodName, "Method name must not be null or blank"); @@ -692,7 +769,7 @@ * @since 1.10 * @see NestedClassSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static NestedClassSelector selectNestedClass(ClassLoader classLoader, List enclosingClassNames, String nestedClassName) { Preconditions.notEmpty(enclosingClassNames, "Enclosing class names must not be null or empty"); @@ -728,7 +805,7 @@ * @since 1.10 * @see NestedMethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static NestedMethodSelector selectNestedMethod(ClassLoader classLoader, List enclosingClassNames, String nestedClassName, String methodName) throws PreconditionViolationException { Preconditions.notEmpty(enclosingClassNames, "Enclosing class names must not be null or empty"); @@ -776,7 +853,7 @@ * @since 1.10 * @see #selectNestedMethod(List, String, String, String) */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static NestedMethodSelector selectNestedMethod(ClassLoader classLoader, List enclosingClassNames, String nestedClassName, String methodName, String parameterTypeNames) { @@ -802,7 +879,7 @@ * @since 1.10 * @see NestedMethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static NestedMethodSelector selectNestedMethod(List enclosingClassNames, String nestedClassName, String methodName, Class... parameterTypes) { @@ -871,7 +948,7 @@ * @since 1.10 * @see NestedMethodSelector */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static NestedMethodSelector selectNestedMethod(List> enclosingClasses, Class nestedClass, String methodName, Class... parameterTypes) { @@ -930,12 +1007,12 @@ * * @param parentSelector the parent selector to select iterations for; never * {@code null} - * @param iterationIndices the iteration indices to select; never - * {@code null} or empty + * @param iterationIndices the iteration indices to select; never {@code null} + * or empty * @since 1.9 * @see IterationSelector */ - @API(status = EXPERIMENTAL, since = "1.9") + @API(status = MAINTAINED, since = "1.13.3") public static IterationSelector selectIteration(DiscoverySelector parentSelector, int... iterationIndices) { Preconditions.notNull(parentSelector, "Parent selector must not be null"); Preconditions.notEmpty(iterationIndices, "iteration indices must not be empty"); @@ -943,15 +1020,16 @@ } /** - * Parse the supplied string representation of a - * {@link DiscoverySelectorIdentifier}. + * Parse the supplied string representation of a {@link DiscoverySelectorIdentifier}. * * @param identifier the string representation of a {@code DiscoverySelectorIdentifier}; * never {@code null} or blank + * @return an {@link Optional} containing the corresponding {@link DiscoverySelector}; + * never {@code null} but potentially empty * @since 1.11 * @see DiscoverySelectorIdentifierParser */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = MAINTAINED, since = "1.13.3") public static Optional parse(String identifier) { return DiscoverySelectorIdentifierParsers.parse(identifier); } @@ -961,10 +1039,12 @@ * * @param identifier the {@code DiscoverySelectorIdentifier} to parse; * never {@code null} + * @return an {@link Optional} containing the corresponding {@link DiscoverySelector}; + * never {@code null} but potentially empty * @since 1.11 * @see DiscoverySelectorIdentifierParser */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = MAINTAINED, since = "1.13.3") public static Optional parse(DiscoverySelectorIdentifier identifier) { return DiscoverySelectorIdentifierParsers.parse(identifier); } @@ -975,10 +1055,12 @@ * * @param identifiers the string representations of * {@code DiscoverySelectorIdentifiers} to parse; never {@code null} + * @return a stream of the corresponding {@link DiscoverySelector DiscoverySelectors}; + * never {@code null} but potentially empty * @since 1.11 * @see DiscoverySelectorIdentifierParser */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = MAINTAINED, since = "1.13.3") public static Stream parseAll(String... identifiers) { return DiscoverySelectorIdentifierParsers.parseAll(identifiers); } @@ -989,11 +1071,14 @@ * * @param identifiers the {@code DiscoverySelectorIdentifiers} to parse; * never {@code null} + * @return a stream of the corresponding {@link DiscoverySelector DiscoverySelectors}; + * never {@code null} but potentially empty * @since 1.11 * @see DiscoverySelectorIdentifierParser */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = MAINTAINED, since = "1.13.3") public static Stream parseAll(Collection identifiers) { return DiscoverySelectorIdentifierParsers.parseAll(identifiers); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludeClassNameFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludeClassNameFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludeClassNameFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludeClassNameFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludePackageNameFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludePackageNameFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludePackageNameFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ExcludePackageNameFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FilePosition.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FilePosition.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FilePosition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FilePosition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FileSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FileSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FileSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/FileSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -112,7 +112,7 @@ @API(status = STABLE, since = "1.3") @Override public int hashCode() { - return Objects.hash(path, position); + return Objects.hash(this.path, this.position); } @Override @@ -158,5 +158,7 @@ } // )); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludeClassNameFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludeClassNameFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludeClassNameFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludeClassNameFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludePackageNameFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludePackageNameFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludePackageNameFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IncludePackageNameFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IterationSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IterationSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IterationSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/IterationSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,8 +13,8 @@ import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toCollection; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.util.ArrayList; import java.util.Arrays; @@ -44,7 +44,7 @@ * @since 1.9 * @see DiscoverySelectors#selectIteration(DiscoverySelector, int...) */ -@API(status = EXPERIMENTAL, since = "1.9") +@API(status = MAINTAINED, since = "1.13.3") public class IterationSelector implements DiscoverySelector { private final DiscoverySelector parentSelector; @@ -65,14 +65,14 @@ * Get the selected parent {@link DiscoverySelector}. */ public DiscoverySelector getParentSelector() { - return parentSelector; + return this.parentSelector; } /** * Get the selected iteration indices. */ public SortedSet getIterationIndices() { - return iterationIndices; + return this.iterationIndices; } @Override @@ -84,12 +84,12 @@ return false; } IterationSelector that = (IterationSelector) o; - return parentSelector.equals(that.parentSelector) && iterationIndices.equals(that.iterationIndices); + return this.parentSelector.equals(that.parentSelector) && this.iterationIndices.equals(that.iterationIndices); } @Override public int hashCode() { - return Objects.hash(parentSelector, iterationIndices); + return Objects.hash(this.parentSelector, this.iterationIndices); } @Override @@ -104,13 +104,14 @@ @Override public Optional toIdentifier() { - return parentSelector.toIdentifier().map(parentSelectorString -> DiscoverySelectorIdentifier.create( // + return this.parentSelector.toIdentifier().map(parentSelectorString -> DiscoverySelectorIdentifier.create( // IdentifierParser.PREFIX, // String.format("%s[%s]", parentSelectorString, formatIterationIndicesAsRanges())) // ); } private String formatIterationIndicesAsRanges() { + class Range { final int start; int end; @@ -120,10 +121,11 @@ this.end = start; } } + List ranges = new ArrayList<>(); - Range current = new Range(iterationIndices.first()); + Range current = new Range(this.iterationIndices.first()); ranges.add(current); - for (int n : iterationIndices.tailSet(current.start + 1)) { + for (int n : this.iterationIndices.tailSet(current.start + 1)) { if (n == current.end + 1) { current.end = n; } @@ -133,14 +135,14 @@ } } return ranges.stream() // - .map(r -> { - if (r.start == r.end) { - return String.valueOf(r.start); + .map(range -> { + if (range.start == range.end) { + return String.valueOf(range.start); } - if (r.start == r.end - 1) { - return r.start + "," + r.end; + if (range.start == range.end - 1) { + return range.start + "," + range.end; } - return r.start + ".." + r.end; + return range.start + ".." + range.end; }) // .collect(joining(",")); } @@ -185,5 +187,7 @@ Integer.parseInt(lastIndex))// ); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/MethodSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/MethodSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/MethodSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/MethodSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,8 +11,8 @@ package org.junit.platform.engine.discovery; import static org.apiguardian.api.API.Status.DEPRECATED; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.reflect.Method; @@ -23,6 +23,7 @@ import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.ToStringBuilder; @@ -79,44 +80,38 @@ } MethodSelector(Class javaClass, String methodName, String parameterTypeNames) { - this.classLoader = javaClass.getClassLoader(); + this(javaClass.getClassLoader(), javaClass.getName(), methodName, parameterTypeNames); this.javaClass = javaClass; - this.className = javaClass.getName(); - this.methodName = methodName; - this.parameterTypeNames = parameterTypeNames; } /** * @since 1.10 */ MethodSelector(ClassLoader classLoader, String className, String methodName, Class... parameterTypes) { - this.classLoader = classLoader; - this.className = className; - this.methodName = methodName; + this(classLoader, className, methodName, ClassUtils.nullSafeToString(Class::getTypeName, parameterTypes)); this.parameterTypes = parameterTypes.clone(); - this.parameterTypeNames = ClassUtils.nullSafeToString(Class::getTypeName, this.parameterTypes); } /** * @since 1.10 */ MethodSelector(Class javaClass, String methodName, Class... parameterTypes) { - this.classLoader = javaClass.getClassLoader(); + this(javaClass.getClassLoader(), javaClass.getName(), methodName, + ClassUtils.nullSafeToString(Class::getTypeName, parameterTypes)); this.javaClass = javaClass; - this.className = javaClass.getName(); - this.methodName = methodName; this.parameterTypes = parameterTypes.clone(); - this.parameterTypeNames = ClassUtils.nullSafeToString(Class::getTypeName, this.parameterTypes); } MethodSelector(Class javaClass, Method method) { - this.classLoader = javaClass.getClassLoader(); + this(javaClass, method, method.getParameterTypes()); + } + + private MethodSelector(Class javaClass, Method method, Class... parameterTypes) { + this(javaClass.getClassLoader(), javaClass.getName(), method.getName(), + ClassUtils.nullSafeToString(Class::getTypeName, parameterTypes)); this.javaClass = javaClass; - this.className = javaClass.getName(); this.javaMethod = method; - this.methodName = method.getName(); - this.parameterTypes = method.getParameterTypes(); - this.parameterTypeNames = ClassUtils.nullSafeToString(Class::getTypeName, this.parameterTypes); + this.parameterTypes = parameterTypes; } /** @@ -125,7 +120,7 @@ * @return the {@code ClassLoader}; potentially {@code null} * @since 1.10 */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public ClassLoader getClassLoader() { return this.classLoader; } @@ -226,7 +221,7 @@ * @see #getParameterTypeNames() * @see Method#getParameterTypes() */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public Class[] getParameterTypes() { lazyLoadParameterTypes(); return this.parameterTypes.clone(); @@ -236,8 +231,8 @@ // @formatter:off if (this.javaClass == null) { Try> tryToLoadClass = this.classLoader == null - ? ReflectionUtils.tryToLoadClass(this.className) - : ReflectionUtils.tryToLoadClass(this.className, this.classLoader); + ? ReflectionSupport.tryToLoadClass(this.className) + : ReflectionSupport.tryToLoadClass(this.className, this.classLoader); this.javaClass = tryToLoadClass.getOrThrow(cause -> new PreconditionViolationException("Could not load class with name: " + this.className, cause)); } @@ -249,14 +244,14 @@ lazyLoadJavaClass(); lazyLoadParameterTypes(); if (this.parameterTypes.length > 0) { - this.javaMethod = ReflectionUtils.findMethod(this.javaClass, this.methodName, + this.javaMethod = ReflectionSupport.findMethod(this.javaClass, this.methodName, this.parameterTypes).orElseThrow( () -> new PreconditionViolationException(String.format( "Could not find method with name [%s] and parameter types [%s] in class [%s].", this.methodName, this.parameterTypeNames, this.javaClass.getName()))); } else { - this.javaMethod = ReflectionUtils.findMethod(this.javaClass, this.methodName).orElseThrow( + this.javaMethod = ReflectionSupport.findMethod(this.javaClass, this.methodName).orElseThrow( () -> new PreconditionViolationException( String.format("Could not find method with name [%s] in class [%s].", this.methodName, this.javaClass.getName()))); @@ -341,4 +336,5 @@ } } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ModuleSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ModuleSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ModuleSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ModuleSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -102,5 +102,7 @@ public Optional parse(DiscoverySelectorIdentifier identifier, Context context) { return Optional.of(DiscoverySelectors.selectModule(identifier.getValue())); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedClassSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedClassSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedClassSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedClassSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,8 +12,8 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; @@ -78,7 +78,7 @@ * @return the {@code ClassLoader}; potentially {@code null} * @since 1.10 */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public ClassLoader getClassLoader() { return this.classLoader; } @@ -180,5 +180,7 @@ return Optional.of( DiscoverySelectors.selectNestedClass(parts.subList(0, parts.size() - 1), parts.get(parts.size() - 1))); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedMethodSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedMethodSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedMethodSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/NestedMethodSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,8 +11,8 @@ package org.junit.platform.engine.discovery; import static org.apiguardian.api.API.Status.DEPRECATED; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.lang.reflect.Method; @@ -29,15 +29,14 @@ import org.junit.platform.engine.DiscoverySelectorIdentifier; /** - * A {@link DiscoverySelector} that selects a nested {@link Method} - * or a combination of enclosing classes names, class name, method - * name, and parameter types so that - * {@link org.junit.platform.engine.TestEngine TestEngines} can discover - * tests or containers based on methods. + * A {@link DiscoverySelector} that selects a nested {@link Method} or a + * combination of enclosing class names, class name, method name, and parameter + * types so that {@link org.junit.platform.engine.TestEngine TestEngines} can + * discover tests or containers based on methods. * *

    If a Java {@link Method} is provided, the selector will return that * {@linkplain #getMethod() method} and its method name, class name, enclosing - * classes names, and parameter types accordingly. If class names or method names + * class names, and parameter types accordingly. If class names or method names * are provided, this selector will only attempt to lazily load a class or method * if {@link #getEnclosingClasses()}, {@link #getNestedClass()}, * {@link #getMethod()}, or {@link #getParameterTypes()} is invoked. @@ -102,7 +101,7 @@ * * @since 1.10 */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public ClassLoader getClassLoader() { return this.nestedClassSelector.getClassLoader(); } @@ -210,7 +209,7 @@ * @see #getParameterTypeNames() * @see MethodSelector#getParameterTypes() */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public Class[] getParameterTypes() { return this.methodSelector.getParameterTypes(); } @@ -284,5 +283,7 @@ return Optional.of(DiscoverySelectors.selectNestedMethod(enclosingClassNames, nestedClassName, methodName, parameterTypeNames)); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageNameFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageNameFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageNameFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageNameFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/PackageSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -102,5 +102,7 @@ public Optional parse(DiscoverySelectorIdentifier identifier, Context context) { return Optional.of(DiscoverySelectors.selectPackage(identifier.getValue())); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UniqueIdSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UniqueIdSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UniqueIdSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UniqueIdSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -103,5 +103,7 @@ public Optional parse(DiscoverySelectorIdentifier identifier, Context context) { return Optional.of(DiscoverySelectors.selectUniqueId(identifier.getValue())); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UriSelector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UriSelector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UriSelector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/UriSelector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -106,5 +106,7 @@ public Optional parse(DiscoverySelectorIdentifier identifier, Context context) { return Optional.of(DiscoverySelectors.selectUri(identifier.getValue())); } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/FileEntry.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/FileEntry.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/FileEntry.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/FileEntry.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.reporting; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.util.Optional; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ToStringBuilder; + +/** + * {@code FileEntry} encapsulates a file or directory to be published to the + * reporting infrastructure. + * + * @since 1.12 + * @see #from(Path, String) + */ +@API(status = MAINTAINED, since = "1.13.3") +public final class FileEntry { + + /** + * Factory for creating a new {@code FileEntry} from the supplied path and + * media type. + * + *

    The {@link Path} may represent a file or a directory. + * + * @param path the path to publish; never {@code null} + * @param mediaType the media type of the path to publish; may be + * {@code null} — for example, if the path represents a directory + */ + public static FileEntry from(Path path, String mediaType) { + return new FileEntry(path, mediaType); + } + + private final LocalDateTime timestamp = LocalDateTime.now(); + private final Path path; + private final String mediaType; + + private FileEntry(Path path, String mediaType) { + this.path = Preconditions.notNull(path, "path must not be null"); + this.mediaType = mediaType; + } + + /** + * Get the timestamp for when this {@code FileEntry} was created. + * + * @return when this entry was created; never {@code null} + */ + public LocalDateTime getTimestamp() { + return this.timestamp; + } + + /** + * Get the path for the file or directory to be published. + * + * @return the path to publish; never {@code null} + */ + public Path getPath() { + return path; + } + + /** + * Get the media type of the path to be published. + * + * @return the media type of the path to publish; never {@code null} but + * potentially empty — for example, if the path represents a directory + */ + public Optional getMediaType() { + return Optional.ofNullable(mediaType); + } + + @Override + public String toString() { + ToStringBuilder builder = new ToStringBuilder(this); + builder.append("timestamp", this.timestamp); + builder.append("path", this.path); + if (this.mediaType != null) { + builder.append("mediaType", this.mediaType); + } + return builder.toString(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProvider.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.reporting; + +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.INTERNAL; + +import org.apiguardian.api.API; +import org.junit.platform.engine.EngineDiscoveryRequest; +import org.junit.platform.engine.OutputDirectoryCreator; + +/** + * Provider of output directories for test engines to write reports and other + * output files to. + * + * @since 1.12 + * @see EngineDiscoveryRequest#getOutputDirectoryProvider() + * @deprecated Please implement {@link OutputDirectoryCreator} instead + */ +@Deprecated +@API(status = DEPRECATED, since = "1.14") +public interface OutputDirectoryProvider extends OutputDirectoryCreator { + + /** + * Cast or adapt an {@link OutputDirectoryCreator} to a + * {@code OutputDirectoryProvider}. + * + * @since 1.14 + */ + @API(status = INTERNAL, since = "1.14") + static OutputDirectoryProvider castOrAdapt(OutputDirectoryCreator outputDirectoryCreator) { + if (outputDirectoryCreator instanceof OutputDirectoryProvider) { + return (OutputDirectoryProvider) outputDirectoryCreator; + } + return new OutputDirectoryProviderAdapter(outputDirectoryCreator); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProviderAdapter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProviderAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProviderAdapter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/OutputDirectoryProviderAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.reporting; + +import java.io.IOException; +import java.nio.file.Path; + +import org.junit.platform.engine.OutputDirectoryCreator; +import org.junit.platform.engine.TestDescriptor; + +/** + * @since 1.14 + */ +@SuppressWarnings("deprecation") +class OutputDirectoryProviderAdapter implements OutputDirectoryProvider { + + private final OutputDirectoryCreator outputDirectoryCreator; + + OutputDirectoryProviderAdapter(OutputDirectoryCreator outputDirectoryCreator) { + this.outputDirectoryCreator = outputDirectoryCreator; + } + + @Override + public Path getRootDirectory() { + return this.outputDirectoryCreator.getRootDirectory(); + } + + @Override + public Path createOutputDirectory(TestDescriptor testDescriptor) throws IOException { + return this.outputDirectoryCreator.createOutputDirectory(testDescriptor); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/ReportEntry.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/ReportEntry.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/ReportEntry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/reporting/ReportEntry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -39,7 +39,7 @@ /** * @deprecated Use {@link #from(String, String)} or {@link #from(Map)} */ - @API(status = DEPRECATED, since = "5.8") + @API(status = DEPRECATED, since = "1.8") @Deprecated public ReportEntry() { } @@ -83,7 +83,7 @@ * * @return a copy of the map of key-value pairs; never {@code null} */ - public final Map getKeyValuePairs() { + public Map getKeyValuePairs() { return Collections.unmodifiableMap(this.keyValuePairs); } @@ -94,7 +94,7 @@ * * @return when this entry was created; never {@code null} */ - public final LocalDateTime getTimestamp() { + public LocalDateTime getTimestamp() { return this.timestamp; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/config/PrefixedConfigurationParameters.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/config/PrefixedConfigurationParameters.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/config/PrefixedConfigurationParameters.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/config/PrefixedConfigurationParameters.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,10 +13,13 @@ import static java.util.Collections.emptySet; import static org.apiguardian.api.API.Status.STABLE; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.UnaryOperator; import org.apiguardian.api.API; import org.junit.platform.commons.util.Preconditions; @@ -147,6 +150,24 @@ this.children.clear(); } + /** + * {@inheritDoc} + */ + @Override + public void orderChildren(UnaryOperator> orderer) { + Preconditions.notNull(orderer, "orderer must not be null"); + List suggestedOrder = orderer.apply(new ArrayList<>(this.children)); + Preconditions.notNull(suggestedOrder, "orderer may not return null"); + + Set orderedChildren = new LinkedHashSet<>(suggestedOrder); + boolean unmodified = this.children.equals(orderedChildren); + Preconditions.condition(unmodified && this.children.size() == suggestedOrder.size(), + "orderer may not add or remove test descriptors"); + + this.children.clear(); + this.children.addAll(orderedChildren); + } + @Override public Optional findByUniqueId(UniqueId uniqueId) { Preconditions.notNull(uniqueId, "UniqueId must not be null"); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClassSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClassSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClassSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClassSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,8 +18,8 @@ import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.TestSource; @@ -175,7 +175,7 @@ public final Class getJavaClass() { if (this.javaClass == null) { // @formatter:off - this.javaClass = ReflectionUtils.tryToLoadClass(this.className).getOrThrow( + this.javaClass = ReflectionSupport.tryToLoadClass(this.className).getOrThrow( cause -> new PreconditionViolationException("Could not load class with name: " + this.className, cause)); // @formatter:on } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,6 +19,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ResourceUtils; import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.TestSource; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/CompositeTestSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/CompositeTestSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/CompositeTestSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/CompositeTestSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DefaultUriSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DefaultUriSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DefaultUriSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DefaultUriSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DirectorySource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DirectorySource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DirectorySource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/DirectorySource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/EngineDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/EngineDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/EngineDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/EngineDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FilePosition.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FilePosition.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FilePosition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FilePosition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.platform.engine.support.descriptor; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.io.File; @@ -50,6 +51,7 @@ * * @param file the source file; must not be {@code null} * @param filePosition the position in the source file; may be {@code null} + * @see #withPosition(FilePosition) */ public static FileSource from(File file, FilePosition filePosition) { return new FileSource(file, filePosition); @@ -73,6 +75,11 @@ this.filePosition = filePosition; } + private FileSource(FileSource fileSource, FilePosition filePosition) { + this.file = fileSource.file; + this.filePosition = filePosition; + } + /** * Get the {@link URI} for the source {@linkplain #getFile file}. * @@ -100,6 +107,30 @@ return Optional.ofNullable(this.filePosition); } + /** + * {@return a {@code FileSource} based on this instance but with the + * supplied {@link FilePosition}} + * + *

    If the supplied {@code FilePosition} + * {@linkplain Objects#equals(Object, Object) equals} the existing one, this + * method returns {@code this}. Otherwise, a new instance is created and + * returned. + * + *

    Calling this method rather than creating a new {@code FileSource} via + * {@link #from(File, FilePosition)} avoids the overhead of redundant + * canonical path resolution. + * + * @param filePosition the position in the source file; may be {@code null} + * @since 1.14 + */ + @API(status = EXPERIMENTAL, since = "1.14") + public FileSource withPosition(FilePosition filePosition) { + if (Objects.equals(this.filePosition, filePosition)) { + return this; + } + return new FileSource(this, filePosition); + } + @Override public boolean equals(Object o) { if (this == o) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSystemSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSystemSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSystemSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSystemSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/MethodSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/MethodSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/MethodSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/MethodSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,8 +18,8 @@ import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.TestSource; @@ -195,7 +195,7 @@ private void lazyLoadJavaClass() { if (this.javaClass == null) { // @formatter:off - this.javaClass = ReflectionUtils.tryToLoadClass(this.className).getOrThrow( + this.javaClass = ReflectionSupport.tryToLoadClass(this.className).getOrThrow( cause -> new PreconditionViolationException("Could not load class with name: " + this.className, cause)); // @formatter:on } @@ -206,14 +206,14 @@ if (this.javaMethod == null) { if (StringUtils.isNotBlank(this.methodParameterTypes)) { - this.javaMethod = ReflectionUtils.findMethod(this.javaClass, this.methodName, + this.javaMethod = ReflectionSupport.findMethod(this.javaClass, this.methodName, this.methodParameterTypes).orElseThrow( () -> new PreconditionViolationException(String.format( "Could not find method with name [%s] and parameter types [%s] in class [%s].", this.methodName, this.methodParameterTypes, this.javaClass.getName()))); } else { - this.javaMethod = ReflectionUtils.findMethod(this.javaClass, this.methodName).orElseThrow( + this.javaMethod = ReflectionSupport.findMethod(this.javaClass, this.methodName).orElseThrow( () -> new PreconditionViolationException( String.format("Could not find method with name [%s] in class [%s].", this.methodName, this.javaClass.getName()))); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/PackageSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/PackageSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/PackageSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/PackageSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.platform.engine.support.descriptor; import static org.apiguardian.api.API.Status.STABLE; +import static org.junit.platform.commons.util.StringUtils.isNotBlank; import java.util.Objects; @@ -58,7 +59,10 @@ } private PackageSource(String packageName) { - this.packageName = Preconditions.notBlank(packageName, "package name must not be null or blank"); + Preconditions.notNull(packageName, "package name must not be null"); + Preconditions.condition(packageName.isEmpty() || isNotBlank(packageName), + "package name must not contain only whitespace"); + this.packageName = packageName; } /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ResourceUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ResourceUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ResourceUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/ResourceUtils.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.engine.support.descriptor; - -import java.net.URI; - -import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.StringUtils; - -/** - * Collection of static utility methods for working with resources. - * - * @since 1.3 - */ -final class ResourceUtils { - - private ResourceUtils() { - /* no-op */ - } - - /** - * Strip the {@link URI#getQuery() query} component from the supplied - * {@link URI}. - * - * @param uri the {@code URI} from which to strip the query component - * @return a new {@code URI} with the query component removed, or the - * original {@code URI} unmodified if it does not have a query component - */ - static URI stripQueryComponent(URI uri) { - Preconditions.notNull(uri, "URI must not be null"); - - if (StringUtils.isBlank(uri.getQuery())) { - return uri; - } - - String uriAsString = uri.toString(); - return URI.create(uriAsString.substring(0, uriAsString.indexOf('?'))); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/UriSource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/UriSource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/UriSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/UriSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,6 +20,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ResourceUtils; import org.junit.platform.engine.TestSource; /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ClassContainerSelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ClassContainerSelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ClassContainerSelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ClassContainerSelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,6 +20,7 @@ import java.util.List; import java.util.function.Predicate; +import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.discovery.ClasspathRootSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.discovery.ModuleSelector; @@ -34,8 +35,8 @@ private final Predicate classNameFilter; ClassContainerSelectorResolver(Predicate> classFilter, Predicate classNameFilter) { - this.classFilter = classFilter; - this.classNameFilter = classNameFilter; + this.classFilter = Preconditions.notNull(classFilter, "classFilter must not be null"); + this.classNameFilter = Preconditions.notNull(classNameFilter, "classNameFilter must not be null"); } @Override diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/DiscoveryIssueReporter.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/DiscoveryIssueReporter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/DiscoveryIssueReporter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/DiscoveryIssueReporter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.EngineDiscoveryListener; +import org.junit.platform.engine.UniqueId; + +/** + * {@code DiscoveryIssueReporter} defines the API for reporting + * {@link DiscoveryIssue DiscoveryIssues}. + * + *

    This interface is not intended to be implemented by clients. + * + * @since 1.13 + * @see SelectorResolver.Context + */ +@API(status = MAINTAINED, since = "1.13.3") +public interface DiscoveryIssueReporter { + + /** + * Create a new {@code DiscoveryIssueReporter} that reports issues to the + * supplied {@link EngineDiscoveryListener} for the specified engine. + * + * @param engineDiscoveryListener the listener to report issues to; never + * {@code null} + * @param engineId the unique identifier of the engine; never {@code null} + */ + static DiscoveryIssueReporter forwarding(EngineDiscoveryListener engineDiscoveryListener, UniqueId engineId) { + Preconditions.notNull(engineDiscoveryListener, "engineDiscoveryListener must not be null"); + Preconditions.notNull(engineId, "engineId must not be null"); + return issue -> engineDiscoveryListener.issueEncountered(engineId, issue); + } + + /** + * Create a new {@code DiscoveryIssueReporter} that adds reported issues to + * the supplied collection. + * + * @param collection the collection to add issues to; never {@code null} + */ + static DiscoveryIssueReporter collecting(Collection collection) { + Preconditions.notNull(collection, "collection must not be null"); + return consuming(collection::add); + } + + /** + * Create a new {@code DiscoveryIssueReporter} that adds reported issues to + * the supplied consumer. + * + * @param consumer the consumer to report issues to; never {@code null} + */ + static DiscoveryIssueReporter consuming(Consumer consumer) { + Preconditions.notNull(consumer, "consumer must not be null"); + return consumer::accept; + } + + /** + * Create a new {@code DiscoveryIssueReporter} that avoids reporting + * duplicate issues. + * + *

    The implementation returned by this method is not thread-safe. + * + * @param delegate the delegate to forward issues to; never {@code null} + */ + static DiscoveryIssueReporter deduplicating(DiscoveryIssueReporter delegate) { + Preconditions.notNull(delegate, "delegate must not be null"); + Set seen = new HashSet<>(); + return issue -> { + boolean notSeen = seen.add(issue); + if (notSeen) { + delegate.reportIssue(issue); + } + }; + } + + /** + * Build the supplied {@link DiscoveryIssue.Builder Builder} and report the + * resulting {@link DiscoveryIssue}. + */ + default void reportIssue(DiscoveryIssue.Builder builder) { + reportIssue(builder.build()); + } + + /** + * Report the supplied {@link DiscoveryIssue}. + */ + void reportIssue(DiscoveryIssue issue); + + /** + * Create a {@link Condition} that reports a {@link DiscoveryIssue} when the + * supplied {@link Predicate} is not met. + * + * @param predicate the predicate to test; never {@code null} + * @param issueCreator the function to create the issue with; never {@code null} + * @return a new {@code Condition}; never {@code null} + */ + default Condition createReportingCondition(Predicate predicate, + Function issueCreator) { + Preconditions.notNull(predicate, "predicate must not be null"); + Preconditions.notNull(issueCreator, "issueCreator must not be null"); + return value -> { + if (predicate.test(value)) { + return true; + } + else { + reportIssue(issueCreator.apply(value)); + return false; + } + }; + } + + /** + * A {@code Condition} is a union of {@link Predicate} and {@link Consumer}. + * + *

    Instances of this type may be used as {@link Predicate Predicates} or + * {@link Consumer Consumers}. For example, a {@code Condition} may be + * passed to {@link java.util.stream.Stream#filter(Predicate)} if it is used + * for filtering, or to {@link java.util.stream.Stream#peek(Consumer)} if it + * is only used for reporting or other side effects. + * + *

    This interface is not intended to be implemented by clients. + * + * @see #createReportingCondition(Predicate, Function) + */ + interface Condition { + + /** + * Create a {@link Condition} that is always satisfied. + */ + static Condition alwaysSatisfied() { + return __ -> true; + } + + /** + * Evaluate this condition to potentially report an issue. + */ + boolean check(T value); + + /** + * Return a composed condition that represents a logical AND of this + * and the supplied condition. + * + *

    The default implementation avoids short-circuiting so + * both conditions will be evaluated even if this condition + * returns {@code false} to ensure that all issues are reported. + * + * @return the composed condition; never {@code null} + */ + default Condition and(Condition that) { + Preconditions.notNull(that, "condition must not be null"); + return value -> this.check(value) & that.check(value); + } + + /** + * {@return this condition as a {@link Predicate}} + */ + default Predicate toPredicate() { + return this::check; + } + + /** + * {@return this condition as a {@link Consumer}} + */ + default Consumer toConsumer() { + return this::check; + } + + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolution.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolution.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolution.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolution.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,8 @@ package org.junit.platform.engine.support.discovery; import static java.util.stream.Collectors.toCollection; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.ArrayList; @@ -19,6 +21,7 @@ import java.util.function.Predicate; import org.apiguardian.api.API; +import org.junit.platform.commons.io.ResourceFilter; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.DiscoveryFilter; import org.junit.platform.engine.EngineDiscoveryRequest; @@ -26,6 +29,7 @@ import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.discovery.ClassNameFilter; import org.junit.platform.engine.discovery.ClassSelector; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; import org.junit.platform.engine.discovery.ClasspathRootSelector; import org.junit.platform.engine.discovery.ModuleSelector; import org.junit.platform.engine.discovery.PackageNameFilter; @@ -62,7 +66,9 @@ /** * Resolve the supplied {@link EngineDiscoveryRequest} and collect the - * results into the supplied {@link TestDescriptor}. + * results into the supplied {@link TestDescriptor} while forwarding + * encountered discovery issues to the {@link EngineDiscoveryRequest}'s + * {@link org.junit.platform.engine.EngineDiscoveryListener}. * *

    The algorithm works as follows: * @@ -107,7 +113,37 @@ public void resolve(EngineDiscoveryRequest request, T engineDescriptor) { Preconditions.notNull(request, "request must not be null"); Preconditions.notNull(engineDescriptor, "engineDescriptor must not be null"); - InitializationContext initializationContext = new DefaultInitializationContext<>(request, engineDescriptor); + DiscoveryIssueReporter issueReporter = DiscoveryIssueReporter.forwarding(request.getDiscoveryListener(), + engineDescriptor.getUniqueId()); + resolve(request, engineDescriptor, issueReporter); + } + + /** + * Resolve the supplied {@link EngineDiscoveryRequest} and collect the + * results into the supplied {@link TestDescriptor} using the supplied + * {@link DiscoveryIssueReporter} to report issues encountered during + * resolution. + * + *

    The algorithm works as described in + * {@link #resolve(EngineDiscoveryRequest, TestDescriptor)}. + * + * @param request the request to be resolved; never {@code null} + * @param engineDescriptor the engine's {@code TestDescriptor} to be used + * for adding direct children + * @param issueReporter the {@link DiscoveryIssueReporter} to report issues + * encountered during resolution + * @since 1.13 + * @see #resolve(EngineDiscoveryRequest, TestDescriptor) + * @see SelectorResolver + * @see TestDescriptor.Visitor + */ + @API(status = MAINTAINED, since = "1.13.3") + public void resolve(EngineDiscoveryRequest request, T engineDescriptor, DiscoveryIssueReporter issueReporter) { + Preconditions.notNull(request, "request must not be null"); + Preconditions.notNull(engineDescriptor, "engineDescriptor must not be null"); + Preconditions.notNull(issueReporter, "issueReporter must not be null"); + InitializationContext initializationContext = new DefaultInitializationContext<>(request, engineDescriptor, + issueReporter); List resolvers = instantiate(resolverCreators, initializationContext); List visitors = instantiate(visitorCreators, initializationContext); new EngineDiscoveryRequestResolution(request, engineDescriptor, resolvers, visitors).run(); @@ -156,8 +192,70 @@ */ public Builder addClassContainerSelectorResolver(Predicate> classFilter) { Preconditions.notNull(classFilter, "classFilter must not be null"); + return addClassContainerSelectorResolverWithContext(__ -> classFilter); + } + + /** + * Add a predefined resolver that resolves {@link ClasspathRootSelector + * ClasspathRootSelectors}, {@link ModuleSelector ModuleSelectors}, and + * {@link PackageSelector PackageSelectors} into {@link ClassSelector + * ClassSelectors} by scanning for classes that satisfy the predicate + * created by the supplied {@code Function} in the respective class + * containers to this builder. + * + * @param classFilterCreator the function that will be called to create + * the predicate the resolved classes must satisfy; never + * {@code null} + * @return this builder for method chaining + */ + @API(status = MAINTAINED, since = "1.13.3") + public Builder addClassContainerSelectorResolverWithContext( + Function, Predicate>> classFilterCreator) { + Preconditions.notNull(classFilterCreator, "classFilterCreator must not be null"); + return addSelectorResolver(context -> new ClassContainerSelectorResolver(classFilterCreator.apply(context), + context.getClassNameFilter())); + } + + /** + * Add a predefined resolver that resolves {@link ClasspathRootSelector + * ClasspathRootSelectors}, {@link ModuleSelector ModuleSelectors}, and + * {@link PackageSelector PackageSelectors} into {@link ClasspathResourceSelector + * ClasspathResourceSelectors} by scanning for resources that satisfy the supplied + * predicate in the respective class containers to this builder. + * + * @param resourceFilter predicate the resolved classes must satisfy; never + * {@code null} + * @return this builder for method chaining + * @since 1.12 + * @deprecated Please use {@link #addResourceContainerSelectorResolver(ResourceFilter)} instead. + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + public Builder addResourceContainerSelectorResolver( + Predicate resourceFilter) { + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); + return addResourceContainerSelectorResolver( + ResourceFilter.of(r -> resourceFilter.test(org.junit.platform.commons.support.Resource.of(r)))); + } + + /** + * Add a predefined resolver that resolves {@link ClasspathRootSelector + * ClasspathRootSelectors}, {@link ModuleSelector ModuleSelectors}, and + * {@link PackageSelector PackageSelectors} into + * {@link ClasspathResourceSelector ClasspathResourceSelectors} by + * scanning for resources that match the supplied resource filter in the + * respective class containers to this builder. + * + * @param resourceFilter filter the resolved classes must match; never + * {@code null} + * @return this builder for method chaining + * @since 1.14 + */ + @API(status = MAINTAINED, since = "1.14") + public Builder addResourceContainerSelectorResolver(ResourceFilter resourceFilter) { + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); return addSelectorResolver( - context -> new ClassContainerSelectorResolver(classFilter, context.getClassNameFilter())); + context -> new ResourceContainerSelectorResolver(resourceFilter, context.getPackageFilter())); } /** @@ -188,6 +286,12 @@ * Add a context sensitive {@link TestDescriptor.Visitor} to this * builder. * + *

    If multiple {@linkplain TestDescriptor.Visitor visitors} are registered, + * they will iterate over the test tree separately. To avoid the overhead of + * multiple iterations, consider combining multiple visitors into a single + * visitor using + * {@link TestDescriptor.Visitor#composite(TestDescriptor.Visitor...)}. + * * @param visitorCreator the function that will be called to create the * {@link TestDescriptor.Visitor} to be added. * @return this builder for method chaining @@ -247,6 +351,26 @@ */ Predicate getClassNameFilter(); + /** + * Get the package name filter built from the {@link PackageNameFilter + * PackageNameFilters} in the {@link EngineDiscoveryRequest} that is + * about to be resolved. + * + * @return the predicate for filtering the resolved resource names; never + * {@code null} + * @since 1.12 + */ + @API(status = MAINTAINED, since = "1.13.3") + Predicate getPackageFilter(); + + /** + * {@return the {@link DiscoveryIssueReporter} for the current + * resolution} + * + * @since 1.13 + */ + @API(status = MAINTAINED, since = "1.13.3") + DiscoveryIssueReporter getIssueReporter(); } private static class DefaultInitializationContext implements InitializationContext { @@ -254,11 +378,16 @@ private final EngineDiscoveryRequest request; private final T engineDescriptor; private final Predicate classNameFilter; + private final Predicate packageFilter; + private final DiscoveryIssueReporter issueReporter; - DefaultInitializationContext(EngineDiscoveryRequest request, T engineDescriptor) { + DefaultInitializationContext(EngineDiscoveryRequest request, T engineDescriptor, + DiscoveryIssueReporter issueReporter) { this.request = request; this.engineDescriptor = engineDescriptor; this.classNameFilter = buildClassNamePredicate(request); + this.packageFilter = buildPackagePredicate(request); + this.issueReporter = issueReporter; } /** @@ -274,6 +403,12 @@ return Filter.composeFilters(filters).toPredicate(); } + private Predicate buildPackagePredicate(EngineDiscoveryRequest request) { + List> filters = new ArrayList<>(); + filters.addAll(request.getFiltersByType(PackageNameFilter.class)); + return Filter.composeFilters(filters).toPredicate(); + } + @Override public EngineDiscoveryRequest getDiscoveryRequest() { return request; @@ -288,6 +423,16 @@ public Predicate getClassNameFilter() { return classNameFilter; } + + @Override + public Predicate getPackageFilter() { + return packageFilter; + } + + @Override + public DiscoveryIssueReporter getIssueReporter() { + return issueReporter; + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toSet; +import static org.junit.platform.commons.support.ResourceSupport.findAllResourcesInClasspathRoot; +import static org.junit.platform.commons.support.ResourceSupport.findAllResourcesInModule; +import static org.junit.platform.commons.support.ResourceSupport.findAllResourcesInPackage; +import static org.junit.platform.engine.support.discovery.ResourceUtils.packageName; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; +import org.junit.platform.engine.discovery.ClasspathRootSelector; +import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.engine.discovery.ModuleSelector; +import org.junit.platform.engine.discovery.PackageSelector; + +/** + * @since 1.12 + */ +class ResourceContainerSelectorResolver implements SelectorResolver { + private final ResourceFilter resourceFilter; + + ResourceContainerSelectorResolver(ResourceFilter resourceFilter, Predicate packageFilter) { + this.resourceFilter = ResourceFilter.of(packageName(packageFilter).and(resourceFilter::match)); + } + + @Override + public Resolution resolve(ClasspathRootSelector selector, Context context) { + return resourceSelectors(findAllResourcesInClasspathRoot(selector.getClasspathRoot(), resourceFilter)); + } + + @Override + public Resolution resolve(ModuleSelector selector, Context context) { + return resourceSelectors(findAllResourcesInModule(selector.getModuleName(), resourceFilter)); + } + + @Override + public Resolution resolve(PackageSelector selector, Context context) { + return resourceSelectors(findAllResourcesInPackage(selector.getPackageName(), resourceFilter)); + } + + private Resolution resourceSelectors(List resources) { + Set selectors = resources.stream() // + .collect(groupingBy(Resource::getName)) // + .values() // + .stream() // + .map(LinkedHashSet::new) // + .map(DiscoverySelectors::selectClasspathResourceByName) // + .collect(toSet()); + + if (selectors.isEmpty()) { + return unresolved(); + } + return selectors(selectors); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import java.util.function.Predicate; + +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.support.ReflectionSupport; + +/** + * Resource-related utilities to be used in conjunction with {@link ReflectionSupport}. + * + * @since 1.12 + */ +class ResourceUtils { + public static final String DEFAULT_PACKAGE_NAME = ""; + private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; + private static final char PACKAGE_SEPARATOR_CHAR = '.'; + + /** + * Match resources against a package filter. + * + *

    The {@code /} separated path of a resource is rewritten to a + * {@code .} separated package names. The package filter is applied to that + * package name. + */ + static Predicate packageName(Predicate packageFilter) { + return resource -> packageFilter.test(packageName(resource.getName())); + } + + private static String packageName(String classpathResourceName) { + int lastIndexOf = classpathResourceName.lastIndexOf(CLASSPATH_RESOURCE_PATH_SEPARATOR); + if (lastIndexOf < 0) { + return DEFAULT_PACKAGE_NAME; + } + // classpath resource names do not start with / + String resourcePackagePath = classpathResourceName.substring(0, lastIndexOf); + return resourcePackagePath.replace(CLASSPATH_RESOURCE_PATH_SEPARATOR, PACKAGE_SEPARATOR_CHAR); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/SelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/SelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/SelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/SelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,7 +12,7 @@ import static java.util.Collections.emptySet; import static java.util.Collections.singleton; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.util.Collections; @@ -315,7 +315,7 @@ * Resolution#matches(Set) matches()}; never {@code null} * @see #resolve(DiscoverySelector, Context) */ - @API(status = EXPERIMENTAL, since = "1.9") + @API(status = MAINTAINED, since = "1.13.3") default Resolution resolve(IterationSelector selector, Context context) { return resolve((DiscoverySelector) selector, context); } @@ -469,7 +469,7 @@ * {@link Match Match}. * * @param match the resolved {@code Match}; never {@code null} - * @return an resolution that contains the supplied {@code Match}; never + * @return a resolution that contains the supplied {@code Match}; never * {@code null} */ public static Resolution match(Match match) { @@ -482,7 +482,7 @@ * * @param matches the resolved {@code Matches}; never {@code null} or * empty - * @return an resolution that contains the supplied {@code Matches}; + * @return a resolution that contains the supplied {@code Matches}; * never {@code null} */ public static Resolution matches(Set matches) { @@ -497,7 +497,7 @@ * * @param selectors the resolved {@code DiscoverySelectors}; never * {@code null} or empty - * @return an resolution that contains the supplied + * @return a resolution that contains the supplied * {@code DiscoverySelectors}; never {@code null} */ public static Resolution selectors(Set selectors) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/filter/ClasspathScanningSupport.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/filter/ClasspathScanningSupport.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/filter/ClasspathScanningSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/filter/ClasspathScanningSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,7 +18,7 @@ import java.util.function.Predicate; import org.apiguardian.api.API; -import org.junit.platform.commons.util.ClassFilter; +import org.junit.platform.commons.support.scanning.ClassFilter; import org.junit.platform.engine.DiscoveryFilter; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.discovery.ClassNameFilter; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/CompositeLock.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/CompositeLock.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/CompositeLock.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/CompositeLock.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfiguration.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfiguration.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfiguration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfiguration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategy.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategy.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategy.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategy.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.engine.support.hierarchical; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import java.math.BigDecimal; @@ -18,8 +18,8 @@ import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.engine.ConfigurationParameters; /** @@ -77,7 +77,7 @@ Preconditions.condition(maxPoolSizeFactor.compareTo(BigDecimal.ONE) >= 0, () -> String.format( "Factor '%s' specified via configuration parameter '%s' must be greater than or equal to 1", - factor, CONFIG_DYNAMIC_FACTOR_PROPERTY_NAME)); + factor, CONFIG_DYNAMIC_MAX_POOL_SIZE_FACTOR_PROPERTY_NAME)); return maxPoolSizeFactor.multiply(BigDecimal.valueOf(parallelism)).intValue(); }).orElseGet(() -> 256 + parallelism); @@ -99,13 +99,13 @@ public ParallelExecutionConfiguration createConfiguration(ConfigurationParameters configurationParameters) { String className = configurationParameters.get(CONFIG_CUSTOM_CLASS_PROPERTY_NAME).orElseThrow( () -> new JUnitException(CONFIG_CUSTOM_CLASS_PROPERTY_NAME + " must be set")); - return ReflectionUtils.tryToLoadClass(className) // + return ReflectionSupport.tryToLoadClass(className) // .andThenTry(strategyClass -> { Preconditions.condition( ParallelExecutionConfigurationStrategy.class.isAssignableFrom(strategyClass), CONFIG_CUSTOM_CLASS_PROPERTY_NAME + " does not implement " + ParallelExecutionConfigurationStrategy.class); - return (ParallelExecutionConfigurationStrategy) ReflectionUtils.newInstance(strategyClass); + return (ParallelExecutionConfigurationStrategy) ReflectionSupport.newInstance(strategyClass); }) // .andThenTry(strategy -> strategy.createConfiguration(configurationParameters)) // .getOrThrow(cause -> new JUnitException( @@ -144,7 +144,7 @@ * @since 1.10 * @see #FIXED */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static final String CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME = "fixed.max-pool-size"; /** @@ -160,7 +160,7 @@ * @see #FIXED * @see #CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static final String CONFIG_FIXED_SATURATE_PROPERTY_NAME = "fixed.saturate"; /** @@ -188,7 +188,7 @@ * @since 1.10 * @see #DYNAMIC */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static final String CONFIG_DYNAMIC_MAX_POOL_SIZE_FACTOR_PROPERTY_NAME = "dynamic.max-pool-size-factor"; /** @@ -204,7 +204,7 @@ * @see #DYNAMIC * @see #CONFIG_DYNAMIC_FACTOR_PROPERTY_NAME */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static final String CONFIG_DYNAMIC_SATURATE_PROPERTY_NAME = "dynamic.saturate"; /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/EngineExecutionContext.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/EngineExecutionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/EngineExecutionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/EngineExecutionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ExclusiveResource.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ExclusiveResource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ExclusiveResource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ExclusiveResource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestEngine.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestEngine.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestEngine.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestEngine.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorService.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorService.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorService.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorService.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/LockManager.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/LockManager.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/LockManager.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/LockManager.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/Node.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/Node.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/Node.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/Node.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeExecutionAdvisor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeExecutionAdvisor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeExecutionAdvisor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeExecutionAdvisor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTask.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTask.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTask.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTask.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -76,7 +76,8 @@ @Override public ExecutionMode getExecutionMode() { - return taskContext.getExecutionAdvisor().getForcedExecutionMode(testDescriptor).orElse(node.getExecutionMode()); + return taskContext.getExecutionAdvisor().getForcedExecutionMode(testDescriptor) // + .orElseGet(node::getExecutionMode); } @Override @@ -107,7 +108,7 @@ finally { // Ensure that the 'interrupted status' flag for the current thread // is cleared for reuse of the thread in subsequent task executions. - // See https://github.com/junit-team/junit5/issues/1688 + // See https://github.com/junit-team/junit-framework/issues/1688 if (Thread.interrupted()) { logger.debug(() -> String.format( "Execution of TestDescriptor with display name [%s] " @@ -120,7 +121,7 @@ } // Clear reference to context to allow it to be garbage collected. - // See https://github.com/junit-team/junit5/issues/1578 + // See https://github.com/junit-team/junit-framework/issues/1578 context = null; } @@ -128,7 +129,7 @@ throwableCollector.execute(() -> context = node.prepare(parentContext)); // Clear reference to parent context to allow it to be garbage collected. - // See https://github.com/junit-team/junit5/issues/1578 + // See https://github.com/junit-team/junit-framework/issues/1578 parentContext = null; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTaskContext.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTaskContext.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTaskContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTestTaskContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalker.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalker.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalker.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalker.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NodeUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NopLock.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NopLock.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NopLock.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/NopLock.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/OpenTest4JAwareThrowableCollector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/OpenTest4JAwareThrowableCollector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/OpenTest4JAwareThrowableCollector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/OpenTest4JAwareThrowableCollector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfiguration.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfiguration.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfiguration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfiguration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfigurationStrategy.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfigurationStrategy.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfigurationStrategy.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfigurationStrategy.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ResourceLock.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ResourceLock.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ResourceLock.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ResourceLock.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SameThreadHierarchicalTestExecutorService.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SameThreadHierarchicalTestExecutorService.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SameThreadHierarchicalTestExecutorService.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SameThreadHierarchicalTestExecutorService.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleLock.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleLock.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleLock.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleLock.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ThrowableCollector.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ThrowableCollector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ThrowableCollector.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ThrowableCollector.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/Namespace.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/Namespace.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/Namespace.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/Namespace.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.store; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; + +/** + * A {@code Namespace} is used to provide a scope for data saved by + * extensions within a {@link NamespacedHierarchicalStore}. + * + *

    Storing data in custom namespaces allows extensions to avoid accidentally + * mixing data between extensions or across different invocations within the + * lifecycle of a single extension. + */ +@API(status = MAINTAINED, since = "1.13.3") +public class Namespace { + + /** + * The default, global namespace which allows access to stored data from + * all extensions. + */ + public static final Namespace GLOBAL = Namespace.create(new Object()); + + /** + * Create a namespace which restricts access to data to all extensions + * which use the same sequence of {@code parts} for creating a namespace. + * + *

    The order of the {@code parts} is significant. + * + *

    Internally the {@code parts} are compared using {@link Object#equals(Object)}. + */ + public static Namespace create(Object... parts) { + Preconditions.notEmpty(parts, "parts array must not be null or empty"); + Preconditions.containsNoNullElements(parts, "individual parts must not be null"); + return new Namespace(Arrays.asList(parts)); + } + + /** + * Create a namespace which restricts access to data to all extensions + * which use the same sequence of {@code objects} for creating a namespace. + * + *

    The order of the {@code objects} is significant. + * + *

    Internally the {@code objects} are compared using {@link Object#equals(Object)}. + */ + public static Namespace create(List objects) { + Preconditions.notEmpty(objects, "objects list must not be null or empty"); + Preconditions.containsNoNullElements(objects, "individual objects must not be null"); + return new Namespace(objects); + } + + private final List parts; + + private Namespace(List parts) { + this.parts = new ArrayList<>(parts); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Namespace that = (Namespace) o; + return this.parts.equals(that.parts); + } + + @Override + public int hashCode() { + return this.parts.hashCode(); + } + + /** + * Create a new namespace by appending the supplied {@code parts} to the + * existing sequence of parts in this namespace. + * + * @return new namespace; never {@code null} + */ + public Namespace append(Object... parts) { + Preconditions.notEmpty(parts, "parts array must not be null or empty"); + Preconditions.containsNoNullElements(parts, "individual parts must not be null"); + ArrayList newParts = new ArrayList<>(this.parts.size() + parts.length); + newParts.addAll(this.parts); + Collections.addAll(newParts, parts); + return new Namespace(newParts); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,12 +11,17 @@ package org.junit.platform.engine.support.store; import static java.util.Comparator.comparing; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; +import static org.junit.platform.commons.util.ExceptionUtils.throwAsUncheckedException; import static org.junit.platform.commons.util.ReflectionUtils.getWrapperType; import static org.junit.platform.commons.util.ReflectionUtils.isAssignableTo; +import java.util.ArrayList; import java.util.Comparator; +import java.util.Iterator; +import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; @@ -24,10 +29,8 @@ import java.util.function.Supplier; import org.apiguardian.api.API; -import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.UnrecoverableExceptions; -import org.junit.platform.engine.support.hierarchical.ThrowableCollector; /** * {@code NamespacedHierarchicalStore} is a hierarchical, namespaced key-value store. @@ -43,7 +46,7 @@ * @param Namespace type * @since 1.10 */ -@API(status = EXPERIMENTAL, since = "1.10") +@API(status = MAINTAINED, since = "1.13.3") public final class NamespacedHierarchicalStore implements AutoCloseable { private final AtomicInteger insertOrderSequence = new AtomicInteger(); @@ -86,13 +89,26 @@ } /** + * Returns the parent store of this {@code NamespacedHierarchicalStore}. + * + *

    If this store does not have a parent, an empty {@code Optional} is returned. + * + * @return an {@code Optional} containing the parent store, or an empty {@code Optional} if there is no parent + * @since 1.13 + */ + @API(status = MAINTAINED, since = "5.13.3") + public Optional> getParent() { + return Optional.ofNullable(this.parentStore); + } + + /** * Determine if this store has been {@linkplain #close() closed}. * * @return {@code true} if this store has been closed * @since 1.11 * @see #close() */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = MAINTAINED, since = "1.13.3") public boolean isClosed() { return this.closed; } @@ -113,13 +129,26 @@ if (!this.closed) { try { if (this.closeAction != null) { - ThrowableCollector throwableCollector = new ThrowableCollector(__ -> false); + List failures = new ArrayList<>(); this.storedValues.entrySet().stream() // .map(e -> e.getValue().evaluateSafely(e.getKey())) // .filter(it -> it != null && it.value != null) // .sorted(EvaluatedValue.REVERSE_INSERT_ORDER) // - .forEach(it -> throwableCollector.execute(() -> it.close(this.closeAction))); - throwableCollector.assertEmpty(); + .forEach(it -> { + try { + it.close(this.closeAction); + } + catch (Throwable t) { + UnrecoverableExceptions.rethrowIfUnrecoverable(t); + failures.add(t); + } + }); + if (!failures.isEmpty()) { + Iterator iterator = failures.iterator(); + Throwable throwable = iterator.next(); + iterator.forEachRemaining(throwable::addSuppressed); + throw throwAsUncheckedException(throwable); + } } } finally { @@ -411,7 +440,7 @@ computeValue(); } if (this.value instanceof Failure) { - throw ExceptionUtils.throwAsUncheckedException(((Failure) this.value).throwable); + throw throwAsUncheckedException(((Failure) this.value).throwable); } return this.value; } @@ -447,6 +476,15 @@ @FunctionalInterface public interface CloseAction { + @API(status = MAINTAINED, since = "1.13.3") + static CloseAction closeAutoCloseables() { + return (__, ___, value) -> { + if (value instanceof AutoCloseable) { + ((AutoCloseable) value).close(); + } + }; + } + /** * Close the supplied {@code value}. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreException.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreException.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.engine.support.store; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; @@ -20,7 +20,7 @@ * * @since 1.10 */ -@API(status = EXPERIMENTAL, since = "1.10") +@API(status = MAINTAINED, since = "1.13.3") public class NamespacedHierarchicalStoreException extends JUnitException { private static final long serialVersionUID = 1L; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/module/org.junit.platform.engine/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/module/org.junit.platform.engine/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/module/org.junit.platform.engine/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/module/org.junit.platform.engine/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,11 +8,12 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Public API for test engines. * - *

    Provides the {@linkplain org.junit.platform.engine.TestEngine} interface, test discovery - * and execution reporting support. + *

    Provides the {@link org.junit.platform.engine.TestEngine} interface, + * test discovery, and execution reporting support. * * @since 1.0 */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoEngineExecutionContext.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoEngineExecutionContext.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoEngineExecutionContext.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoEngineExecutionContext.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalContainerDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalContainerDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalContainerDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalContainerDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalEngineDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalEngineDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalEngineDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalEngineDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestEngine.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestEngine.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestEngine.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestEngine.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/FaultyTestEngines.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/FaultyTestEngines.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/FaultyTestEngines.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/FaultyTestEngines.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.fakes; + +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.EngineDiscoveryRequest; +import org.junit.platform.engine.ExecutionRequest; +import org.junit.platform.engine.SelectorResolutionResult; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.EngineDescriptor; + +public class FaultyTestEngines { + + public static TestEngineStub createEngineThatCannotResolveAnything(String engineId) { + return new TestEngineStub(engineId) { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + discoveryRequest.getSelectorsByType(DiscoverySelector.class) // + .forEach(selector -> discoveryRequest.getDiscoveryListener().selectorProcessed(uniqueId, + selector, SelectorResolutionResult.unresolved())); + return new EngineDescriptor(uniqueId, "Some Engine"); + } + + @Override + public void execute(ExecutionRequest request) { + var listener = request.getEngineExecutionListener(); + var rootTestDescriptor = request.getRootTestDescriptor(); + listener.executionStarted(rootTestDescriptor); + listener.executionFinished(rootTestDescriptor, TestExecutionResult.successful()); + } + }; + } + + public static TestEngineStub createEngineThatFailsToResolveAnything(String engineId, Throwable rootCause) { + return new TestEngineStub(engineId) { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + discoveryRequest.getSelectorsByType(DiscoverySelector.class) // + .forEach(selector -> discoveryRequest.getDiscoveryListener().selectorProcessed(uniqueId, + selector, SelectorResolutionResult.failed(rootCause))); + return new EngineDescriptor(uniqueId, "Some Engine"); + } + + @Override + public void execute(ExecutionRequest request) { + var listener = request.getEngineExecutionListener(); + var rootTestDescriptor = request.getRootTestDescriptor(); + listener.executionStarted(rootTestDescriptor); + listener.executionFinished(rootTestDescriptor, TestExecutionResult.successful()); + } + }; + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestDescriptorStub.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestDescriptorStub.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestDescriptorStub.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestDescriptorStub.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineSpy.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineSpy.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineSpy.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineSpy.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineStub.java jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineStub.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineStub.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-engine/src/testFixtures/java/org/junit/platform/fakes/TestEngineStub.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingDiscoveryListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingDiscoveryListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingDiscoveryListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingDiscoveryListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -23,7 +23,9 @@ import jdk.jfr.StackTrace; import org.apiguardian.api.API; +import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.engine.DiscoveryFilter; +import org.junit.platform.engine.DiscoveryIssue; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.launcher.EngineDiscoveryResult; import org.junit.platform.launcher.LauncherDiscoveryListener; @@ -71,13 +73,23 @@ event.commit(); } + @Override + public void issueEncountered(org.junit.platform.engine.UniqueId engineId, DiscoveryIssue issue) { + DiscoveryIssueEvent event = new DiscoveryIssueEvent(); + event.engineId = engineId.toString(); + event.severity = issue.severity().name(); + event.message = issue.message(); + event.source = issue.source().map(Object::toString).orElse(null); + event.cause = issue.cause().map(ExceptionUtils::readStackTrace).orElse(null); + event.commit(); + } + @Category({ "JUnit", "Discovery" }) @StackTrace(false) abstract static class DiscoveryEvent extends Event { } @Label("Test Discovery") - @Category({ "JUnit", "Discovery" }) @Name("org.junit.LauncherDiscovery") static class LauncherDiscoveryEvent extends DiscoveryEvent { @@ -89,7 +101,6 @@ } @Label("Engine Discovery") - @Category({ "JUnit", "Discovery" }) @Name("org.junit.EngineDiscovery") static class EngineDiscoveryEvent extends DiscoveryEvent { @@ -100,4 +111,24 @@ @Label("Result") String result; } + + @Label("Discovery Issue") + @Name("org.junit.DiscoveryIssue") + static class DiscoveryIssueEvent extends DiscoveryEvent { + + @Label("Engine Id") + String engineId; + + @Label("Severity") + String severity; + + @Label("Message") + String message; + + @Label("Source") + String source; + + @Label("Cause") + String cause; + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/FlightRecordingExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -26,6 +26,7 @@ import org.apiguardian.api.API; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; @@ -97,6 +98,14 @@ } } + @Override + public void fileEntryPublished(TestIdentifier testIdentifier, FileEntry file) { + FileEntryEvent event = new FileEntryEvent(); + event.uniqueId = testIdentifier.getUniqueId(); + event.path = file.getPath().toAbsolutePath().toString(); + event.commit(); + } + @Category({ "JUnit", "Execution" }) @StackTrace(false) abstract static class ExecutionEvent extends Event { @@ -159,4 +168,14 @@ @Label("Value") String value; } + + @Label("File Entry") + @Name("org.junit.FileEntry") + static class FileEntryEvent extends ExecutionEvent { + @UniqueId + @Label("Unique Id") + String uniqueId; + @Label("Path") + String path; + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/UniqueId.java jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/UniqueId.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/UniqueId.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/main/java/org/junit/platform/jfr/UniqueId.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/module/org.junit.platform.jfr/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/module/org.junit.platform.jfr/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-jfr/src/module/org.junit.platform.jfr/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-jfr/src/module/org.junit.platform.jfr/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Provides Java Flight Recorder events for the JUnit Platform. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/AbstractMethodFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/AbstractMethodFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/AbstractMethodFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/AbstractMethodFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher; + +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; + +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.descriptor.MethodSource; + +/** + * Abstract {@link MethodFilter} that servers as a superclass + * for filters including or excluding fully qualified method names + * without parameters based on pattern-matching. + * + * @since 1.12 + */ +abstract class AbstractMethodFilter implements MethodFilter { + + protected final List patterns; + protected final String patternDescription; + + AbstractMethodFilter(String... patterns) { + Preconditions.notEmpty(patterns, "patterns array must not be null or empty"); + Preconditions.containsNoNullElements(patterns, "patterns array must not contain null elements"); + this.patterns = Arrays.stream(patterns).map(Pattern::compile).collect(toList()); + this.patternDescription = Arrays.stream(patterns).collect(joining("' OR '", "'", "'")); + } + + protected Optional findMatchingPattern(String methodName) { + if (methodName == null) { + return Optional.empty(); + } + return this.patterns.stream().filter(pattern -> pattern.matcher(methodName).matches()).findAny(); + } + + protected String getFullyQualifiedMethodNameFromDescriptor(TestDescriptor descriptor) { + return descriptor.getSource() // + .filter(source -> source instanceof MethodSource) // + .map(methodSource -> getFullyQualifiedMethodNameWithoutParameters(((MethodSource) methodSource))) // + .orElse(null); + } + + private String getFullyQualifiedMethodNameWithoutParameters(MethodSource methodSource) { + String methodNameWithParentheses = ReflectionUtils.getFullyQualifiedMethodName(methodSource.getJavaClass(), + methodSource.getMethodName(), (Class[]) null); + return methodNameWithParentheses.substring(0, methodNameWithParentheses.length() - 2); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineDiscoveryResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineDiscoveryResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineDiscoveryResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineDiscoveryResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -100,11 +100,11 @@ @Override public String toString() { // @formatter:off - return new ToStringBuilder(this) - .append("status", status) - .append("throwable", throwable) - .toString(); - // @formatter:on + return new ToStringBuilder(this) + .append("status", status) + .append("throwable", throwable) + .toString(); + // @formatter:on } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/EngineFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/ExcludeMethodFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/ExcludeMethodFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/ExcludeMethodFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/ExcludeMethodFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher; + +import static org.junit.platform.engine.FilterResult.excluded; +import static org.junit.platform.engine.FilterResult.included; + +import java.util.regex.Pattern; + +import org.junit.platform.engine.FilterResult; +import org.junit.platform.engine.TestDescriptor; + +/** + * {@link MethodFilter} that matches fully qualified method names against + * patterns in the form of regular expressions. + * + *

    If the fully qualified name of a method matches against at least one + * pattern, the class will be excluded. + * + * @since 1.12 + */ +class ExcludeMethodFilter extends AbstractMethodFilter { + + ExcludeMethodFilter(String... patterns) { + super(patterns); + } + + @Override + public FilterResult apply(TestDescriptor descriptor) { + String methodName = getFullyQualifiedMethodNameFromDescriptor(descriptor); + return findMatchingPattern(methodName) // + .map(pattern -> excluded(formatExclusionReason(methodName, pattern))) // + .orElseGet(() -> included(formatInclusionReason(methodName))); + } + + private String formatInclusionReason(String methodName) { + return String.format("Method name [%s] does not match any excluded pattern: %s", methodName, + patternDescription); + } + + private String formatExclusionReason(String methodName, Pattern pattern) { + return String.format("Method name [%s] matches excluded pattern: '%s'", methodName, pattern); + } + + @Override + public String toString() { + return String.format("%s that excludes method names that match one of the following regular expressions: %s", + getClass().getSimpleName(), patternDescription); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/IncludeMethodFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/IncludeMethodFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/IncludeMethodFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/IncludeMethodFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher; + +import static org.junit.platform.engine.FilterResult.excluded; +import static org.junit.platform.engine.FilterResult.included; + +import java.util.regex.Pattern; + +import org.junit.platform.engine.FilterResult; +import org.junit.platform.engine.TestDescriptor; + +/** + * {@link MethodFilter} that matches fully qualified method names against + * patterns in the form of regular expressions. + * + *

    If the fully qualified name of a method matches against at least one + * pattern, the method will be included. + * + * @since 1.12 + */ +class IncludeMethodFilter extends AbstractMethodFilter { + + IncludeMethodFilter(String... patterns) { + super(patterns); + } + + @Override + public FilterResult apply(TestDescriptor descriptor) { + String methodName = getFullyQualifiedMethodNameFromDescriptor(descriptor); + return findMatchingPattern(methodName) // + .map(pattern -> included(formatInclusionReason(methodName, pattern))) // + .orElseGet(() -> excluded(formatExclusionReason(methodName))); + } + + private String formatInclusionReason(String methodName, Pattern pattern) { + return String.format("Method name [%s] matches included pattern: '%s'", methodName, pattern); + } + + private String formatExclusionReason(String methodName) { + return String.format("Method name [%s] does not match any included pattern: %s", methodName, + patternDescription); + } + + @Override + public String toString() { + return String.format("%s that includes method names that match one of the following regular expressions: %s", + getClass().getSimpleName(), patternDescription); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/Launcher.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/Launcher.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/Launcher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/Launcher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -36,7 +36,7 @@ * {@linkplain #registerTestExecutionListeners register} one or more * {@link TestExecutionListener} instances in order to get feedback about the * progress and results of test execution. Listeners will be notified of events - * in the order in which they were registered. The default implementation + * in the order in which they were registered. The default implementation * returned by {@link org.junit.platform.launcher.core.LauncherFactory#create} * dynamically discovers test execution listeners via Java's * {@link java.util.ServiceLoader ServiceLoader} mechanism. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,11 +10,12 @@ package org.junit.platform.launcher; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; import org.junit.platform.commons.util.ClassNamePatternFilterUtils; +import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.reporting.ReportEntry; /** @@ -146,7 +147,7 @@ * @see #DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME * @see org.junit.platform.launcher.TestExecutionListener */ - public static final String DEACTIVATE_ALL_LISTENERS_PATTERN = ClassNamePatternFilterUtils.DEACTIVATE_ALL_PATTERN; + public static final String DEACTIVATE_ALL_LISTENERS_PATTERN = ClassNamePatternFilterUtils.ALL_PATTERN; /** * Property name used to enable support for @@ -162,7 +163,7 @@ * * @see LauncherInterceptor */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static final String ENABLE_LAUNCHER_INTERCEPTORS = "junit.platform.launcher.interceptors.enabled"; /** @@ -178,7 +179,7 @@ * *

    Value must be either {@code true} or {@code false}; defaults to {@code false}. */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static final String DRY_RUN_PROPERTY_NAME = "junit.platform.execution.dryRun.enabled"; /** @@ -188,9 +189,86 @@ * * @see org.junit.platform.launcher.core.EngineExecutionOrchestrator */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public static final String STACKTRACE_PRUNING_ENABLED_PROPERTY_NAME = "junit.platform.stacktrace.pruning.enabled"; + /** + * Property name used to configure the output directory for reporting. + * + *

    If set, value must be a valid path that will be created if it doesn't + * exist. If not set, the default output directory will be determined by the + * reporting engine based on the current working directory. + * + * @since 1.12 + * @see #OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER + * @see org.junit.platform.engine.OutputDirectoryCreator + * @see EngineDiscoveryRequest#getOutputDirectoryCreator() + * @see TestPlan#getOutputDirectoryCreator() + */ + @API(status = MAINTAINED, since = "1.13.3") + public static final String OUTPUT_DIR_PROPERTY_NAME = "junit.platform.reporting.output.dir"; + + /** + * Placeholder for use in {@link #OUTPUT_DIR_PROPERTY_NAME} that will be + * replaced with a unique number. + * + *

    This can be used to create a unique output directory for each test + * run. For example, if multiple forks are used, each fork can be configured + * to write its output to a separate directory. + * + * @since 1.12 + * @see #OUTPUT_DIR_PROPERTY_NAME + */ + @API(status = MAINTAINED, since = "1.13.3") + public static final String OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER = "{uniqueNumber}"; + + /** + * Property name used to configure the critical severity of issues + * encountered during test discovery. + * + *

    If an engine reports an issue with a severity equal to or higher than + * the configured critical severity, its tests will not be executed. + * Depending on {@link #DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME}, a + * {@link org.junit.platform.launcher.core.DiscoveryIssueException} listing + * all critical issues will be thrown during discovery or be reported as + * engine-level failure during execution. + * + *

    Supported Values

    + * + *

    Supported values include names of enum constants defined in + * {@link org.junit.platform.engine.DiscoveryIssue.Severity Severity}, + * ignoring case. + * + *

    If not specified, the default is "error" which corresponds to + * {@code Severity.ERROR)}. + * + * @since 1.13 + * @see org.junit.platform.engine.DiscoveryIssue.Severity + */ + @API(status = MAINTAINED, since = "1.13.3") + public static final String CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME = "junit.platform.discovery.issue.severity.critical"; + + /** + * Property name used to configure the phase that critical discovery issues + * should cause a failure + * + *

    Supported Values

    + * + *

    Supported values are "discovery" or "execution". + * + *

    If not specified, the {@code Launcher} will report discovery issues + * during the discovery phase if + * {@link Launcher#discover(LauncherDiscoveryRequest)} is called, and during + * the execution phase if + * {@link Launcher#execute(LauncherDiscoveryRequest, TestExecutionListener...)} + * is called. + * + * @since 1.13 + * @see #CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME + */ + @API(status = MAINTAINED, since = "1.13.3") + public static final String DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME = "junit.platform.discovery.issue.failure.phase"; + private LauncherConstants() { /* no-op */ } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryRequest.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryRequest.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryRequest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherDiscoveryRequest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherInterceptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherInterceptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherInterceptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherInterceptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.launcher; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import org.apiguardian.api.API; @@ -52,7 +52,7 @@ * @see LauncherSession * @see LauncherConstants#ENABLE_LAUNCHER_INTERCEPTORS */ -@API(status = EXPERIMENTAL, since = "1.10") +@API(status = MAINTAINED, since = "1.13.3") public interface LauncherInterceptor { /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSession.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSession.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSession.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSession.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,9 +10,12 @@ package org.junit.platform.launcher; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.core.LauncherFactory; /** @@ -47,4 +50,19 @@ @Override void close(); + /** + * Get the {@link NamespacedHierarchicalStore} associated with this session. + * + *

    All stored values that implement {@link AutoCloseable} are notified by + * invoking their {@code close()} methods when this session is closed. + * + *

    Any call to the store returned by this method after the session has + * been closed will throw an exception. + * + * @since 1.13 + * @see NamespacedHierarchicalStore + */ + @API(status = MAINTAINED, since = "1.13.3") + NamespacedHierarchicalStore getStore(); + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSessionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSessionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSessionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherSessionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/MethodFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/MethodFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/MethodFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/MethodFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.lang.reflect.Method; +import java.util.List; + +import org.apiguardian.api.API; + +/** + * {@link PostDiscoveryFilter} that is applied to the fully qualified + * {@link Method} name without parameters. + * + * @since 1.12 + * @see #includeMethodNamePatterns(String...) + * @see #excludeMethodNamePatterns(String...) + */ +@API(status = MAINTAINED, since = "1.13.3") +public interface MethodFilter extends PostDiscoveryFilter { + + /** + * Create a new include {@link MethodFilter} based on the + * supplied patterns. + * + *

    The patterns are combined using OR semantics, i.e. if the fully + * qualified name of a method matches against at least one of the patterns, + * the method will be included in the result set. + * + * @param patterns regular expressions to match against fully qualified + * method names; never {@code null}, empty, or containing {@code null} + * @see Class#getName() + * @see Method#getName() + * @see #includeMethodNamePatterns(List) + * @see #excludeMethodNamePatterns(String...) + */ + static MethodFilter includeMethodNamePatterns(String... patterns) { + return new IncludeMethodFilter(patterns); + } + + /** + * Create a new include {@link MethodFilter} based on the + * supplied patterns. + * + *

    The patterns are combined using OR semantics, i.e. if the fully + * qualified name of a method matches against at least one of the patterns, + * the method will be included in the result set. + * + * @param patterns regular expressions to match against fully qualified + * method names; never {@code null}, empty, or containing {@code null} + * @see Class#getName() + * @see Method#getName() + * @see #includeMethodNamePatterns(String...) + * @see #excludeMethodNamePatterns(String...) + */ + static MethodFilter includeMethodNamePatterns(List patterns) { + return includeMethodNamePatterns(patterns.toArray(new String[0])); + } + + /** + * Create a new exclude {@link MethodFilter} based on the + * supplied patterns. + * + *

    The patterns are combined using OR semantics, i.e. if the fully + * qualified name of a method matches against at least one of the patterns, + * the method will be excluded from the result set. + * + * @param patterns regular expressions to match against fully qualified + * method names; never {@code null}, empty, or containing {@code null} + * @see Class#getName() + * @see Method#getName() + * @see #excludeMethodNamePatterns(List) + * @see #includeMethodNamePatterns(String...) + */ + static MethodFilter excludeMethodNamePatterns(String... patterns) { + return new ExcludeMethodFilter(patterns); + } + + /** + * Create a new exclude {@link MethodFilter} based on the + * supplied patterns. + * + *

    The patterns are combined using OR semantics, i.e. if the fully + * qualified name of a method matches against at least one of the patterns, + * the method will be excluded from the result set. + * + * @param patterns regular expressions to match against fully qualified + * method names; never {@code null}, empty, or containing {@code null} + * @see Class#getName() + * @see Method#getName() + * @see #excludeMethodNamePatterns(String...) + * @see #includeMethodNamePatterns(String...) + */ + static MethodFilter excludeMethodNamePatterns(List patterns) { + return excludeMethodNamePatterns(patterns.toArray(new String[0])); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/PostDiscoveryFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/PostDiscoveryFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/PostDiscoveryFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/PostDiscoveryFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TagFilter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TagFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TagFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TagFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -33,7 +33,7 @@ *

    Tag expressions are boolean expressions with the following allowed * operators: {@code !} (not), {@code &} (and), and {@code |} (or). Parentheses * can be used to adjust for operator precedence. Please refer to the - * JUnit 5 User Guide + * JUnit 5 User Guide * for usage examples. * *

    Please note that a tag name is a valid tag expression. Thus, wherever a tag diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,12 +10,14 @@ package org.junit.platform.launcher; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; import org.apiguardian.api.API; import org.junit.platform.commons.util.UnrecoverableExceptions; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.TestExecutionResult.Status; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; /** @@ -184,4 +186,17 @@ default void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry entry) { } + /** + * Called when a file or directory has been published for the supplied + * {@link TestIdentifier}. + * + *

    Can be called at any time during the execution of a test plan. + * + * @param testIdentifier describes the test or container to which the entry pertains + * @param file the published {@code FileEntry} + * @since 1.12 + */ + @API(status = MAINTAINED, since = "1.13.3") + default void fileEntryPublished(TestIdentifier testIdentifier, FileEntry file) { + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -122,9 +122,9 @@ * behind the scenes. * * @return the unique ID for this identifier; never {@code null} - * @since 5.8 + * @since 1.8 */ - @API(status = STABLE, since = "5.8") + @API(status = STABLE, since = "1.8") public UniqueId getUniqueIdObject() { return this.uniqueId; } @@ -150,9 +150,9 @@ * * @return a container for the unique ID for this identifier's parent; * never {@code null} though potentially empty - * @since 5.8 + * @since 1.8 */ - @API(status = STABLE, since = "5.8") + @API(status = STABLE, since = "1.8") public Optional getParentIdObject() { return Optional.ofNullable(this.parentId); } @@ -291,7 +291,7 @@ /** * Represents the serialized output of {@code TestIdentifier}. The fields on this - * class match the fields that {@code TestIdentifier} had prior to 5.8. + * class match the fields that {@code TestIdentifier} had prior to 1.8. */ private static class SerializedForm implements Serializable { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestPlan.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestPlan.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestPlan.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestPlan.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,7 +14,6 @@ import static java.util.Collections.synchronizedSet; import static java.util.Collections.unmodifiableSet; import static org.apiguardian.api.API.Status.DEPRECATED; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; @@ -32,6 +31,7 @@ import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; @@ -62,14 +62,12 @@ public class TestPlan { private final Set roots = synchronizedSet(new LinkedHashSet<>(4)); - private final Map> children = new ConcurrentHashMap<>(32); - private final Map allIdentifiers = new ConcurrentHashMap<>(32); private final boolean containsTests; - private final ConfigurationParameters configurationParameters; + private final OutputDirectoryCreator outputDirectoryCreator; /** * Construct a new {@code TestPlan} from the supplied collection of @@ -78,28 +76,32 @@ *

    Each supplied {@code TestDescriptor} is expected to be a descriptor * for a {@link org.junit.platform.engine.TestEngine TestEngine}. * + * @param containsTests whether the test plan contains tests * @param engineDescriptors the engine test descriptors from which the test * plan should be created; never {@code null} * @param configurationParameters the {@code ConfigurationParameters} for * this test plan; never {@code null} + * @param outputDirectoryCreator the {@code OutputDirectoryProvider} for + * this test plan; never {@code null} * @return a new test plan */ - @API(status = INTERNAL, since = "1.0") - public static TestPlan from(Collection engineDescriptors, - ConfigurationParameters configurationParameters) { + @API(status = INTERNAL, since = "1.14") + public static TestPlan from(boolean containsTests, Collection engineDescriptors, + ConfigurationParameters configurationParameters, OutputDirectoryCreator outputDirectoryCreator) { Preconditions.notNull(engineDescriptors, "Cannot create TestPlan from a null collection of TestDescriptors"); Preconditions.notNull(configurationParameters, "Cannot create TestPlan from null ConfigurationParameters"); - TestPlan testPlan = new TestPlan(engineDescriptors.stream().anyMatch(TestDescriptor::containsTests), - configurationParameters); + TestPlan testPlan = new TestPlan(containsTests, configurationParameters, outputDirectoryCreator); TestDescriptor.Visitor visitor = descriptor -> testPlan.addInternal(TestIdentifier.from(descriptor)); engineDescriptors.forEach(engineDescriptor -> engineDescriptor.accept(visitor)); return testPlan; } @API(status = INTERNAL, since = "1.4") - protected TestPlan(boolean containsTests, ConfigurationParameters configurationParameters) { + protected TestPlan(boolean containsTests, ConfigurationParameters configurationParameters, + OutputDirectoryCreator outputDirectoryCreator) { this.containsTests = containsTests; this.configurationParameters = configurationParameters; + this.outputDirectoryCreator = outputDirectoryCreator; } /** @@ -292,13 +294,39 @@ } /** + * Get the + * {@link org.junit.platform.engine.reporting.OutputDirectoryProvider} for + * this test plan. + * + * @return the output directory provider; never {@code null} + * @since 1.12 + * @deprecated Please use {@link #getOutputDirectoryCreator()} instead + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + public org.junit.platform.engine.reporting.OutputDirectoryProvider getOutputDirectoryProvider() { + return org.junit.platform.engine.reporting.OutputDirectoryProvider.castOrAdapt(getOutputDirectoryCreator()); + } + + /** + * Get the {@link OutputDirectoryCreator} for this test plan. + * + * @return the output directory creator; never {@code null} + * @since 1.14 + */ + @API(status = MAINTAINED, since = "1.14") + public OutputDirectoryCreator getOutputDirectoryCreator() { + return outputDirectoryCreator; + } + + /** * Accept the supplied {@link Visitor} for a depth-first traversal of the * test plan. * * @param visitor the visitor to accept; never {@code null} * @since 1.10 */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public void accept(Visitor visitor) { getRoots().forEach(it -> accept(visitor, it)); } @@ -319,7 +347,7 @@ * * @since 1.10 */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") public interface Visitor { /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentChecker.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentChecker.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentChecker.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentChecker.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,110 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static java.util.Collections.unmodifiableList; +import static java.util.Comparator.comparing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.util.ClassLoaderUtils; + +/** + * @since 1.12 + */ +class ClasspathAlignmentChecker { + + // VisibleForTesting + static final List WELL_KNOWN_PACKAGES = unmodifiableList(Arrays.asList( // + "org.junit.jupiter.api", // + "org.junit.jupiter.engine", // + "org.junit.jupiter.migrationsupport", // + "org.junit.jupiter.params", // + "org.junit.platform.commons", // + "org.junit.platform.console", // + "org.junit.platform.engine", // + "org.junit.platform.jfr", // + "org.junit.platform.launcher", // + "org.junit.platform.reporting", // + "org.junit.platform.runner", // + "org.junit.platform.suite.api", // + "org.junit.platform.suite.commons", // + "org.junit.platform.suite.engine", // + "org.junit.platform.testkit", // + "org.junit.vintage.engine" // + )); + + static Optional check(LinkageError error) { + ClassLoader classLoader = ClassLoaderUtils.getClassLoader(ClasspathAlignmentChecker.class); + Function packageLookup = name -> ReflectionSupport.findMethod(ClassLoader.class, + "getDefinedPackage", String.class) // + .map(m -> (Package) ReflectionSupport.invokeMethod(m, classLoader, name)) // + .orElseGet(() -> getPackage(name)); + return check(error, packageLookup); + } + + // VisibleForTesting + static Optional check(LinkageError error, Function packageLookup) { + Map> packagesByVersions = new HashMap<>(); + WELL_KNOWN_PACKAGES.stream() // + .map(packageLookup) // + .filter(Objects::nonNull) // + .forEach(pkg -> { + String version = pkg.getImplementationVersion(); + if (version != null) { + if (pkg.getName().startsWith("org.junit.platform") && version.contains(".")) { + version = platformToJupiterVersion(version); + } + packagesByVersions.computeIfAbsent(version, __ -> new ArrayList<>()).add(pkg); + } + }); + if (packagesByVersions.size() > 1) { + StringBuilder message = new StringBuilder(); + String lineBreak = System.lineSeparator(); + message.append("The wrapped ").append(error.getClass().getSimpleName()) // + .append(" is likely caused by the versions of JUnit jars on the classpath/module path ") // + .append("not being properly aligned. ") // + .append(lineBreak) // + .append("Please ensure consistent versions are used (see https://docs.junit.org/") // + .append(platformToJupiterVersion( + ClasspathAlignmentChecker.class.getPackage().getImplementationVersion())) // + .append("/user-guide/#dependency-metadata).") // + .append(lineBreak) // + .append("The following conflicting versions were detected:").append(lineBreak); + packagesByVersions.values().stream() // + .flatMap(List::stream) // + .sorted(comparing(Package::getName)) // + .map(pkg -> String.format("- %s: %s%n", pkg.getName(), pkg.getImplementationVersion())) // + .forEach(message::append); + return Optional.of(new JUnitException(message.toString(), error)); + } + return Optional.empty(); + } + + private static String platformToJupiterVersion(String version) { + int majorVersion = Integer.parseInt(version.substring(0, version.indexOf("."))) + 4; + return majorVersion + version.substring(version.indexOf(".")); + } + + @SuppressWarnings({ "deprecation", "RedundantSuppression" }) // only called when running on JDK 8 + private static Package getPackage(String name) { + return Package.getPackage(name); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckingLauncherInterceptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckingLauncherInterceptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckingLauncherInterceptor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckingLauncherInterceptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import java.util.Optional; + +import org.junit.platform.commons.JUnitException; +import org.junit.platform.launcher.LauncherInterceptor; + +class ClasspathAlignmentCheckingLauncherInterceptor implements LauncherInterceptor { + + static final LauncherInterceptor INSTANCE = new ClasspathAlignmentCheckingLauncherInterceptor(); + + @Override + public T intercept(Invocation invocation) { + try { + return invocation.proceed(); + } + catch (LinkageError e) { + Optional exception = ClasspathAlignmentChecker.check(e); + if (exception.isPresent()) { + throw exception.get(); + } + throw e; + } + } + + @Override + public void close() { + // do nothing + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeEngineExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeEngineExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeEngineExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeEngineExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,6 +21,7 @@ import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; class CompositeEngineExecutionListener implements EngineExecutionListener { @@ -67,6 +68,13 @@ () -> "reportingEntryPublished(" + testDescriptor + ", " + entry + ")"); } + @Override + public void fileEntryPublished(TestDescriptor testDescriptor, FileEntry file) { + notifyEach(engineExecutionListeners, IterationOrder.ORIGINAL, + listener -> listener.fileEntryPublished(testDescriptor, file), + () -> "fileEntryPublished(" + testDescriptor + ", " + file + ")"); + } + private static void notifyEach(List listeners, IterationOrder iterationOrder, Consumer consumer, Supplier description) { iterationOrder.forEach(listeners, listener -> { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeTestExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeTestExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeTestExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/CompositeTestExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,6 +21,7 @@ import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.UnrecoverableExceptions; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; @@ -95,6 +96,13 @@ () -> "reportingEntryPublished(" + testIdentifier + ", " + entry + ")"); } + @Override + public void fileEntryPublished(TestIdentifier testIdentifier, FileEntry file) { + notifyEach(testExecutionListeners, IterationOrder.ORIGINAL, + listener -> listener.fileEntryPublished(testIdentifier, file), + () -> "fileEntryPublished(" + testIdentifier + ", " + file + ")"); + } + private static void notifyEach(List listeners, IterationOrder iterationOrder, Consumer consumer, Supplier description) { iterationOrder.forEach(listeners, listener -> { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultDiscoveryRequest.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultDiscoveryRequest.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultDiscoveryRequest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultDiscoveryRequest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,6 +20,7 @@ import org.junit.platform.engine.DiscoveryFilter; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.EngineDiscoveryRequest; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.launcher.EngineFilter; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; @@ -51,15 +52,19 @@ // Listener for test discovery that may abort on errors. private final LauncherDiscoveryListener discoveryListener; + private final OutputDirectoryCreator outputDirectoryCreator; + DefaultDiscoveryRequest(List selectors, List engineFilters, List> discoveryFilters, List postDiscoveryFilters, - LauncherConfigurationParameters configurationParameters, LauncherDiscoveryListener discoveryListener) { + LauncherConfigurationParameters configurationParameters, LauncherDiscoveryListener discoveryListener, + OutputDirectoryCreator outputDirectoryCreator) { this.selectors = selectors; this.engineFilters = engineFilters; this.discoveryFilters = discoveryFilters; this.postDiscoveryFilters = postDiscoveryFilters; this.configurationParameters = configurationParameters; this.discoveryListener = discoveryListener; + this.outputDirectoryCreator = outputDirectoryCreator; } @Override @@ -91,7 +96,12 @@ @Override public LauncherDiscoveryListener getDiscoveryListener() { - return discoveryListener; + return this.discoveryListener; + } + + @Override + public OutputDirectoryCreator getOutputDirectoryCreator() { + return this.outputDirectoryCreator; } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncher.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncher.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,13 +11,16 @@ package org.junit.platform.launcher.core; import static java.util.Collections.unmodifiableCollection; -import static org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.Phase.DISCOVERY; -import static org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.Phase.EXECUTION; +import static org.junit.platform.engine.support.store.NamespacedHierarchicalStore.CloseAction.closeAutoCloseables; +import static org.junit.platform.launcher.core.LauncherPhase.DISCOVERY; +import static org.junit.platform.launcher.core.LauncherPhase.EXECUTION; import java.util.Collection; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.TestEngine; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; @@ -41,6 +44,7 @@ private final EngineExecutionOrchestrator executionOrchestrator = new EngineExecutionOrchestrator( listenerRegistry.testExecutionListeners); private final EngineDiscoveryOrchestrator discoveryOrchestrator; + private final NamespacedHierarchicalStore sessionLevelStore; /** * Construct a new {@code DefaultLauncher} with the supplied test engines. @@ -50,7 +54,8 @@ * @param postDiscoveryFilters the additional post discovery filters for * discovery requests; never {@code null} */ - DefaultLauncher(Iterable testEngines, Collection postDiscoveryFilters) { + DefaultLauncher(Iterable testEngines, Collection postDiscoveryFilters, + NamespacedHierarchicalStore sessionLevelStore) { Preconditions.condition(testEngines != null && testEngines.iterator().hasNext(), () -> "Cannot create Launcher without at least one TestEngine; " + "consider adding an engine implementation JAR to the classpath"); @@ -59,6 +64,7 @@ "PostDiscoveryFilter array must not contain null elements"); this.discoveryOrchestrator = new EngineDiscoveryOrchestrator(testEngines, unmodifiableCollection(postDiscoveryFilters), listenerRegistry.launcherDiscoveryListeners); + this.sessionLevelStore = sessionLevelStore; } @Override @@ -94,13 +100,18 @@ execute((InternalTestPlan) testPlan, listeners); } - private LauncherDiscoveryResult discover(LauncherDiscoveryRequest discoveryRequest, - EngineDiscoveryOrchestrator.Phase phase) { + private LauncherDiscoveryResult discover(LauncherDiscoveryRequest discoveryRequest, LauncherPhase phase) { return discoveryOrchestrator.discover(discoveryRequest, phase); } private void execute(InternalTestPlan internalTestPlan, TestExecutionListener[] listeners) { - executionOrchestrator.execute(internalTestPlan, listeners); + try (NamespacedHierarchicalStore requestLevelStore = createRequestLevelStore()) { + executionOrchestrator.execute(internalTestPlan, requestLevelStore, listeners); + } + } + + private NamespacedHierarchicalStore createRequestLevelStore() { + return new NamespacedHierarchicalStore<>(sessionLevelStore, closeAutoCloseables()); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherConfig.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherConfig.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherConfig.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherConfig.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherSession.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherSession.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherSession.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherSession.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,15 @@ package org.junit.platform.launcher.core; +import static org.junit.platform.engine.support.store.NamespacedHierarchicalStore.CloseAction.closeAutoCloseables; + import java.util.List; +import java.util.function.Function; import java.util.function.Supplier; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; @@ -40,21 +45,26 @@ } }; + private final NamespacedHierarchicalStore store = new NamespacedHierarchicalStore<>(null, + closeAutoCloseables()); private final LauncherInterceptor interceptor; private final LauncherSessionListener listener; private final DelegatingLauncher launcher; - DefaultLauncherSession(List interceptors, Supplier listenerSupplier, - Supplier launcherSupplier) { + DefaultLauncherSession(List interceptors, // + Supplier listenerSupplier, // + Function, Launcher> launcherFactory // + ) { interceptor = composite(interceptors); Launcher launcher; if (interceptor == NOOP_INTERCEPTOR) { this.listener = listenerSupplier.get(); - launcher = launcherSupplier.get(); + launcher = launcherFactory.apply(this.store); } else { this.listener = interceptor.intercept(listenerSupplier::get); - launcher = new InterceptingLauncher(interceptor.intercept(launcherSupplier::get), interceptor); + launcher = new InterceptingLauncher(interceptor.intercept(() -> launcherFactory.apply(this.store)), + interceptor); } this.launcher = new DelegatingLauncher(launcher); listener.launcherSessionOpened(this); @@ -74,10 +84,16 @@ if (launcher.delegate != ClosedLauncher.INSTANCE) { launcher.delegate = ClosedLauncher.INSTANCE; listener.launcherSessionClosed(this); + store.close(); interceptor.close(); } } + @Override + public NamespacedHierarchicalStore getStore() { + return store; + } + private static class ClosedLauncher implements Launcher { static final ClosedLauncher INSTANCE = new ClosedLauncher(); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingEngineExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingEngineExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingEngineExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingEngineExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; /** @@ -51,4 +52,8 @@ delegate.reportingEntryPublished(testDescriptor, entry); } + @Override + public void fileEntryPublished(TestDescriptor testDescriptor, FileEntry file) { + delegate.fileEntryPublished(testDescriptor, file); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncher.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncher.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncherDiscoveryRequest.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncherDiscoveryRequest.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncherDiscoveryRequest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DelegatingLauncherDiscoveryRequest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import java.util.List; + +import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.DiscoveryFilter; +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.OutputDirectoryCreator; +import org.junit.platform.launcher.EngineFilter; +import org.junit.platform.launcher.LauncherDiscoveryListener; +import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.PostDiscoveryFilter; + +/** + * @since 1.13 + */ +class DelegatingLauncherDiscoveryRequest implements LauncherDiscoveryRequest { + + private final LauncherDiscoveryRequest request; + + DelegatingLauncherDiscoveryRequest(LauncherDiscoveryRequest request) { + this.request = request; + } + + public List getEngineFilters() { + return this.request.getEngineFilters(); + } + + public List getPostDiscoveryFilters() { + return this.request.getPostDiscoveryFilters(); + } + + public LauncherDiscoveryListener getDiscoveryListener() { + return this.request.getDiscoveryListener(); + } + + public List getSelectorsByType(Class selectorType) { + return this.request.getSelectorsByType(selectorType); + } + + public > List getFiltersByType(Class filterType) { + return this.request.getFiltersByType(filterType); + } + + public ConfigurationParameters getConfigurationParameters() { + return this.request.getConfigurationParameters(); + } + + @SuppressWarnings("deprecation") + @Override + public org.junit.platform.engine.reporting.OutputDirectoryProvider getOutputDirectoryProvider() { + return this.request.getOutputDirectoryProvider(); + } + + @Override + public OutputDirectoryCreator getOutputDirectoryCreator() { + return this.request.getOutputDirectoryCreator(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueCollector.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueCollector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueCollector.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueCollector.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,161 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.junit.platform.commons.util.UnrecoverableExceptions.rethrowIfUnrecoverable; +import static org.junit.platform.engine.SelectorResolutionResult.Status.FAILED; +import static org.junit.platform.engine.SelectorResolutionResult.Status.UNRESOLVED; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.SelectorResolutionResult; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.discovery.ClassSelector; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; +import org.junit.platform.engine.discovery.DirectorySelector; +import org.junit.platform.engine.discovery.FileSelector; +import org.junit.platform.engine.discovery.MethodSelector; +import org.junit.platform.engine.discovery.PackageSelector; +import org.junit.platform.engine.discovery.UniqueIdSelector; +import org.junit.platform.engine.discovery.UriSelector; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.descriptor.ClasspathResourceSource; +import org.junit.platform.engine.support.descriptor.DirectorySource; +import org.junit.platform.engine.support.descriptor.FilePosition; +import org.junit.platform.engine.support.descriptor.FileSource; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.descriptor.PackageSource; +import org.junit.platform.engine.support.descriptor.UriSource; +import org.junit.platform.launcher.LauncherConstants; +import org.junit.platform.launcher.LauncherDiscoveryListener; + +class DiscoveryIssueCollector implements LauncherDiscoveryListener { + + private static final Logger logger = LoggerFactory.getLogger(DiscoveryIssueCollector.class); + + final List issues = new ArrayList<>(); + private final ConfigurationParameters configurationParameters; + + DiscoveryIssueCollector(ConfigurationParameters configurationParameters) { + this.configurationParameters = configurationParameters; + } + + @Override + public void engineDiscoveryStarted(UniqueId engineId) { + this.issues.clear(); + } + + @Override + public void selectorProcessed(UniqueId engineId, DiscoverySelector selector, SelectorResolutionResult result) { + if (result.getStatus() == FAILED) { + this.issues.add(DiscoveryIssue.builder(Severity.ERROR, selector + " resolution failed") // + .cause(result.getThrowable()) // + .source(toSource(selector)) // + .build()); + } + else if (result.getStatus() == UNRESOLVED && selector instanceof UniqueIdSelector) { + UniqueId uniqueId = ((UniqueIdSelector) selector).getUniqueId(); + if (uniqueId.hasPrefix(engineId)) { + this.issues.add(DiscoveryIssue.create(Severity.ERROR, selector + " could not be resolved")); + } + } + } + + private static TestSource toSource(DiscoverySelector selector) { + if (selector instanceof ClassSelector) { + return ClassSource.from(((ClassSelector) selector).getClassName()); + } + if (selector instanceof MethodSelector) { + MethodSelector methodSelector = (MethodSelector) selector; + return MethodSource.from(methodSelector.getClassName(), methodSelector.getMethodName(), + methodSelector.getParameterTypeNames()); + } + if (selector instanceof ClasspathResourceSelector) { + ClasspathResourceSelector resourceSelector = (ClasspathResourceSelector) selector; + String resourceName = resourceSelector.getClasspathResourceName(); + return resourceSelector.getPosition() // + .map(DiscoveryIssueCollector::convert) // + .map(position -> ClasspathResourceSource.from(resourceName, position)) // + .orElseGet(() -> ClasspathResourceSource.from(resourceName)); + } + if (selector instanceof PackageSelector) { + return PackageSource.from(((PackageSelector) selector).getPackageName()); + } + try { + // Both FileSource and DirectorySource call File.getCanonicalFile() to normalize the reported file which + // can throw an exception for certain file names on certain file systems. UriSource.from(...) is affected + // as well because it may return a FileSource or DirectorySource + if (selector instanceof FileSelector) { + FileSelector fileSelector = (FileSelector) selector; + return fileSelector.getPosition() // + .map(DiscoveryIssueCollector::convert) // + .map(position -> FileSource.from(fileSelector.getFile(), position)) // + .orElseGet(() -> FileSource.from(fileSelector.getFile())); + } + if (selector instanceof DirectorySelector) { + return DirectorySource.from(((DirectorySelector) selector).getDirectory()); + } + if (selector instanceof UriSelector) { + return UriSource.from(((UriSelector) selector).getUri()); + } + } + catch (Exception ex) { + rethrowIfUnrecoverable(ex); + logger.warn(ex, () -> String.format("Failed to convert DiscoverySelector [%s] into TestSource", selector)); + } + return null; + } + + private static FilePosition convert(org.junit.platform.engine.discovery.FilePosition position) { + return position.getColumn() // + .map(column -> FilePosition.from(position.getLine(), column)) // + .orElseGet(() -> FilePosition.from(position.getLine())); + } + + @Override + public void issueEncountered(UniqueId engineId, DiscoveryIssue issue) { + this.issues.add(issue); + } + + DiscoveryIssueNotifier toNotifier() { + if (this.issues.isEmpty()) { + return DiscoveryIssueNotifier.NO_ISSUES; + } + return DiscoveryIssueNotifier.from(getCriticalSeverity(), this.issues); + } + + private Severity getCriticalSeverity() { + Severity defaultValue = Severity.ERROR; + return this.configurationParameters // + .get(LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, value -> { + try { + return Severity.valueOf(value.toUpperCase(Locale.ROOT)); + } + catch (Exception e) { + logger.warn(() -> String.format( + "Invalid DiscoveryIssue.Severity '%s' set via the '%s' configuration parameter. " + + "Falling back to the %s default value.", + value, LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, defaultValue)); + return defaultValue; + } + }) // + .orElse(defaultValue); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueException.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueException.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueException.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueException.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.apiguardian.api.API.Status.MAINTAINED; + +import org.apiguardian.api.API; +import org.junit.platform.commons.JUnitException; + +/** + * {@code DiscoveryIssueException} is an exception that is thrown if an engine + * reports critical issues during test discovery. + * + * @since 1.13 + */ +@API(status = MAINTAINED, since = "1.13.3") +public class DiscoveryIssueException extends JUnitException { + + private static final long serialVersionUID = 1L; + + DiscoveryIssueException(String message) { + super(message, null, false, false); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueNotifier.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueNotifier.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueNotifier.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DiscoveryIssueNotifier.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,143 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static java.util.Collections.emptyList; +import static java.util.Comparator.comparing; +import static java.util.stream.Collectors.partitioningBy; +import static org.junit.platform.commons.util.ExceptionUtils.readStackTrace; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.TestEngine; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.descriptor.MethodSource; + +/** + * @since 1.13 + */ +class DiscoveryIssueNotifier { + + static final DiscoveryIssueNotifier NO_ISSUES = new DiscoveryIssueNotifier(emptyList(), emptyList(), emptyList()); + private static final Logger logger = LoggerFactory.getLogger(DiscoveryIssueNotifier.class); + + private final List allIssues; + private final List criticalIssues; + private final List nonCriticalIssues; + + static DiscoveryIssueNotifier from(Severity criticalSeverity, List issues) { + Map> issuesByCriticality = issues.stream() // + .sorted(comparing(DiscoveryIssue::severity).reversed()) // + .collect(partitioningBy(issue -> issue.severity().compareTo(criticalSeverity) >= 0)); + List criticalIssues = issuesByCriticality.get(true); + List nonCriticalIssues = issuesByCriticality.get(false); + return new DiscoveryIssueNotifier(new ArrayList<>(issues), criticalIssues, nonCriticalIssues); + } + + private DiscoveryIssueNotifier(List allIssues, List criticalIssues, + List nonCriticalIssues) { + this.allIssues = allIssues; + this.criticalIssues = criticalIssues; + this.nonCriticalIssues = nonCriticalIssues; + } + + List getAllIssues() { + return allIssues; + } + + boolean hasCriticalIssues() { + return !criticalIssues.isEmpty(); + } + + void logCriticalIssues(TestEngine testEngine) { + logIssues(testEngine, criticalIssues, "critical"); + } + + void logNonCriticalIssues(TestEngine testEngine) { + logIssues(testEngine, nonCriticalIssues, "non-critical"); + } + + DiscoveryIssueException createExceptionForCriticalIssues(TestEngine testEngine) { + if (criticalIssues.isEmpty()) { + return null; + } + String message = formatMessage(testEngine, criticalIssues, "critical"); + return new DiscoveryIssueException(message); + } + + private void logIssues(TestEngine testEngine, List issues, String adjective) { + if (!issues.isEmpty()) { + Severity maxSeverity = issues.get(0).severity(); + logger(maxSeverity).accept(() -> formatMessage(testEngine, issues, adjective)); + } + } + + private static Consumer> logger(Severity severity) { + // TODO [#4246] Use switch expression + switch (severity) { + case INFO: + return logger::info; + case WARNING: + return logger::warn; + case ERROR: + return logger::error; + default: + throw new IllegalArgumentException("Unknown severity: " + severity); + } + } + + private static String formatMessage(TestEngine testEngine, List issues, String adjective) { + Preconditions.notNull(testEngine, "testEngine must not be null"); + Preconditions.notNull(issues, "issues must not be null"); + Preconditions.notEmpty(issues, "issues must not be empty"); + String engineId = testEngine.getId(); + StringBuilder message = new StringBuilder(); + message.append("TestEngine with ID '").append(engineId).append("' encountered "); + if (issues.size() == 1) { + message.append("a ").append(adjective).append(" issue"); + } + else { + message.append(issues.size()).append(' ').append(adjective).append(" issues"); + } + message.append(" during test discovery:"); + for (int i = 0; i < issues.size(); i++) { + DiscoveryIssue issue = issues.get(i); + message.append("\n\n(").append(i + 1).append(") [").append(issue.severity()).append("] ").append( + issue.message()); + issue.source().ifPresent(source -> { + message.append("\n Source: ").append(source); + if (source instanceof MethodSource) { + MethodSource methodSource = (MethodSource) source; + appendIdeCompatibleLink(message, methodSource.getClassName(), methodSource.getMethodName()); + } + else if (source instanceof ClassSource) { + ClassSource classSource = (ClassSource) source; + appendIdeCompatibleLink(message, classSource.getClassName(), ""); + } + }); + issue.cause().ifPresent(t -> message.append("\n Cause: ").append(readStackTrace(t))); + } + return message.toString(); + } + + private static void appendIdeCompatibleLink(StringBuilder message, String className, String methodName) { + message.append("\n at ").append(className).append(".").append(methodName).append("(SourceFile:0)"); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryErrorDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryErrorDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryErrorDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryErrorDescriptor.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.launcher.core; - -import org.junit.platform.engine.TestEngine; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor; -import org.junit.platform.engine.support.descriptor.ClassSource; - -/** - * Represents an error thrown by a {@link org.junit.platform.engine.TestEngine} - * during discovery. - * - *

    The contained {@link Throwable} will be reported as the cause of a test - * failure by the {@link DefaultLauncher} when execution is started for this - * engine. - * - * @since 1.6 - */ -class EngineDiscoveryErrorDescriptor extends AbstractTestDescriptor { - - private final Throwable cause; - - EngineDiscoveryErrorDescriptor(UniqueId uniqueId, TestEngine testEngine, Throwable cause) { - super(uniqueId, testEngine.getId(), ClassSource.from(testEngine.getClass())); - this.cause = cause; - } - - Throwable getCause() { - return cause; - } - - @Override - public Type getType() { - return Type.TEST; - } - - @Override - public void prune() { - // prevent pruning - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryOrchestrator.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryOrchestrator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryOrchestrator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryOrchestrator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,12 +13,12 @@ import static java.util.stream.Collectors.joining; import static org.apiguardian.api.API.Status.INTERNAL; import static org.junit.platform.engine.Filter.composeFilters; +import static org.junit.platform.launcher.core.LauncherPhase.getDiscoveryIssueFailurePhase; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.Function; @@ -28,16 +28,18 @@ import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.UnrecoverableExceptions; -import org.junit.platform.engine.EngineExecutionListener; +import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.Filter; import org.junit.platform.engine.FilterResult; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.EngineDescriptor; import org.junit.platform.launcher.EngineDiscoveryResult; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.PostDiscoveryFilter; +import org.junit.platform.launcher.core.LauncherDiscoveryResult.EngineResultInfo; /** * Orchestrates test discovery using the configured test engines. @@ -67,16 +69,19 @@ } /** - * Discovers tests for the supplied request in the supplied phase using the - * configured test engines. + * Discovers tests for the supplied request using the configured test + * engines. * *

    Applies {@linkplain org.junit.platform.launcher.EngineFilter engine * filters} and {@linkplain PostDiscoveryFilter post-discovery filters} and * {@linkplain TestDescriptor#prune() prunes} the resulting test tree. */ - public LauncherDiscoveryResult discover(LauncherDiscoveryRequest request, Phase phase) { - Map result = discover(request, phase, UniqueId::forEngine); - return new LauncherDiscoveryResult(result, request.getConfigurationParameters()); + public LauncherDiscoveryResult discover(LauncherDiscoveryRequest request) { + return discover(request, Optional.empty(), UniqueId::forEngine); + } + + LauncherDiscoveryResult discover(LauncherDiscoveryRequest request, LauncherPhase phase) { + return discover(request, Optional.of(phase), UniqueId::forEngine); } /** @@ -87,50 +92,87 @@ * filters} and {@linkplain PostDiscoveryFilter post-discovery filters} and * {@linkplain TestDescriptor#prune() prunes} the resulting test tree. * - * Note: The test descriptors in the discovery result can safely be used as - * non-root descriptors. Engine-test descriptor entries are pruned from + *

    Note: The test descriptors in the discovery result can safely be used + * as non-root descriptors. Engine-test descriptor entries are pruned from * the returned result. As such execution by - * {@link EngineExecutionOrchestrator#execute(LauncherDiscoveryResult, EngineExecutionListener)} - * will not emit start or emit events for engines without tests. + * {@link EngineExecutionOrchestrator} will not emit start or emit events + * for engines without tests. */ - public LauncherDiscoveryResult discover(LauncherDiscoveryRequest request, Phase phase, UniqueId parentId) { - Map testEngines = discover(request, phase, parentId::appendEngine); - LauncherDiscoveryResult result = new LauncherDiscoveryResult(testEngines, request.getConfigurationParameters()); + public LauncherDiscoveryResult discover(LauncherDiscoveryRequest request, UniqueId parentId) { + LauncherDiscoveryResult result = discover(request, Optional.empty(), parentId::appendEngine); return result.withRetainedEngines(TestDescriptor::containsTests); } - private Map discover(LauncherDiscoveryRequest request, Phase phase, + private LauncherDiscoveryResult discover(LauncherDiscoveryRequest request, Optional phase, Function uniqueIdCreator) { - LauncherDiscoveryListener listener = getLauncherDiscoveryListener(request); + DiscoveryIssueCollector issueCollector = new DiscoveryIssueCollector(request.getConfigurationParameters()); + LauncherDiscoveryListener listener = getLauncherDiscoveryListener(request, issueCollector); + LauncherDiscoveryRequest delegatingRequest = new DelegatingLauncherDiscoveryRequest(request) { + @Override + public LauncherDiscoveryListener getDiscoveryListener() { + return listener; + } + }; listener.launcherDiscoveryStarted(request); + LauncherDiscoveryResult discoveryResult; try { - return discoverSafely(request, phase, listener, uniqueIdCreator); + Map testEngineResults = discoverSafely(delegatingRequest, phase, + issueCollector, uniqueIdCreator); + discoveryResult = new LauncherDiscoveryResult(testEngineResults, request.getConfigurationParameters(), + request.getOutputDirectoryCreator()); } finally { listener.launcherDiscoveryFinished(request); } + if (shouldReportDiscoveryIssues(request, phase)) { + reportDiscoveryIssues(discoveryResult); + } + return discoveryResult; + } + + private static boolean shouldReportDiscoveryIssues(LauncherDiscoveryRequest request, + Optional phase) { + ConfigurationParameters configurationParameters = request.getConfigurationParameters(); + return getDiscoveryIssueFailurePhase(configurationParameters).orElse( + phase.orElse(null)) == LauncherPhase.DISCOVERY; + } + + private static void reportDiscoveryIssues(LauncherDiscoveryResult discoveryResult) { + DiscoveryIssueException exception = null; + for (TestEngine testEngine : discoveryResult.getTestEngines()) { + EngineResultInfo engineResult = discoveryResult.getEngineResult(testEngine); + DiscoveryIssueNotifier discoveryIssueNotifier = engineResult.getDiscoveryIssueNotifier(); + discoveryIssueNotifier.logCriticalIssues(testEngine); + discoveryIssueNotifier.logNonCriticalIssues(testEngine); + if (exception == null) { + exception = discoveryIssueNotifier.createExceptionForCriticalIssues(testEngine); + } + } + if (exception != null) { + throw exception; + } } - private Map discoverSafely(LauncherDiscoveryRequest request, Phase phase, - LauncherDiscoveryListener listener, Function uniqueIdCreator) { - Map testEngineDescriptors = new LinkedHashMap<>(); + private Map discoverSafely(LauncherDiscoveryRequest request, + Optional phase, DiscoveryIssueCollector issueCollector, + Function uniqueIdCreator) { + Map testEngineDescriptors = new LinkedHashMap<>(); EngineFilterer engineFilterer = new EngineFilterer(request.getEngineFilters()); for (TestEngine testEngine : this.testEngines) { boolean engineIsExcluded = engineFilterer.isExcluded(testEngine); if (engineIsExcluded) { - logger.debug(() -> String.format( - "Test discovery for engine '%s' was skipped due to an EngineFilter in %s phase.", - testEngine.getId(), phase)); + logger.debug(() -> String.format("Test discovery for engine '%s' was skipped due to an EngineFilter%s.", + testEngine.getId(), phase.map(it -> String.format(" in %s phase", it)).orElse(""))); continue; } - logger.debug(() -> String.format("Discovering tests during Launcher %s phase in engine '%s'.", phase, - testEngine.getId())); + logger.debug(() -> String.format("Discovering tests%s in engine '%s'.", + phase.map(it -> String.format(" during Launcher %s phase", it)).orElse(""), testEngine.getId())); - TestDescriptor rootDescriptor = discoverEngineRoot(testEngine, request, listener, uniqueIdCreator); - testEngineDescriptors.put(testEngine, rootDescriptor); + EngineResultInfo engineResult = discoverEngineRoot(testEngine, request, issueCollector, uniqueIdCreator); + testEngineDescriptors.put(testEngine, engineResult); } engineFilterer.performSanityChecks(); @@ -144,32 +186,42 @@ return testEngineDescriptors; } - private TestDescriptor discoverEngineRoot(TestEngine testEngine, LauncherDiscoveryRequest request, - LauncherDiscoveryListener listener, Function uniqueIdCreator) { + private EngineResultInfo discoverEngineRoot(TestEngine testEngine, LauncherDiscoveryRequest request, + DiscoveryIssueCollector issueCollector, Function uniqueIdCreator) { UniqueId uniqueEngineId = uniqueIdCreator.apply(testEngine.getId()); + LauncherDiscoveryListener listener = request.getDiscoveryListener(); try { listener.engineDiscoveryStarted(uniqueEngineId); TestDescriptor engineRoot = testEngine.discover(request, uniqueEngineId); discoveryResultValidator.validate(testEngine, engineRoot); listener.engineDiscoveryFinished(uniqueEngineId, EngineDiscoveryResult.successful()); - return engineRoot; + return EngineResultInfo.completed(engineRoot, issueCollector.toNotifier()); } catch (Throwable throwable) { UnrecoverableExceptions.rethrowIfUnrecoverable(throwable); - String message = String.format("TestEngine with ID '%s' failed to discover tests", testEngine.getId()); - JUnitException cause = new JUnitException(message, throwable); + JUnitException cause = null; + if (throwable instanceof LinkageError) { + cause = ClasspathAlignmentChecker.check((LinkageError) throwable).orElse(null); + } + if (cause == null) { + String message = String.format("TestEngine with ID '%s' failed to discover tests", testEngine.getId()); + cause = new JUnitException(message, throwable); + } listener.engineDiscoveryFinished(uniqueEngineId, EngineDiscoveryResult.failed(cause)); - return new EngineDiscoveryErrorDescriptor(uniqueEngineId, testEngine, cause); + return EngineResultInfo.errored(new EngineDescriptor(uniqueEngineId, testEngine.getId()), + issueCollector.toNotifier(), cause); } } - LauncherDiscoveryListener getLauncherDiscoveryListener(LauncherDiscoveryRequest discoveryRequest) { + LauncherDiscoveryListener getLauncherDiscoveryListener(LauncherDiscoveryRequest discoveryRequest, + DiscoveryIssueCollector issueCollector) { return ListenerRegistry.copyOf(launcherDiscoveryListenerRegistry) // .add(discoveryRequest.getDiscoveryListener()) // + .add(issueCollector) // .getCompositeListener(); } - private void applyPostDiscoveryFilters(Map testEngineDescriptors, + private void applyPostDiscoveryFilters(Map testEngineDescriptors, List filters) { Filter postDiscoveryFilter = composeFilters(filters); Map> excludedTestDescriptorsByReason = new LinkedHashMap<>(); @@ -209,26 +261,17 @@ *

    If a {@link TestEngine} ends up with no {@code TestDescriptors} after * pruning, it will not be removed. */ - private void prune(Map testEngineDescriptors) { - acceptInAllTestEngines(testEngineDescriptors, TestDescriptor::prune); + private void prune(Map testEngineResults) { + acceptInAllTestEngines(testEngineResults, TestDescriptor::prune); } private boolean isExcluded(TestDescriptor descriptor, FilterResult filterResult) { return descriptor.getChildren().isEmpty() && filterResult.excluded(); } - private void acceptInAllTestEngines(Map testEngineDescriptors, + private void acceptInAllTestEngines(Map testEngineResults, TestDescriptor.Visitor visitor) { - testEngineDescriptors.values().forEach(descriptor -> descriptor.accept(visitor)); - } - - public enum Phase { - DISCOVERY, EXECUTION; - - @Override - public String toString() { - return name().toLowerCase(Locale.ENGLISH); - } + testEngineResults.values().forEach(result -> result.getRootDescriptor().accept(visitor)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidator.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -33,7 +33,7 @@ class EngineDiscoveryResultValidator { /** - * Perform common validation checks. + * Perform common validation checks. * * @throws org.junit.platform.commons.PreconditionViolationException if any check fails */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineExecutionOrchestrator.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineExecutionOrchestrator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineExecutionOrchestrator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineExecutionOrchestrator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.apiguardian.api.API.Status.INTERNAL; import static org.junit.platform.launcher.LauncherConstants.DRY_RUN_PROPERTY_NAME; import static org.junit.platform.launcher.LauncherConstants.STACKTRACE_PRUNING_ENABLED_PROPERTY_NAME; +import static org.junit.platform.launcher.core.LauncherPhase.getDiscoveryIssueFailurePhase; import static org.junit.platform.launcher.core.ListenerRegistry.forEngineExecutionListeners; import java.util.Optional; @@ -25,12 +26,16 @@ import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.ExecutionRequest; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestPlan; +import org.junit.platform.launcher.core.LauncherDiscoveryResult.EngineResultInfo; /** * Orchestrates test execution using the configured test engines. @@ -50,12 +55,14 @@ this.listenerRegistry = listenerRegistry; } - void execute(InternalTestPlan internalTestPlan, TestExecutionListener... listeners) { + void execute(InternalTestPlan internalTestPlan, NamespacedHierarchicalStore requestLevelStore, + TestExecutionListener... listeners) { ConfigurationParameters configurationParameters = internalTestPlan.getConfigurationParameters(); ListenerRegistry testExecutionListenerListeners = buildListenerRegistryForExecution( listeners); withInterceptedStreams(configurationParameters, testExecutionListenerListeners, - testExecutionListener -> execute(internalTestPlan, EngineExecutionListener.NOOP, testExecutionListener)); + testExecutionListener -> execute(internalTestPlan, EngineExecutionListener.NOOP, testExecutionListener, + requestLevelStore)); } /** @@ -67,17 +74,18 @@ */ @API(status = INTERNAL, since = "1.9", consumers = { "org.junit.platform.suite.engine" }) public void execute(LauncherDiscoveryResult discoveryResult, EngineExecutionListener engineExecutionListener, - TestExecutionListener testExecutionListener) { + TestExecutionListener testExecutionListener, NamespacedHierarchicalStore requestLevelStore) { Preconditions.notNull(discoveryResult, "discoveryResult must not be null"); Preconditions.notNull(engineExecutionListener, "engineExecutionListener must not be null"); Preconditions.notNull(testExecutionListener, "testExecutionListener must not be null"); + Preconditions.notNull(requestLevelStore, "requestLevelStore must not be null"); InternalTestPlan internalTestPlan = InternalTestPlan.from(discoveryResult); - execute(internalTestPlan, engineExecutionListener, testExecutionListener); + execute(internalTestPlan, engineExecutionListener, testExecutionListener, requestLevelStore); } private void execute(InternalTestPlan internalTestPlan, EngineExecutionListener parentEngineExecutionListener, - TestExecutionListener testExecutionListener) { + TestExecutionListener testExecutionListener, NamespacedHierarchicalStore requestLevelStore) { internalTestPlan.markStarted(); // Do not directly pass the internal test plan to test execution listeners. @@ -91,7 +99,8 @@ } else { execute(discoveryResult, - buildEngineExecutionListener(parentEngineExecutionListener, testExecutionListener, testPlan)); + buildEngineExecutionListener(parentEngineExecutionListener, testExecutionListener, testPlan), + requestLevelStore); } testExecutionListener.testPlanExecutionFinished(testPlan); } @@ -151,7 +160,8 @@ * EngineExecutionListener listener} of execution events. */ @API(status = INTERNAL, since = "1.7", consumers = { "org.junit.platform.testkit" }) - public void execute(LauncherDiscoveryResult discoveryResult, EngineExecutionListener engineExecutionListener) { + public void execute(LauncherDiscoveryResult discoveryResult, EngineExecutionListener engineExecutionListener, + NamespacedHierarchicalStore requestLevelStore) { Preconditions.notNull(discoveryResult, "discoveryResult must not be null"); Preconditions.notNull(engineExecutionListener, "engineExecutionListener must not be null"); @@ -159,15 +169,7 @@ EngineExecutionListener listener = selectExecutionListener(engineExecutionListener, configurationParameters); for (TestEngine testEngine : discoveryResult.getTestEngines()) { - TestDescriptor engineDescriptor = discoveryResult.getEngineTestDescriptor(testEngine); - if (engineDescriptor instanceof EngineDiscoveryErrorDescriptor) { - listener.executionStarted(engineDescriptor); - listener.executionFinished(engineDescriptor, - TestExecutionResult.failed(((EngineDiscoveryErrorDescriptor) engineDescriptor).getCause())); - } - else { - execute(engineDescriptor, listener, configurationParameters, testEngine); - } + failOrExecuteEngine(discoveryResult, listener, testEngine, requestLevelStore); } } @@ -181,6 +183,35 @@ return engineExecutionListener; } + private void failOrExecuteEngine(LauncherDiscoveryResult discoveryResult, EngineExecutionListener listener, + TestEngine testEngine, NamespacedHierarchicalStore requestLevelStore) { + EngineResultInfo engineDiscoveryResult = discoveryResult.getEngineResult(testEngine); + DiscoveryIssueNotifier discoveryIssueNotifier = shouldReportDiscoveryIssues(discoveryResult) // + ? engineDiscoveryResult.getDiscoveryIssueNotifier() // + : DiscoveryIssueNotifier.NO_ISSUES; + TestDescriptor engineDescriptor = engineDiscoveryResult.getRootDescriptor(); + Throwable failure = engineDiscoveryResult.getCause() // + .orElseGet(() -> discoveryIssueNotifier.createExceptionForCriticalIssues(testEngine)); + if (failure != null) { + listener.executionStarted(engineDescriptor); + if (engineDiscoveryResult.getCause().isPresent()) { + discoveryIssueNotifier.logCriticalIssues(testEngine); + } + discoveryIssueNotifier.logNonCriticalIssues(testEngine); + listener.executionFinished(engineDescriptor, TestExecutionResult.failed(failure)); + } + else { + executeEngine(engineDescriptor, listener, discoveryResult.getConfigurationParameters(), testEngine, + discoveryResult.getOutputDirectoryCreator(), discoveryIssueNotifier, requestLevelStore); + } + } + + private static boolean shouldReportDiscoveryIssues(LauncherDiscoveryResult discoveryResult) { + ConfigurationParameters configurationParameters = discoveryResult.getConfigurationParameters(); + return getDiscoveryIssueFailurePhase(configurationParameters).orElse( + LauncherPhase.EXECUTION) == LauncherPhase.EXECUTION; + } + private ListenerRegistry buildListenerRegistryForExecution( TestExecutionListener... listeners) { if (listeners.length == 0) { @@ -189,19 +220,31 @@ return ListenerRegistry.copyOf(this.listenerRegistry).addAll(listeners); } - private void execute(TestDescriptor engineDescriptor, EngineExecutionListener listener, - ConfigurationParameters configurationParameters, TestEngine testEngine) { - + private void executeEngine(TestDescriptor engineDescriptor, EngineExecutionListener listener, + ConfigurationParameters configurationParameters, TestEngine testEngine, + OutputDirectoryCreator outputDirectoryCreator, DiscoveryIssueNotifier discoveryIssueNotifier, + NamespacedHierarchicalStore requestLevelStore) { OutcomeDelayingEngineExecutionListener delayingListener = new OutcomeDelayingEngineExecutionListener(listener, engineDescriptor); try { - testEngine.execute(new ExecutionRequest(engineDescriptor, delayingListener, configurationParameters)); + testEngine.execute(ExecutionRequest.create(engineDescriptor, delayingListener, configurationParameters, + outputDirectoryCreator, requestLevelStore)); + discoveryIssueNotifier.logNonCriticalIssues(testEngine); delayingListener.reportEngineOutcome(); } catch (Throwable throwable) { UnrecoverableExceptions.rethrowIfUnrecoverable(throwable); - delayingListener.reportEngineFailure(new JUnitException( - String.format("TestEngine with ID '%s' failed to execute tests", testEngine.getId()), throwable)); + JUnitException cause = null; + if (throwable instanceof LinkageError) { + cause = ClasspathAlignmentChecker.check((LinkageError) throwable).orElse(null); + } + if (cause == null) { + String message = String.format("TestEngine with ID '%s' failed to execute tests", testEngine.getId()); + cause = new JUnitException(message, throwable); + } + delayingListener.reportEngineStartIfNecessary(); + discoveryIssueNotifier.logNonCriticalIssues(testEngine); + delayingListener.reportEngineFailure(cause); } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineFilterer.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineFilterer.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineFilterer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineFilterer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,11 +12,14 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toCollection; +import static java.util.stream.Collectors.toSet; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -69,12 +72,14 @@ } private SortedSet getUnmatchedEngineIdsOfIncludeFilters() { + Set checkedTestEngineIds = checkedTestEngines.keySet().stream() // + .map(TestEngine::getId) // + .collect(toSet()); return engineFilters.stream() // .filter(EngineFilter::isIncludeFilter) // - .filter(engineFilter -> checkedTestEngines.keySet().stream() // - .map(engineFilter::apply) // - .noneMatch(FilterResult::included)) // - .flatMap(engineFilter -> engineFilter.getEngineIds().stream()) // + .map(EngineFilter::getEngineIds) // + .flatMap(Collection::stream) // + .filter(id -> !checkedTestEngineIds.contains(id)) // .collect(toCollection(TreeSet::new)); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -51,7 +51,7 @@ return LoggerFactory.getLogger(EngineIdValidator.class); } - // https://github.com/junit-team/junit5/issues/1557 + // https://github.com/junit-team/junit-framework/issues/1557 private static boolean validateReservedIds(TestEngine testEngine) { String engineId = Preconditions.notBlank(testEngine.getId(), () -> String.format("ID for TestEngine [%s] must not be null or blank", testEngine.getClass().getName())); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ExecutionListenerAdapter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ExecutionListenerAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ExecutionListenerAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ExecutionListenerAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; @@ -61,6 +62,11 @@ this.testExecutionListener.reportingEntryPublished(getTestIdentifier(testDescriptor), entry); } + @Override + public void fileEntryPublished(TestDescriptor testDescriptor, FileEntry file) { + this.testExecutionListener.fileEntryPublished(getTestIdentifier(testDescriptor), file); + } + private TestIdentifier getTestIdentifier(TestDescriptor testDescriptor) { return this.testPlan.getTestIdentifier(testDescriptor.getUniqueId()); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreator.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.function.Supplier; +import java.util.regex.Pattern; + +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.OutputDirectoryCreator; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId.Segment; + +/** + * Hierarchical {@link OutputDirectoryCreator} that creates directories based on + * the unique ID segments of a {@link TestDescriptor}. + * + * @since 1.12 + */ +class HierarchicalOutputDirectoryCreator implements OutputDirectoryCreator { + + private static final Pattern FORBIDDEN_CHARS = Pattern.compile("[^a-z0-9.,_\\-() ]", Pattern.CASE_INSENSITIVE); + private static final String REPLACEMENT = "_"; + + private final Supplier rootDirSupplier; + private volatile Path rootDir; + + HierarchicalOutputDirectoryCreator(Supplier rootDirSupplier) { + this.rootDirSupplier = rootDirSupplier; + } + + @Override + public Path createOutputDirectory(TestDescriptor testDescriptor) throws IOException { + Preconditions.notNull(testDescriptor, "testDescriptor must not be null"); + + List segments = testDescriptor.getUniqueId().getSegments(); + Path relativePath = segments.stream() // + .skip(1) // + .map(HierarchicalOutputDirectoryCreator::toSanitizedPath) // + .reduce(toSanitizedPath(segments.get(0)), Path::resolve); + return Files.createDirectories(getRootDirectory().resolve(relativePath)); + } + + @Override + public synchronized Path getRootDirectory() { + if (rootDir == null) { + rootDir = rootDirSupplier.get(); + } + return rootDir; + } + + private static Path toSanitizedPath(Segment segment) { + return Paths.get(sanitizeName(segment.getValue())); + } + + private static String sanitizeName(String value) { + return FORBIDDEN_CHARS.matcher(value).replaceAll(REPLACEMENT); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InterceptingLauncher.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InterceptingLauncher.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InterceptingLauncher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InterceptingLauncher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InternalTestPlan.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InternalTestPlan.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InternalTestPlan.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/InternalTestPlan.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -30,13 +30,14 @@ private final TestPlan delegate; static InternalTestPlan from(LauncherDiscoveryResult discoveryResult) { - TestPlan delegate = TestPlan.from(discoveryResult.getEngineTestDescriptors(), - discoveryResult.getConfigurationParameters()); + TestPlan delegate = TestPlan.from(discoveryResult.containsCriticalIssuesOrContainsTests(), + discoveryResult.getEngineTestDescriptors(), discoveryResult.getConfigurationParameters(), + discoveryResult.getOutputDirectoryCreator()); return new InternalTestPlan(discoveryResult, delegate); } private InternalTestPlan(LauncherDiscoveryResult discoveryResult, TestPlan delegate) { - super(delegate.containsTests(), delegate.getConfigurationParameters()); + super(delegate.containsTests(), delegate.getConfigurationParameters(), delegate.getOutputDirectoryCreator()); this.discoveryResult = discoveryResult; this.delegate = delegate; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/IterationOrder.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/IterationOrder.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/IterationOrder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/IterationOrder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfig.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfig.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfig.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfig.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,9 @@ package org.junit.platform.launcher.core; import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; +import static org.junit.platform.launcher.LauncherConstants.OUTPUT_DIR_PROPERTY_NAME; import java.util.ArrayList; import java.util.Arrays; @@ -27,11 +29,14 @@ import org.junit.platform.engine.DiscoveryFilter; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.Filter; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.launcher.EngineFilter; +import org.junit.platform.launcher.LauncherConstants; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.PostDiscoveryFilter; import org.junit.platform.launcher.core.LauncherConfigurationParameters.Builder; +import org.junit.platform.launcher.listeners.OutputDir; import org.junit.platform.launcher.listeners.discovery.LauncherDiscoveryListeners; /** @@ -73,8 +78,7 @@ * ) * .configurationParameter("key1", "value1") * .configurationParameters(configParameterMap) - * .build(); - * + * .build(); * * @since 1.0 * @see org.junit.platform.engine.discovery.DiscoverySelectors @@ -107,6 +111,7 @@ private final List discoveryListeners = new ArrayList<>(); private boolean implicitConfigurationParametersEnabled = true; private ConfigurationParameters parentConfigurationParameters; + private OutputDirectoryCreator outputDirectoryCreator; /** * Create a new {@code LauncherDiscoveryRequestBuilder}. @@ -283,6 +288,51 @@ return this; } + /** + * Set the + * {@link org.junit.platform.engine.reporting.OutputDirectoryProvider} to use for the request. + * + *

    If not specified, a default provider will be used that can be + * configured via the {@value LauncherConstants#OUTPUT_DIR_PROPERTY_NAME} + * configuration parameter. + * + * @param outputDirectoryProvider the output directory provider to use; + * never {@code null} + * @return this builder for method chaining + * @since 1.12 + * @see org.junit.platform.engine.reporting.OutputDirectoryProvider + * @see LauncherConstants#OUTPUT_DIR_PROPERTY_NAME + * @deprecated Please use + * {@link #outputDirectoryCreator(OutputDirectoryCreator)} instead + */ + @API(status = DEPRECATED, since = "1.14") + @Deprecated + public LauncherDiscoveryRequestBuilder outputDirectoryProvider( + org.junit.platform.engine.reporting.OutputDirectoryProvider outputDirectoryProvider) { + return outputDirectoryCreator(outputDirectoryProvider); + } + + /** + * Set the {@link OutputDirectoryCreator} to use for the request. + * + *

    If not specified, a default implementation will be used that can be + * configured via the {@value LauncherConstants#OUTPUT_DIR_PROPERTY_NAME} + * configuration parameter. + * + * @param outputDirectoryCreator the output directory creator to use; + * never {@code null} + * @return this builder for method chaining + * @since 1.14 + * @see OutputDirectoryCreator + * @see LauncherConstants#OUTPUT_DIR_PROPERTY_NAME + */ + @API(status = MAINTAINED, since = "1.14") + public LauncherDiscoveryRequestBuilder outputDirectoryCreator(OutputDirectoryCreator outputDirectoryCreator) { + this.outputDirectoryCreator = Preconditions.notNull(outputDirectoryCreator, + "outputDirectoryCreator must not be null"); + return this; + } + private void storeFilter(Filter filter) { if (filter instanceof EngineFilter) { this.engineFilters.add((EngineFilter) filter); @@ -307,8 +357,17 @@ public LauncherDiscoveryRequest build() { LauncherConfigurationParameters launcherConfigurationParameters = buildLauncherConfigurationParameters(); LauncherDiscoveryListener discoveryListener = getLauncherDiscoveryListener(launcherConfigurationParameters); + OutputDirectoryCreator outputDirectoryCreator = getOutputDirectoryCreator(launcherConfigurationParameters); return new DefaultDiscoveryRequest(this.selectors, this.engineFilters, this.discoveryFilters, - this.postDiscoveryFilters, launcherConfigurationParameters, discoveryListener); + this.postDiscoveryFilters, launcherConfigurationParameters, discoveryListener, outputDirectoryCreator); + } + + private OutputDirectoryCreator getOutputDirectoryCreator(LauncherConfigurationParameters configurationParameters) { + if (this.outputDirectoryCreator != null) { + return this.outputDirectoryCreator; + } + return new HierarchicalOutputDirectoryCreator( + () -> OutputDir.create(configurationParameters.get(OUTPUT_DIR_PROPERTY_NAME)).toPath()); } private LauncherConfigurationParameters buildLauncherConfigurationParameters() { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,16 +11,20 @@ package org.junit.platform.launcher.core; import static java.util.Collections.unmodifiableMap; -import static java.util.stream.Collectors.toMap; import static org.apiguardian.api.API.Status.INTERNAL; import java.util.Collection; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Predicate; +import java.util.stream.Collectors; import org.apiguardian.api.API; import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; @@ -33,46 +37,108 @@ @API(status = INTERNAL, since = "1.7", consumers = { "org.junit.platform.testkit", "org.junit.platform.suite.engine" }) public class LauncherDiscoveryResult { - private final Map testEngineDescriptors; + private final Map testEngineResults; private final ConfigurationParameters configurationParameters; + private final OutputDirectoryCreator outputDirectoryCreator; - LauncherDiscoveryResult(Map testEngineDescriptors, - ConfigurationParameters configurationParameters) { - this.testEngineDescriptors = unmodifiableMap(new LinkedHashMap<>(testEngineDescriptors)); + LauncherDiscoveryResult(Map testEngineResults, + ConfigurationParameters configurationParameters, OutputDirectoryCreator outputDirectoryCreator) { + this.testEngineResults = unmodifiableMap(new LinkedHashMap<>(testEngineResults)); this.configurationParameters = configurationParameters; + this.outputDirectoryCreator = outputDirectoryCreator; } public TestDescriptor getEngineTestDescriptor(TestEngine testEngine) { - return this.testEngineDescriptors.get(testEngine); + return getEngineResult(testEngine).getRootDescriptor(); + } + + @API(status = INTERNAL, since = "1.13") + public List getDiscoveryIssues(TestEngine testEngine) { + return getEngineResult(testEngine).getDiscoveryIssueNotifier().getAllIssues(); + } + + EngineResultInfo getEngineResult(TestEngine testEngine) { + return this.testEngineResults.get(testEngine); } ConfigurationParameters getConfigurationParameters() { - return configurationParameters; + return this.configurationParameters; + } + + OutputDirectoryCreator getOutputDirectoryCreator() { + return this.outputDirectoryCreator; } public Collection getTestEngines() { - return this.testEngineDescriptors.keySet(); + return this.testEngineResults.keySet(); + } + + boolean containsCriticalIssuesOrContainsTests() { + return this.testEngineResults.values().stream() // + .anyMatch(EngineResultInfo::containsCriticalIssuesOrContainsTests); } Collection getEngineTestDescriptors() { - return this.testEngineDescriptors.values(); + return this.testEngineResults.values().stream() // + .map(EngineResultInfo::getRootDescriptor) // + .collect(Collectors.toList()); } public LauncherDiscoveryResult withRetainedEngines(Predicate predicate) { - Map prunedTestEngineDescriptors = retainEngines(predicate); - if (prunedTestEngineDescriptors.size() < testEngineDescriptors.size()) { - return new LauncherDiscoveryResult(prunedTestEngineDescriptors, configurationParameters); + Map prunedTestEngineResults = retainEngines(predicate); + if (prunedTestEngineResults.size() < this.testEngineResults.size()) { + return new LauncherDiscoveryResult(prunedTestEngineResults, this.configurationParameters, + this.outputDirectoryCreator); } return this; } - private Map retainEngines(Predicate predicate) { - // @formatter:off - return testEngineDescriptors.entrySet() - .stream() - .filter(entry -> predicate.test(entry.getValue())) - .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - // @formatter:on + private Map retainEngines(Predicate predicate) { + Map retainedEngines = new LinkedHashMap<>(this.testEngineResults); + retainedEngines.entrySet().removeIf(entry -> !predicate.test(entry.getValue().getRootDescriptor())); + return retainedEngines; + } + + static class EngineResultInfo { + + static EngineResultInfo completed(TestDescriptor rootDescriptor, + DiscoveryIssueNotifier discoveryIssueNotifier) { + return new EngineResultInfo(rootDescriptor, discoveryIssueNotifier, null); + } + + static EngineResultInfo errored(TestDescriptor rootDescriptor, DiscoveryIssueNotifier discoveryIssueNotifier, + Throwable cause) { + return new EngineResultInfo(rootDescriptor, discoveryIssueNotifier, cause); + } + + private final TestDescriptor rootDescriptor; + private final Throwable cause; + private final DiscoveryIssueNotifier discoveryIssueNotifier; + + EngineResultInfo(TestDescriptor rootDescriptor, DiscoveryIssueNotifier discoveryIssueNotifier, + Throwable cause) { + this.rootDescriptor = rootDescriptor; + this.discoveryIssueNotifier = discoveryIssueNotifier; + this.cause = cause; + } + + TestDescriptor getRootDescriptor() { + return this.rootDescriptor; + } + + DiscoveryIssueNotifier getDiscoveryIssueNotifier() { + return discoveryIssueNotifier; + } + + Optional getCause() { + return Optional.ofNullable(this.cause); + } + + boolean containsCriticalIssuesOrContainsTests() { + return cause != null // + || discoveryIssueNotifier.hasCriticalIssues() // + || TestDescriptor.containsTests(rootDescriptor); + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherFactory.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.platform.launcher.core; -import static java.util.Collections.emptyList; import static org.apiguardian.api.API.Status.STABLE; import static org.junit.platform.launcher.LauncherConstants.DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME; import static org.junit.platform.launcher.LauncherConstants.ENABLE_LAUNCHER_INTERCEPTORS; @@ -19,8 +18,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; +import java.util.function.Predicate; import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; @@ -28,6 +26,8 @@ import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestEngine; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherInterceptor; @@ -98,7 +98,8 @@ Preconditions.notNull(config, "LauncherConfig must not be null"); LauncherConfigurationParameters configurationParameters = LauncherConfigurationParameters.builder().build(); return new DefaultLauncherSession(collectLauncherInterceptors(configurationParameters), - () -> createLauncherSessionListener(config), () -> createDefaultLauncher(config, configurationParameters)); + () -> createLauncherSessionListener(config), + sessionLevelStore -> createDefaultLauncher(config, configurationParameters, sessionLevelStore)); } /** @@ -127,17 +128,17 @@ public static Launcher create(LauncherConfig config) throws PreconditionViolationException { Preconditions.notNull(config, "LauncherConfig must not be null"); LauncherConfigurationParameters configurationParameters = LauncherConfigurationParameters.builder().build(); - return new SessionPerRequestLauncher(() -> createDefaultLauncher(config, configurationParameters), + return new SessionPerRequestLauncher( + sessionLevelStore -> createDefaultLauncher(config, configurationParameters, sessionLevelStore), () -> createLauncherSessionListener(config), () -> collectLauncherInterceptors(configurationParameters)); } private static DefaultLauncher createDefaultLauncher(LauncherConfig config, - LauncherConfigurationParameters configurationParameters) { + LauncherConfigurationParameters configurationParameters, + NamespacedHierarchicalStore sessionLevelStore) { Set engines = collectTestEngines(config); List filters = collectPostDiscoveryFilters(config); - - DefaultLauncher launcher = new DefaultLauncher(engines, filters); - + DefaultLauncher launcher = new DefaultLauncher(engines, filters, sessionLevelStore); registerLauncherDiscoveryListeners(config, launcher); registerTestExecutionListeners(config, launcher, configurationParameters); @@ -146,12 +147,12 @@ private static List collectLauncherInterceptors( LauncherConfigurationParameters configurationParameters) { + List interceptors = new ArrayList<>(); if (configurationParameters.getBoolean(ENABLE_LAUNCHER_INTERCEPTORS).orElse(false)) { - List interceptors = new ArrayList<>(); ServiceLoaderRegistry.load(LauncherInterceptor.class).forEach(interceptors::add); - return interceptors; } - return emptyList(); + interceptors.add(ClasspathAlignmentCheckingLauncherInterceptor.INSTANCE); + return interceptors; } private static Set collectTestEngines(LauncherConfig config) { @@ -198,15 +199,12 @@ config.getAdditionalTestExecutionListeners().forEach(launcher::registerTestExecutionListeners); } - private static Stream loadAndFilterTestExecutionListeners( + private static Iterable loadAndFilterTestExecutionListeners( ConfigurationParameters configurationParameters) { - Iterable listeners = ServiceLoaderRegistry.load(TestExecutionListener.class); - String deactivatedListenersPattern = configurationParameters.get( - DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME).orElse(null); - // @formatter:off - return StreamSupport.stream(listeners.spliterator(), false) - .filter(ClassNamePatternFilterUtils.excludeMatchingClasses(deactivatedListenersPattern)); - // @formatter:on + Predicate classNameFilter = configurationParameters.get(DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME) // + .map(ClassNamePatternFilterUtils::excludeMatchingClassNames) // + .orElse(__ -> true); + return ServiceLoaderRegistry.load(TestExecutionListener.class, classNameFilter); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherListenerRegistry.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherListenerRegistry.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherListenerRegistry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherListenerRegistry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherPhase.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherPhase.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherPhase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherPhase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.junit.platform.launcher.LauncherConstants.DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME; + +import java.util.Locale; +import java.util.Optional; + +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.engine.ConfigurationParameters; + +/** + * The phase the {@link org.junit.platform.launcher.Launcher} is in. + * + * @since 1.13 + */ +enum LauncherPhase { + + DISCOVERY, EXECUTION; + + private static final Logger logger = LoggerFactory.getLogger(LauncherPhase.class); + + static Optional getDiscoveryIssueFailurePhase(ConfigurationParameters configurationParameters) { + return configurationParameters.get(DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME, value -> { + try { + return LauncherPhase.valueOf(value.toUpperCase(Locale.ROOT)); + } + catch (Exception e) { + logger.warn( + () -> String.format("Ignoring invalid LauncherPhase '%s' set via the '%s' configuration parameter.", + value, DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME)); + return null; + } + }); + } + + @Override + public String toString() { + return name().toLowerCase(Locale.ENGLISH); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ListenerRegistry.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ListenerRegistry.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ListenerRegistry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ListenerRegistry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/OutcomeDelayingEngineExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/OutcomeDelayingEngineExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/OutcomeDelayingEngineExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/OutcomeDelayingEngineExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -73,10 +73,13 @@ } } - void reportEngineFailure(Throwable throwable) { + void reportEngineStartIfNecessary() { if (!engineStarted) { super.executionStarted(engineDescriptor); } + } + + void reportEngineFailure(Throwable throwable) { if (executionResult != null && executionResult.getThrowable().isPresent()) { throwable.addSuppressed(executionResult.getThrowable().get()); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderRegistry.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderRegistry.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderRegistry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderRegistry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,24 +11,55 @@ package org.junit.platform.launcher.core; import static java.util.stream.Collectors.toList; -import static java.util.stream.StreamSupport.stream; +import java.util.ArrayList; +import java.util.List; import java.util.ServiceLoader; +import java.util.function.Function; +import java.util.function.Predicate; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.ClassLoaderUtils; +import org.junit.platform.commons.util.ServiceLoaderUtils; /** * @since 1.8 */ class ServiceLoaderRegistry { - static Iterable load(Class serviceProviderClass) { - Iterable listeners = ServiceLoader.load(serviceProviderClass, ClassLoaderUtils.getDefaultClassLoader()); - getLogger().config(() -> "Loaded " + serviceProviderClass.getSimpleName() + " instances: " - + stream(listeners.spliterator(), false).map(Object::toString).collect(toList())); - return listeners; + static Iterable load(Class type) { + return load(type, __ -> true, instances -> logLoadedInstances(type, instances, null)); + } + + static Iterable load(@SuppressWarnings("SameParameterValue") Class type, + Predicate classNameFilter) { + List exclusions = new ArrayList<>(); + Predicate collectingClassNameFilter = className -> { + boolean included = classNameFilter.test(className); + if (!included) { + exclusions.add(className); + } + return included; + }; + return load(type, collectingClassNameFilter, instances -> logLoadedInstances(type, instances, exclusions)); + } + + private static String logLoadedInstances(Class type, List instances, List exclusions) { + String typeName = type.getSimpleName(); + if (exclusions == null) { + return String.format("Loaded %s instances: %s", typeName, instances); + } + return String.format("Loaded %s instances: %s (excluded classes: %s)", typeName, instances, exclusions); + } + + private static List load(Class type, Predicate classNameFilter, + Function, String> logMessageSupplier) { + ServiceLoader serviceLoader = ServiceLoader.load(type, ClassLoaderUtils.getDefaultClassLoader()); + Predicate> providerPredicate = clazz -> classNameFilter.test(clazz.getName()); + List instances = ServiceLoaderUtils.filter(serviceLoader, providerPredicate).collect(toList()); + getLogger().config(() -> logMessageSupplier.apply(instances)); + return instances; } private static Logger getLogger() { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderTestEngineRegistry.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderTestEngineRegistry.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderTestEngineRegistry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/ServiceLoaderTestEngineRegistry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/SessionPerRequestLauncher.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/SessionPerRequestLauncher.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/SessionPerRequestLauncher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/SessionPerRequestLauncher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,8 +11,11 @@ package org.junit.platform.launcher.core; import java.util.List; +import java.util.function.Function; import java.util.function.Supplier; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; @@ -28,14 +31,14 @@ class SessionPerRequestLauncher implements Launcher { private final LauncherListenerRegistry listenerRegistry = new LauncherListenerRegistry(); - private final Supplier launcherSupplier; + private final Function, Launcher> launcherFactory; private final Supplier sessionListenerSupplier; private final Supplier> interceptorFactory; - SessionPerRequestLauncher(Supplier launcherSupplier, + SessionPerRequestLauncher(Function, Launcher> launcherFactory, Supplier sessionListenerSupplier, Supplier> interceptorFactory) { - this.launcherSupplier = launcherSupplier; + this.launcherFactory = launcherFactory; this.sessionListenerSupplier = sessionListenerSupplier; this.interceptorFactory = interceptorFactory; } @@ -73,7 +76,7 @@ private LauncherSession createSession() { LauncherSession session = new DefaultLauncherSession(interceptorFactory.get(), sessionListenerSupplier, - launcherSupplier); + this.launcherFactory); Launcher launcher = session.getLauncher(); listenerRegistry.launcherDiscoveryListeners.getListeners().forEach( launcher::registerLauncherDiscoveryListeners); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,6 +15,7 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.Optional; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.function.Consumer; /** @@ -22,6 +23,8 @@ */ class StreamInterceptor extends PrintStream { + private final Deque mostRecentOutputs = new ConcurrentLinkedDeque<>(); + private final PrintStream originalStream; private final Consumer unregisterAction; private final int maxNumberOfBytesPerThread; @@ -56,11 +59,18 @@ } void capture() { - output.get().mark(); + RewindableByteArrayOutputStream out = output.get(); + out.mark(); + pushToTop(out); } String consume() { - return output.get().rewind(); + RewindableByteArrayOutputStream out = output.get(); + String result = out.rewind(); + if (!out.isMarked()) { + mostRecentOutputs.remove(out); + } + return result; } void unregister() { @@ -69,8 +79,9 @@ @Override public void write(int b) { - RewindableByteArrayOutputStream out = output.get(); - if (out.isMarked() && out.size() < maxNumberOfBytesPerThread) { + RewindableByteArrayOutputStream out = getOutput(); + if (out != null && out.size() < maxNumberOfBytesPerThread) { + pushToTop(out); out.write(b); } super.write(b); @@ -83,16 +94,29 @@ @Override public void write(byte[] buf, int off, int len) { - RewindableByteArrayOutputStream out = output.get(); - if (out.isMarked()) { + RewindableByteArrayOutputStream out = getOutput(); + if (out != null) { int actualLength = Math.max(0, Math.min(len, maxNumberOfBytesPerThread - out.size())); if (actualLength > 0) { + pushToTop(out); out.write(buf, off, actualLength); } } super.write(buf, off, len); } + private void pushToTop(RewindableByteArrayOutputStream out) { + if (!out.equals(mostRecentOutputs.peek())) { + mostRecentOutputs.remove(out); + mostRecentOutputs.push(out); + } + } + + private RewindableByteArrayOutputStream getOutput() { + RewindableByteArrayOutputStream out = output.get(); + return out.isMarked() ? out : mostRecentOutputs.peek(); + } + static class RewindableByteArrayOutputStream extends ByteArrayOutputStream { private final Deque markedPositions = new ArrayDeque<>(); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/TestEngineFormatter.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/TestEngineFormatter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/TestEngineFormatter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/TestEngineFormatter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LegacyReportingUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LegacyReportingUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LegacyReportingUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LegacyReportingUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -46,9 +46,9 @@ * {@linkplain TestIdentifier#getLegacyReportingName legacy reporting name}. * * @param testPlan the test plan that contains the {@code TestIdentifier}; - * never {@code null} + * never {@code null} * @param testIdentifier the identifier to determine the class name for; - * never {@code null} + * never {@code null} * @see TestIdentifier#getLegacyReportingName */ public static String getClassName(TestPlan testPlan, TestIdentifier testIdentifier) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LoggingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LoggingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LoggingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/LoggingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/MutableTestExecutionSummary.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/MutableTestExecutionSummary.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/MutableTestExecutionSummary.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/MutableTestExecutionSummary.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,15 +11,20 @@ package org.junit.platform.launcher.listeners; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.launcher.LauncherConstants.OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; import java.security.SecureRandom; import java.util.Optional; +import java.util.function.BiPredicate; import java.util.function.Supplier; +import java.util.regex.Pattern; +import java.util.stream.Stream; import org.apiguardian.api.API; import org.junit.platform.commons.util.StringUtils; @@ -27,9 +32,16 @@ @API(status = INTERNAL, since = "1.9") public class OutputDir { + private static final Pattern OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER_PATTERN = Pattern.compile( + Pattern.quote(OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER)); + public static OutputDir create(Optional customDir) { + return create(customDir, () -> Paths.get(".")); + } + + static OutputDir create(Optional customDir, Supplier currentWorkingDir) { try { - return createSafely(customDir, () -> Paths.get(".").toAbsolutePath()); + return createSafely(customDir, currentWorkingDir); } catch (IOException e) { throw new UncheckedIOException("Failed to create output dir", e); @@ -40,11 +52,21 @@ * Package private for testing purposes. */ static OutputDir createSafely(Optional customDir, Supplier currentWorkingDir) throws IOException { - Path cwd = currentWorkingDir.get(); + return createSafely(customDir, currentWorkingDir, new SecureRandom()); + } + + private static OutputDir createSafely(Optional customDir, Supplier currentWorkingDir, + SecureRandom random) throws IOException { + Path cwd = currentWorkingDir.get().toAbsolutePath(); Path outputDir; if (customDir.isPresent() && StringUtils.isNotBlank(customDir.get())) { - outputDir = cwd.resolve(customDir.get()); + String customPath = customDir.get(); + while (customPath.contains(OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER)) { + customPath = OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER_PATTERN.matcher(customPath) // + .replaceFirst(String.valueOf(Math.abs(random.nextLong()))); + } + outputDir = cwd.resolve(customPath); } else if (Files.exists(cwd.resolve("pom.xml"))) { outputDir = cwd.resolve("target"); @@ -60,13 +82,15 @@ Files.createDirectories(outputDir); } - return new OutputDir(outputDir); + return new OutputDir(outputDir.normalize(), random); } private final Path path; + private final SecureRandom random; - private OutputDir(Path path) { + private OutputDir(Path path, SecureRandom random) { this.path = path; + this.random = random; } public Path toPath() { @@ -74,7 +98,7 @@ } public Path createFile(String prefix, String extension) throws UncheckedIOException { - String filename = String.format("%s-%d.%s", prefix, Math.abs(new SecureRandom().nextLong()), extension); + String filename = String.format("%s-%d.%s", prefix, Math.abs(random.nextLong()), extension); Path outputFile = path.resolve(filename); try { @@ -93,18 +117,18 @@ * supplied extensions. */ private static boolean containsFilesWithExtensions(Path dir, String... extensions) throws IOException { - return Files.find(dir, 1, // - (path, basicFileAttributes) -> { - if (basicFileAttributes.isRegularFile()) { - for (String extension : extensions) { - if (path.getFileName().toString().endsWith(extension)) { - return true; - } + BiPredicate matcher = (path, basicFileAttributes) -> { + if (basicFileAttributes.isRegularFile()) { + for (String extension : extensions) { + if (path.getFileName().toString().endsWith(extension)) { + return true; } } - return false; - }) // - .findFirst() // - .isPresent(); + } + return false; + }; + try (Stream pathStream = Files.find(dir, 1, matcher)) { + return pathStream.findFirst().isPresent(); + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/SummaryGeneratingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/SummaryGeneratingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/SummaryGeneratingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/SummaryGeneratingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/TestExecutionSummary.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/TestExecutionSummary.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/TestExecutionSummary.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/TestExecutionSummary.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,8 +17,10 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; @@ -125,6 +127,8 @@ */ public static final String DEFAULT_OUTPUT_FILE_PREFIX = "junit-platform-unique-ids"; + static final String WORKING_DIR_PROPERTY_NAME = "junit.platform.listeners.uid.tracking.working.dir"; + private final Logger logger = LoggerFactory.getLogger(UniqueIdTrackingListener.class); private final List uniqueIds = new ArrayList<>(); @@ -201,7 +205,9 @@ private Path createOutputFile(ConfigurationParameters configurationParameters) { String prefix = configurationParameters.get(OUTPUT_FILE_PREFIX_PROPERTY_NAME) // .orElse(DEFAULT_OUTPUT_FILE_PREFIX); - return OutputDir.create(configurationParameters.get(OUTPUT_DIR_PROPERTY_NAME)) // + Supplier workingDirSupplier = () -> configurationParameters.get(WORKING_DIR_PROPERTY_NAME).map( + Paths::get).orElseGet(() -> Paths.get(".")); + return OutputDir.create(configurationParameters.get(OUTPUT_DIR_PROPERTY_NAME), workingDirSupplier) // .createFile(prefix, "txt"); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,15 +10,8 @@ package org.junit.platform.launcher.listeners.discovery; -import static org.junit.platform.engine.SelectorResolutionResult.Status.FAILED; -import static org.junit.platform.engine.SelectorResolutionResult.Status.UNRESOLVED; - -import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.util.ExceptionUtils; -import org.junit.platform.engine.DiscoverySelector; -import org.junit.platform.engine.SelectorResolutionResult; import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.discovery.UniqueIdSelector; import org.junit.platform.launcher.EngineDiscoveryResult; import org.junit.platform.launcher.LauncherDiscoveryListener; @@ -34,19 +27,6 @@ } @Override - public void selectorProcessed(UniqueId engineId, DiscoverySelector selector, SelectorResolutionResult result) { - if (result.getStatus() == FAILED) { - throw new JUnitException(selector + " resolution failed", result.getThrowable().orElse(null)); - } - if (result.getStatus() == UNRESOLVED && selector instanceof UniqueIdSelector) { - UniqueId uniqueId = ((UniqueIdSelector) selector).getUniqueId(); - if (uniqueId.hasPrefix(engineId)) { - throw new JUnitException(selector + " could not be resolved"); - } - } - } - - @Override public boolean equals(Object obj) { if (this == obj) { return true; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,7 @@ import java.util.Collections; import java.util.List; +import org.junit.platform.engine.DiscoveryIssue; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.SelectorResolutionResult; import org.junit.platform.engine.UniqueId; @@ -59,4 +60,10 @@ public void selectorProcessed(UniqueId engineId, DiscoverySelector selector, SelectorResolutionResult result) { listeners.forEach(delegate -> delegate.selectorProcessed(engineId, selector, result)); } + + @Override + public void issueEncountered(UniqueId engineId, DiscoveryIssue issue) { + listeners.forEach(delegate -> delegate.issueEncountered(engineId, issue)); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LauncherDiscoveryListeners.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LauncherDiscoveryListeners.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LauncherDiscoveryListeners.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LauncherDiscoveryListeners.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,9 +21,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.engine.SelectorResolutionResult.Status; import org.junit.platform.engine.TestEngine; -import org.junit.platform.engine.discovery.UniqueIdSelector; import org.junit.platform.launcher.LauncherDiscoveryListener; /** @@ -46,13 +44,6 @@ * *

      *
    • - * a {@linkplain Status#FAILED failed} resolution result. - *
    • - *
    • - * an {@linkplain Status#FAILED unresolved} resolution result for a - * {@link UniqueIdSelector} that starts with the engine's unique ID. - *
    • - *
    • * any recoverable {@link Throwable} thrown by * {@link TestEngine#discover}. *
    • diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,6 +18,7 @@ import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.engine.DiscoveryIssue; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.SelectorResolutionResult; import org.junit.platform.engine.UniqueId; @@ -89,6 +90,11 @@ } @Override + public void issueEncountered(UniqueId engineId, DiscoveryIssue issue) { + logger.trace(() -> "Issue encountered during discovery by TestEngine with ID '" + engineId + "': " + issue); + } + + @Override public boolean equals(Object obj) { if (this == obj) { return true; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/LauncherSessionListeners.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/LauncherSessionListeners.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/LauncherSessionListeners.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/session/LauncherSessionListeners.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/DequeStack.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/DequeStack.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/DequeStack.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/DequeStack.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operator.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operator.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operators.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operators.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operators.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Operators.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResult.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResult.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResults.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResults.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResults.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseResults.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseStatus.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseStatus.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseStatus.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ParseStatus.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Parser.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Parser.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Parser.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Parser.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ShuntingYard.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ShuntingYard.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ShuntingYard.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/ShuntingYard.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Stack.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Stack.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Stack.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Stack.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpression.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpression.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpression.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpression.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpressions.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpressions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpressions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TagExpressions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Token.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Token.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Token.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Token.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TokenWith.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TokenWith.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TokenWith.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/TokenWith.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Tokenizer.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Tokenizer.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Tokenizer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/main/java/org/junit/platform/launcher/tagexpression/Tokenizer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Public API for configuring and launching test plans. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/ConfigurationParametersFactoryForTests.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/ConfigurationParametersFactoryForTests.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/ConfigurationParametersFactoryForTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/ConfigurationParametersFactoryForTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/LauncherFactoryForTestingPurposesOnly.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/LauncherFactoryForTestingPurposesOnly.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/LauncherFactoryForTestingPurposesOnly.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/LauncherFactoryForTestingPurposesOnly.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/NamespacedHierarchicalStoreProviders.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/NamespacedHierarchicalStoreProviders.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/NamespacedHierarchicalStoreProviders.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/NamespacedHierarchicalStoreProviders.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.junit.platform.engine.support.store.NamespacedHierarchicalStore.CloseAction.closeAutoCloseables; + +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; + +public class NamespacedHierarchicalStoreProviders { + + public static NamespacedHierarchicalStore dummyNamespacedHierarchicalStore() { + return new NamespacedHierarchicalStore<>(dummyNamespacedHierarchicalStoreWithNoParent(), closeAutoCloseables()); + } + + public static NamespacedHierarchicalStore dummyNamespacedHierarchicalStoreWithNoParent() { + return new NamespacedHierarchicalStore<>(null, closeAutoCloseables()); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/OutputDirectoryCreators.java jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/OutputDirectoryCreators.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/OutputDirectoryCreators.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-launcher/src/testFixtures/java/org/junit/platform/launcher/core/OutputDirectoryCreators.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import java.nio.file.Path; + +import org.junit.platform.commons.JUnitException; +import org.junit.platform.engine.OutputDirectoryCreator; + +public class OutputDirectoryCreators { + + public static OutputDirectoryCreator dummyOutputDirectoryCreator() { + return new HierarchicalOutputDirectoryCreator(() -> { + throw new JUnitException("This should not be called; use a real implementation instead"); + }); + } + + public static OutputDirectoryCreator hierarchicalOutputDirectoryCreator(Path rootDir) { + return new HierarchicalOutputDirectoryCreator(() -> rootDir); + } + + private OutputDirectoryCreators() { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/junit-platform-reporting.gradle.kts jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/junit-platform-reporting.gradle.kts --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/junit-platform-reporting.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/junit-platform-reporting.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,9 @@ +import junitbuild.extensions.javaModuleName + plugins { id("junitbuild.java-library-conventions") id("junitbuild.shadow-conventions") + `java-test-fixtures` } description = "JUnit Platform Reporting" @@ -9,17 +12,25 @@ api(platform(projects.junitBom)) api(projects.junitPlatformLauncher) + implementation(libs.openTestReporting.tooling.spi) + compileOnlyApi(libs.apiguardian) shadowed(libs.openTestReporting.events) osgiVerification(projects.junitJupiterEngine) osgiVerification(projects.junitPlatformLauncher) + osgiVerification(libs.openTestReporting.tooling.spi) + + testFixturesApi(projects.junitJupiterApi) } tasks { shadowJar { - relocate("org.opentest4j.reporting", "org.junit.platform.reporting.shadow.org.opentest4j.reporting") + listOf("events", "schema").forEach { name -> + val packageName = "org.opentest4j.reporting.${name}" + relocate(packageName, "org.junit.platform.reporting.shadow.${packageName}") + } from(projectDir) { include("LICENSE-open-test-reporting.md") into("META-INF") diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/LegacyReportingUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/LegacyReportingUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/LegacyReportingUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/LegacyReportingUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,8 +21,8 @@ * Utility methods for dealing with legacy reporting infrastructure, such as * reporting systems built on the Ant-based XML reporting format for JUnit 4. * - * This class was formerly from {@code junit-platform-launcher} - * in {@link org.junit.platform.launcher.listeners} package. + *

      This class was formerly from {@code junit-platform-launcher} in the + * {@link org.junit.platform.launcher.listeners} package. * * @since 1.0.3 */ @@ -44,13 +44,14 @@ * {@linkplain TestIdentifier#getLegacyReportingName legacy reporting name}. * * @param testPlan the test plan that contains the {@code TestIdentifier}; - * never {@code null} + * never {@code null} * @param testIdentifier the identifier to determine the class name for; - * never {@code null} + * never {@code null} * @see TestIdentifier#getLegacyReportingName */ @SuppressWarnings("deprecation") public static String getClassName(TestPlan testPlan, TestIdentifier testIdentifier) { return org.junit.platform.launcher.listeners.LegacyReportingUtils.getClassName(testPlan, testIdentifier); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportData.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportData.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportData.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportData.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportWriter.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportWriter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportWriter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/GitInfoCollector.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/GitInfoCollector.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/GitInfoCollector.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/GitInfoCollector.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,209 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.reporting.open.xml; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; + +import org.junit.platform.commons.util.ExceptionUtils; +import org.junit.platform.commons.util.StringUtils; + +/** + * @since 1.13.2 + */ +interface GitInfoCollector { + + static Optional get(Path workingDir) { + ProcessExecutor executor = new ProcessExecutor(workingDir); + boolean gitInstalled = executor.exec("git", "--version").isPresent(); + return gitInstalled ? Optional.of(new CliGitInfoCollector(executor)) : Optional.empty(); + } + + Optional getOriginUrl(); + + Optional getBranch(); + + Optional getCommitHash(); + + Optional getStatus(); + + class CliGitInfoCollector implements GitInfoCollector { + + private static final String ALLOWED_USERNAME = "git"; + private static final String USER_INFO_REPLACEMENT = "***"; + private static final String USER_INFO_SEPARATOR = "@"; + + private final ProcessExecutor executor; + + public CliGitInfoCollector(ProcessExecutor executor) { + this.executor = executor; + } + + @Override + public Optional getOriginUrl() { + return executor.exec("git", "config", "--get", "remote.origin.url") // + .filter(StringUtils::isNotBlank) // + .flatMap(this::toGitUrl) // + .flatMap(this::obfuscateUserInfo); + } + + @Override + public Optional getBranch() { + return executor.exec("git", "rev-parse", "--abbrev-ref", "HEAD") // + .filter(StringUtils::isNotBlank); + } + + @Override + public Optional getCommitHash() { + return executor.exec("git", "rev-parse", "--verify", "HEAD") // + .filter(StringUtils::isNotBlank); + } + + @Override + public Optional getStatus() { + return executor.exec("git", "status", "--porcelain"); + } + + private Optional obfuscateUserInfo(GitUrl gitUrl) { + try { + if (gitUrl.uri.getUserInfo() != null) { + URI newUri = new URI(gitUrl.uri.getScheme(), USER_INFO_REPLACEMENT, gitUrl.uri.getHost(), + gitUrl.uri.getPort(), gitUrl.uri.getPath(), gitUrl.uri.getQuery(), gitUrl.uri.getFragment()); + return Optional.of(newUri.toString().substring(gitUrl.addedPrefix.length())); + } + if (gitUrl.uri.getAuthority() != null && gitUrl.uri.getAuthority().contains(USER_INFO_SEPARATOR)) { + String oldAuthority = gitUrl.uri.getAuthority(); + String[] parts = oldAuthority.split(USER_INFO_SEPARATOR, 2); + if (!ALLOWED_USERNAME.equals(parts[0])) { + String newAuthority = USER_INFO_REPLACEMENT + USER_INFO_SEPARATOR + parts[1]; + URI newUri = new URI(gitUrl.uri.getScheme(), newAuthority, gitUrl.uri.getPath(), + gitUrl.uri.getQuery(), gitUrl.uri.getFragment()); + return Optional.of(newUri.toString().substring(gitUrl.addedPrefix.length())); + } + } + return Optional.of(gitUrl.rawValue); + } + catch (URISyntaxException e) { + return Optional.empty(); + } + } + + private Optional toGitUrl(String remoteUrl) { + try { + return Optional.of(new GitUrl(remoteUrl, new URI(remoteUrl), "")); + } + catch (URISyntaxException ex) { + try { + return Optional.of(new GitUrl(remoteUrl, new URI("ssh://" + remoteUrl), "ssh://")); + } + catch (URISyntaxException ignore) { + return Optional.empty(); + } + } + } + } + + class ProcessExecutor { + + private final Path workingDir; + + ProcessExecutor(Path workingDir) { + this.workingDir = workingDir; + } + + Optional exec(String... args) { + + Process process = startProcess(args); + + try (Reader out = newBufferedReader(process.getInputStream()); + Reader err = newBufferedReader(process.getErrorStream())) { + + StringBuilder output = new StringBuilder(); + readAllChars(out, (chars, numChars) -> output.append(chars, 0, numChars)); + + readAllChars(err, (__, ___) -> { + // ignore + }); + + boolean terminated = process.waitFor(10, TimeUnit.SECONDS); + return terminated && process.exitValue() == 0 ? Optional.of(trimAtEnd(output)) : Optional.empty(); + } + catch (InterruptedException e) { + throw ExceptionUtils.throwAsUncheckedException(e); + } + catch (IOException ignore) { + return Optional.empty(); + } + finally { + process.destroyForcibly(); + } + } + + private static BufferedReader newBufferedReader(InputStream stream) { + return new BufferedReader(new InputStreamReader(stream, Charset.defaultCharset())); + } + + private Process startProcess(String[] command) { + Process process; + try { + process = new ProcessBuilder().directory(workingDir.toFile()).command(command).start(); + } + catch (IOException e) { + throw new UncheckedIOException("Failed to start process", e); + } + return process; + } + + private static void readAllChars(Reader reader, BiConsumer consumer) throws IOException { + char[] buffer = new char[1024]; + int numChars; + while ((numChars = reader.read(buffer)) != -1) { + consumer.accept(buffer, numChars); + } + } + + private static String trimAtEnd(StringBuilder value) { + int endIndex = value.length(); + for (int i = value.length() - 1; i >= 0; i--) { + if (Character.isWhitespace(value.charAt(i))) { + endIndex--; + break; + } + } + return value.substring(0, endIndex); + } + } + + class GitUrl { + + private final String rawValue; + private final URI uri; + private final String addedPrefix; + + GitUrl(String rawValue, URI uri, String addedPrefix) { + this.rawValue = rawValue; + this.uri = uri; + this.addedPrefix = addedPrefix; + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitContributor.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitContributor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitContributor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitContributor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.reporting.open.xml; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.tooling.spi.htmlreport.Contributor; +import org.opentest4j.reporting.tooling.spi.htmlreport.KeyValuePairs; +import org.opentest4j.reporting.tooling.spi.htmlreport.Section; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Contributes a section containing JUnit-specific metadata for each test node + * to the open-test-reporting HTML report. + * + * @since 1.12 + */ +@SuppressWarnings("exports") // we don't want to export 'org.opentest4j.reporting.tooling.spi' transitively +@API(status = INTERNAL, since = "1.12") +public class JUnitContributor implements Contributor { + + public JUnitContributor() { + } + + @Override + public List

      contributeSectionsForTestNode(Context context) { + return findChild(context.element(), Namespace.REPORTING_CORE, "metadata") // + .map(metadata -> { + Map table = new LinkedHashMap<>(); + findChild(metadata, JUnitFactory.NAMESPACE, "type") // + .map(Node::getTextContent) // + .ifPresent(value -> table.put("Type", value)); + findChild(metadata, JUnitFactory.NAMESPACE, "uniqueId") // + .map(Node::getTextContent) // + .ifPresent(value -> table.put("Unique ID", value)); + findChild(metadata, JUnitFactory.NAMESPACE, "legacyReportingName") // + .map(Node::getTextContent) // + .ifPresent(value -> table.put("Legacy reporting name", value)); + return table; + }) // + .filter(table -> !table.isEmpty()) // + .map(table -> singletonList(Section.builder() // + .title("JUnit metadata") // + .order(15) // + .addBlock(KeyValuePairs.builder().content(table).build()) // + .build())) // + .orElse(emptyList()); + } + + private static Optional findChild(Node parent, Namespace namespace, String localName) { + NodeList children = parent.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (localName.equals(child.getLocalName()) && namespace.getUri().equals(child.getNamespaceURI())) { + return Optional.of(child); + } + } + return Optional.empty(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitFactory.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitFactory.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/LegacyReportingName.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/LegacyReportingName.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/LegacyReportingName.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/LegacyReportingName.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,10 @@ package org.junit.platform.reporting.open.xml; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; +import static org.junit.platform.commons.util.StringUtils.isNotBlank; +import static org.junit.platform.launcher.LauncherConstants.STDERR_REPORT_ENTRY_KEY; +import static org.junit.platform.launcher.LauncherConstants.STDOUT_REPORT_ENTRY_KEY; import static org.junit.platform.reporting.open.xml.JUnitFactory.legacyReportingName; import static org.junit.platform.reporting.open.xml.JUnitFactory.type; import static org.junit.platform.reporting.open.xml.JUnitFactory.uniqueId; @@ -18,11 +21,13 @@ import static org.opentest4j.reporting.events.core.CoreFactory.cpuCores; import static org.opentest4j.reporting.events.core.CoreFactory.data; import static org.opentest4j.reporting.events.core.CoreFactory.directorySource; +import static org.opentest4j.reporting.events.core.CoreFactory.file; import static org.opentest4j.reporting.events.core.CoreFactory.fileSource; import static org.opentest4j.reporting.events.core.CoreFactory.hostName; import static org.opentest4j.reporting.events.core.CoreFactory.infrastructure; import static org.opentest4j.reporting.events.core.CoreFactory.metadata; import static org.opentest4j.reporting.events.core.CoreFactory.operatingSystem; +import static org.opentest4j.reporting.events.core.CoreFactory.output; import static org.opentest4j.reporting.events.core.CoreFactory.reason; import static org.opentest4j.reporting.events.core.CoreFactory.result; import static org.opentest4j.reporting.events.core.CoreFactory.sources; @@ -30,6 +35,10 @@ import static org.opentest4j.reporting.events.core.CoreFactory.tags; import static org.opentest4j.reporting.events.core.CoreFactory.uriSource; import static org.opentest4j.reporting.events.core.CoreFactory.userName; +import static org.opentest4j.reporting.events.git.GitFactory.branch; +import static org.opentest4j.reporting.events.git.GitFactory.commit; +import static org.opentest4j.reporting.events.git.GitFactory.repository; +import static org.opentest4j.reporting.events.git.GitFactory.status; import static org.opentest4j.reporting.events.java.JavaFactory.classSource; import static org.opentest4j.reporting.events.java.JavaFactory.classpathResourceSource; import static org.opentest4j.reporting.events.java.JavaFactory.fileEncoding; @@ -47,18 +56,20 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.file.Path; +import java.nio.file.Paths; import java.time.Instant; +import java.time.LocalDateTime; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.util.StringUtils; import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.descriptor.ClassSource; import org.junit.platform.engine.support.descriptor.ClasspathResourceSource; @@ -71,9 +82,10 @@ import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestPlan; -import org.junit.platform.launcher.listeners.OutputDir; import org.opentest4j.reporting.events.api.DocumentWriter; import org.opentest4j.reporting.events.api.NamespaceRegistry; +import org.opentest4j.reporting.events.core.Attachments; +import org.opentest4j.reporting.events.core.Infrastructure; import org.opentest4j.reporting.events.core.Result; import org.opentest4j.reporting.events.core.Sources; import org.opentest4j.reporting.events.root.Events; @@ -84,17 +96,25 @@ * * @since 1.9 */ -@API(status = EXPERIMENTAL, since = "1.9") +@API(status = MAINTAINED, since = "1.13.3") public class OpenTestReportGeneratingListener implements TestExecutionListener { static final String ENABLED_PROPERTY_NAME = "junit.platform.reporting.open.xml.enabled"; - static final String OUTPUT_DIR_PROPERTY_NAME = "junit.platform.reporting.output.dir"; + static final String GIT_ENABLED_PROPERTY_NAME = "junit.platform.reporting.open.xml.git.enabled"; private final AtomicInteger idCounter = new AtomicInteger(); private final Map inProgressIds = new ConcurrentHashMap<>(); private DocumentWriter eventsFileWriter = DocumentWriter.noop(); + private final Path workingDir; + private Path outputDir; + @SuppressWarnings("unused") // Used via ServiceLoader public OpenTestReportGeneratingListener() { + this(Paths.get(".").toAbsolutePath()); + } + + OpenTestReportGeneratingListener(Path workingDir) { + this.workingDir = workingDir; } @Override @@ -103,15 +123,15 @@ if (isEnabled(config)) { NamespaceRegistry namespaceRegistry = NamespaceRegistry.builder(Namespace.REPORTING_CORE) // .add("e", Namespace.REPORTING_EVENTS) // + .add("git", Namespace.REPORTING_GIT) // .add("java", Namespace.REPORTING_JAVA) // - .add("junit", JUnitFactory.NAMESPACE, - "https://junit.org/junit5/schemas/open-test-reporting/junit-1.9.xsd") // + .add("junit", JUnitFactory.NAMESPACE, "https://schemas.junit.org/open-test-reporting/junit-1.9.xsd") // .build(); - Path eventsXml = OutputDir.create(config.get(OUTPUT_DIR_PROPERTY_NAME)) // - .createFile("junit-platform-events", "xml"); + outputDir = testPlan.getOutputDirectoryCreator().getRootDirectory(); + Path eventsXml = outputDir.resolve("open-test-report.xml"); try { eventsFileWriter = Events.createDocumentWriter(namespaceRegistry, eventsXml); - reportInfrastructure(); + reportInfrastructure(config); } catch (Exception e) { throw new JUnitException("Failed to initialize XML events file: " + eventsXml, e); @@ -119,11 +139,15 @@ } } - private Boolean isEnabled(ConfigurationParameters config) { + private boolean isEnabled(ConfigurationParameters config) { return config.getBoolean(ENABLED_PROPERTY_NAME).orElse(false); } - private void reportInfrastructure() { + private boolean isGitEnabled(ConfigurationParameters config) { + return config.getBoolean(GIT_ENABLED_PROPERTY_NAME).orElse(false); + } + + private void reportInfrastructure(ConfigurationParameters config) { eventsFileWriter.append(infrastructure(), infrastructure -> { try { String hostName = InetAddress.getLocalHost().getHostName(); @@ -138,9 +162,26 @@ .append(javaVersion(System.getProperty("java.version"))) // .append(fileEncoding(System.getProperty("file.encoding"))) // .append(heapSize(), heapSize -> heapSize.withMax(Runtime.getRuntime().maxMemory())); + + if (isGitEnabled(config)) { + GitInfoCollector.get(workingDir).ifPresent(git -> addGitInfo(infrastructure, git)); + } }); } + private void addGitInfo(Infrastructure infrastructure, GitInfoCollector git) { + git.getOriginUrl() // + .ifPresent( + gitUrl -> infrastructure.append(repository(), repository -> repository.withOriginUrl(gitUrl))); + git.getBranch() // + .ifPresent(branch -> infrastructure.append(branch(branch))); + git.getCommitHash() // + .ifPresent(gitCommitHash -> infrastructure.append(commit(gitCommitHash))); + git.getStatus() // + .ifPresent(statusOutput -> infrastructure.append(status(statusOutput), + status -> status.withClean(statusOutput.isEmpty()))); + } + @Override public void testPlanExecutionFinished(TestPlan testPlan) { try { @@ -160,7 +201,7 @@ reportStarted(testIdentifier, id); eventsFileWriter.append(finished(id, Instant.now()), // finished -> finished.append(result(Result.Status.SKIPPED), result -> { - if (StringUtils.isNotBlank(reason)) { + if (isNotBlank(reason)) { result.append(reason(reason)); } })); @@ -237,8 +278,37 @@ String id = inProgressIds.get(testIdentifier.getUniqueIdObject()); eventsFileWriter.append(reported(id, Instant.now()), // reported -> reported.append(attachments(), // - attachments -> attachments.append(data(entry.getTimestamp()), // - data -> entry.getKeyValuePairs().forEach(data::addEntry)))); + attachments -> { + Map keyValuePairs = entry.getKeyValuePairs(); + if (keyValuePairs.containsKey(STDOUT_REPORT_ENTRY_KEY) + || keyValuePairs.containsKey(STDERR_REPORT_ENTRY_KEY)) { + attachOutput(attachments, entry.getTimestamp(), keyValuePairs.get(STDOUT_REPORT_ENTRY_KEY), + "stdout"); + attachOutput(attachments, entry.getTimestamp(), keyValuePairs.get(STDERR_REPORT_ENTRY_KEY), + "stderr"); + } + else { + attachments.append(data(entry.getTimestamp()), // + data -> keyValuePairs.forEach(data::addEntry)); + } + })); + } + + private static void attachOutput(Attachments attachments, LocalDateTime timestamp, String content, String source) { + if (content != null) { + attachments.append(output(timestamp), output -> output.withSource(source).withContent(content)); + } + } + + @Override + public void fileEntryPublished(TestIdentifier testIdentifier, FileEntry entry) { + String id = inProgressIds.get(testIdentifier.getUniqueIdObject()); + eventsFileWriter.append(reported(id, Instant.now()), // + reported -> reported.append(attachments(), attachments -> attachments.append(file(entry.getTimestamp()), // + file -> { + file.withPath(outputDir.relativize(entry.getPath()).toString()); + entry.getMediaType().ifPresent(file::withMediaType); + }))); } @Override diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/Type.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/Type.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/Type.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/Type.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/UniqueId.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/UniqueId.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/UniqueId.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/UniqueId.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +org.junit.platform.reporting.open.xml.JUnitContributor diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/resources/org/junit/platform/reporting/open/xml/catalog.xml jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/resources/org/junit/platform/reporting/open/xml/catalog.xml --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/main/resources/org/junit/platform/reporting/open/xml/catalog.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/main/resources/org/junit/platform/reporting/open/xml/catalog.xml 2026-06-21 20:26:05.000000000 +0000 @@ -1,4 +1,4 @@ - + diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/module/org.junit.platform.reporting/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/module/org.junit.platform.reporting/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/module/org.junit.platform.reporting/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/module/org.junit.platform.reporting/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Defines the JUnit Platform Reporting API. * @@ -19,6 +20,7 @@ requires org.junit.platform.commons; requires transitive org.junit.platform.engine; requires transitive org.junit.platform.launcher; + requires org.opentest4j.reporting.tooling.spi; // exports org.junit.platform.reporting; empty package exports org.junit.platform.reporting.legacy; @@ -27,4 +29,7 @@ provides org.junit.platform.launcher.TestExecutionListener with org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener; + + provides org.opentest4j.reporting.tooling.spi.htmlreport.Contributor + with org.junit.platform.reporting.open.xml.JUnitContributor; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/open/xml/OpenTestReportGenerationSystemPropertyOverride.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/open/xml/OpenTestReportGenerationSystemPropertyOverride.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/open/xml/OpenTestReportGenerationSystemPropertyOverride.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/open/xml/OpenTestReportGenerationSystemPropertyOverride.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.reporting.open.xml; + +import static org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener.ENABLED_PROPERTY_NAME; + +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +public class OpenTestReportGenerationSystemPropertyOverride + implements BeforeTestExecutionCallback, AfterTestExecutionCallback { + + @Override + public void beforeTestExecution(ExtensionContext context) { + var oldValue = System.clearProperty(ENABLED_PROPERTY_NAME); + getStore(context).put(ENABLED_PROPERTY_NAME, oldValue); + } + + @Override + public void afterTestExecution(ExtensionContext context) { + var oldValue = getStore(context).get(ENABLED_PROPERTY_NAME, String.class); + if (oldValue == null) { + System.clearProperty(ENABLED_PROPERTY_NAME); + } + else { + System.setProperty(ENABLED_PROPERTY_NAME, oldValue); + } + } + + private static ExtensionContext.Store getStore(ExtensionContext context) { + return context.getStore( + ExtensionContext.Namespace.create(OpenTestReportGenerationSystemPropertyOverride.class)); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/testutil/FileUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/testutil/FileUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/testutil/FileUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/java/org/junit/platform/reporting/testutil/FileUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.reporting.testutil; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class FileUtils { + + public static Path findPath(Path rootDir, String syntaxAndPattern) { + var matcher = rootDir.getFileSystem().getPathMatcher(syntaxAndPattern); + try (var files = Files.walk(rootDir)) { + return files.filter(matcher::matches).findFirst() // + .orElseThrow(() -> new AssertionError( + "Failed to find file matching '%s' in %s".formatted(syntaxAndPattern, rootDir))); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension --- jtreg8-8.1+1+ds1/junit5/junit-platform-reporting/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-reporting/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +org.junit.platform.reporting.open.xml.OpenTestReportGenerationSystemPropertyOverride diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -160,6 +160,7 @@ return new JUnitPlatformTestTree(testPlan, this.testClass); } + @SuppressWarnings("deprecation") private LauncherDiscoveryRequest createDiscoveryRequest() { SuiteLauncherDiscoveryRequestBuilder requestBuilder = request(); // Allows @RunWith(JUnitPlatform.class) to be added to any test case diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformRunnerListener.java jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformRunnerListener.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformRunnerListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformRunnerListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,7 @@ import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.TestExecutionResult.Status; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; @@ -85,6 +86,11 @@ System.out.println(entry); } + @Override + public void fileEntryPublished(TestIdentifier testIdentifier, FileEntry file) { + System.out.println(file); + } + private Failure toFailure(TestExecutionResult testExecutionResult, Description description) { return new Failure(description, testExecutionResult.getThrowable().orElse(null)); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformTestTree.java jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformTestTree.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformTestTree.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformTestTree.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -22,7 +22,7 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.junit.platform.commons.util.AnnotationUtils; +import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.UniqueId; @@ -76,7 +76,7 @@ private String getSuiteDisplayName(Class testClass) { // @formatter:off - return AnnotationUtils.findAnnotation(testClass, SuiteDisplayName.class) + return AnnotationSupport.findAnnotation(testClass, SuiteDisplayName.class) .map(SuiteDisplayName::value) .filter(StringUtils::isNotBlank) .orElse(testClass.getName()); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/module/org.junit.platform.runner/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/module/org.junit.platform.runner/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-runner/src/module/org.junit.platform.runner/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-runner/src/module/org.junit.platform.runner/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * {@code Runner} and annotations for configuring and executing tests on the * JUnit Platform in a JUnit 4 environment. diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite/junit-platform-suite.gradle.kts jtreg8-8.3+1+ds1/junit5/junit-platform-suite/junit-platform-suite.gradle.kts --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite/junit-platform-suite.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite/junit-platform-suite.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -12,3 +12,7 @@ osgiVerification(projects.junitJupiterEngine) osgiVerification(projects.junitPlatformLauncher) } + +japicmp { + enabled = false // already checked by individual projects +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite/src/module/org.junit.platform.suite/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite/src/module/org.junit.platform.suite/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite/src/module/org.junit.platform.suite/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite/src/module/org.junit.platform.suite/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2020 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Aggregates all JUnit Platform Suite modules. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/AfterSuite.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/AfterSuite.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/AfterSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/AfterSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -70,6 +70,6 @@ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public @interface AfterSuite { } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/BeforeSuite.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/BeforeSuite.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/BeforeSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/BeforeSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -70,6 +70,6 @@ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public @interface BeforeSuite { } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameter.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameter.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameters.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameters.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameters.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParameters.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -39,7 +39,7 @@ @Target(ElementType.TYPE) @Inherited @Documented -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") @Repeatable(ConfigurationParametersResources.class) public @interface ConfigurationParametersResource { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -36,7 +36,7 @@ @Target(ElementType.TYPE) @Inherited @Documented -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public @interface ConfigurationParametersResources { /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/DisableParentConfigurationParameters.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/DisableParentConfigurationParameters.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/DisableParentConfigurationParameters.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/DisableParentConfigurationParameters.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeClassNamePatterns.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeClassNamePatterns.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeClassNamePatterns.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeClassNamePatterns.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeEngines.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeEngines.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeEngines.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeEngines.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludePackages.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludePackages.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludePackages.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludePackages.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeTags.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeTags.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeTags.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ExcludeTags.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -31,7 +31,7 @@ *

      Tag expressions are boolean expressions with the following allowed * operators: {@code !} (not), {@code &} (and) and {@code |} (or). Parentheses * can be used to adjust for operator precedence. Please refer to the - * JUnit 5 User Guide + * JUnit 5 User Guide * for usage examples. * *

      Syntax Rules for Tags

      diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeClassNamePatterns.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeClassNamePatterns.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeClassNamePatterns.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeClassNamePatterns.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeEngines.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeEngines.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeEngines.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeEngines.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludePackages.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludePackages.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludePackages.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludePackages.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeTags.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeTags.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeTags.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/IncludeTags.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -31,7 +31,7 @@ *

      Tag expressions are boolean expressions with the following allowed * operators: {@code !} (not), {@code &} (and) and {@code |} (or). Parentheses * can be used to adjust for operator precedence. Please refer to the - * JUnit 5 User Guide + * JUnit 5 User Guide * for usage examples. * *

      Syntax Rules for Tags

      diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Select.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Select.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Select.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Select.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -35,7 +35,7 @@ @Target(ElementType.TYPE) @Inherited @Documented -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") @Repeatable(Selects.class) public @interface Select { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasses.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasses.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasses.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasses.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; @@ -57,7 +56,7 @@ * * @since 1.10 */ - @API(status = EXPERIMENTAL, since = "1.10") + @API(status = MAINTAINED, since = "1.13.3") String[] names() default {}; } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResource.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResource.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResources.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResources.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectClasspathResources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectDirectories.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectDirectories.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectDirectories.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectDirectories.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFile.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFile.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFile.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFile.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFiles.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFiles.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFiles.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectFiles.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethod.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -40,7 +40,7 @@ @Target(ElementType.TYPE) @Inherited @Documented -@API(status = EXPERIMENTAL, since = "1.10") +@API(status = MAINTAINED, since = "1.13.3") @Repeatable(SelectMethods.class) public @interface SelectMethod { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethods.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethods.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethods.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectMethods.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -36,7 +36,7 @@ @Target(ElementType.TYPE) @Inherited @Documented -@API(status = EXPERIMENTAL, since = "1.10") +@API(status = MAINTAINED, since = "1.13.3") public @interface SelectMethods { /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectModules.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectModules.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectModules.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectModules.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectPackages.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectPackages.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectPackages.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectPackages.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectUris.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectUris.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectUris.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SelectUris.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Selects.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Selects.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Selects.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Selects.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.platform.suite.api; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -36,7 +36,7 @@ @Target(ElementType.TYPE) @Inherited @Documented -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = MAINTAINED, since = "1.13.3") public @interface Selects { /** diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Suite.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Suite.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Suite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/Suite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SuiteDisplayName.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SuiteDisplayName.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SuiteDisplayName.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/SuiteDisplayName.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/UseTechnicalNames.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/UseTechnicalNames.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/UseTechnicalNames.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/UseTechnicalNames.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/module/org.junit.platform.suite.api/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/module/org.junit.platform.suite.api/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-api/src/module/org.junit.platform.suite.api/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-api/src/module/org.junit.platform.suite.api/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Annotations for configuring a test suite on the JUnit Platform. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/AdditionalDiscoverySelectors.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/AdditionalDiscoverySelectors.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/AdditionalDiscoverySelectors.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/AdditionalDiscoverySelectors.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,8 +11,10 @@ package org.junit.platform.suite.commons; import static java.util.stream.Collectors.toList; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; -import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; import static org.junit.platform.engine.discovery.ClassNameFilter.STANDARD_INCLUDE_PATTERN; import static org.junit.platform.suite.commons.AdditionalDiscoverySelectors.selectClasspathResource; import static org.junit.platform.suite.commons.AdditionalDiscoverySelectors.selectFile; @@ -30,18 +32,19 @@ import java.util.stream.Stream; import org.apiguardian.api.API; -import org.apiguardian.api.API.Status; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.Filter; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.discovery.ClassNameFilter; import org.junit.platform.engine.discovery.ClassSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.discovery.MethodSelector; import org.junit.platform.engine.discovery.PackageNameFilter; import org.junit.platform.launcher.EngineFilter; +import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.TagFilter; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; @@ -110,8 +113,7 @@ * @see org.junit.platform.launcher.EngineFilter * @see org.junit.platform.launcher.TagFilter */ -@API(status = Status.INTERNAL, since = "1.8", consumers = { "org.junit.platform.suite.engine", - "org.junit.platform.runner" }) +@API(status = INTERNAL, since = "1.8", consumers = { "org.junit.platform.suite.engine", "org.junit.platform.runner" }) public final class SuiteLauncherDiscoveryRequestBuilder { private final LauncherDiscoveryRequestBuilder delegate = LauncherDiscoveryRequestBuilder.request(); @@ -261,6 +263,17 @@ return this; } + public SuiteLauncherDiscoveryRequestBuilder outputDirectoryCreator(OutputDirectoryCreator outputDirectoryCreator) { + delegate.outputDirectoryCreator(outputDirectoryCreator); + return this; + } + + @API(status = INTERNAL, since = "1.13") + public SuiteLauncherDiscoveryRequestBuilder listener(LauncherDiscoveryListener listener) { + delegate.listeners(listener); + return this; + } + /** * Apply a suite's annotation-based configuration, selectors, and filters to * this builder. @@ -273,6 +286,7 @@ * {@link #applySelectorsAndFiltersFromSuite} */ @Deprecated + @API(status = DEPRECATED, since = "1.11") public SuiteLauncherDiscoveryRequestBuilder suite(Class suiteClass) { Preconditions.notNull(suiteClass, "Suite class must not be null"); applyConfigurationParametersFromSuite(suiteClass); @@ -331,6 +345,7 @@ *
    • {@link SelectModules}
    • *
    • {@link SelectUris}
    • *
    • {@link SelectPackages}
    • + *
    • {@link Select}
    • *
    * * @param suiteClass the class to apply the discovery selectors and filter @@ -342,71 +357,84 @@ public SuiteLauncherDiscoveryRequestBuilder applySelectorsAndFiltersFromSuite(Class suiteClass) { Preconditions.notNull(suiteClass, "Suite class must not be null"); - // Annotations in alphabetical order (except @SelectClasses) - // @formatter:off - findAnnotationValues(suiteClass, ExcludeClassNamePatterns.class, ExcludeClassNamePatterns::value) - .flatMap(SuiteLauncherDiscoveryRequestBuilder::trimmed) - .map(ClassNameFilter::excludeClassNamePatterns) + addExcludeFilters(suiteClass); + // Process @SelectClasses and @SelectMethod before @IncludeClassNamePatterns, since the names + // of selected classes get automatically added to the include filter. + addClassAndMethodSelectors(suiteClass); + addIncludeFilters(suiteClass); + addOtherSelectors(suiteClass); + return this; + } + + private void addExcludeFilters(Class suiteClass) { + findAnnotationValues(suiteClass, ExcludeClassNamePatterns.class, ExcludeClassNamePatterns::value) // + .flatMap(SuiteLauncherDiscoveryRequestBuilder::trimmed) // + .map(ClassNameFilter::excludeClassNamePatterns) // .ifPresent(this::filters); - findAnnotationValues(suiteClass, ExcludeEngines.class, ExcludeEngines::value) - .map(EngineFilter::excludeEngines) + findAnnotationValues(suiteClass, ExcludeEngines.class, ExcludeEngines::value) // + .map(EngineFilter::excludeEngines) // .ifPresent(this::filters); - findAnnotationValues(suiteClass, ExcludePackages.class, ExcludePackages::value) - .map(PackageNameFilter::excludePackageNames) + findAnnotationValues(suiteClass, ExcludePackages.class, ExcludePackages::value) // + .map(PackageNameFilter::excludePackageNames) // .ifPresent(this::filters); - findAnnotationValues(suiteClass, ExcludeTags.class, ExcludeTags::value) - .map(TagFilter::excludeTags) + findAnnotationValues(suiteClass, ExcludeTags.class, ExcludeTags::value) // + .map(TagFilter::excludeTags) // .ifPresent(this::filters); - // Process @SelectClasses before @IncludeClassNamePatterns, since the names - // of selected classes get automatically added to the include filter. - findAnnotation(suiteClass, SelectClasses.class) - .map(annotation -> selectClasses(suiteClass, annotation)) + } + + private void addClassAndMethodSelectors(Class suiteClass) { + findAnnotation(suiteClass, SelectClasses.class) // + .map(annotation -> selectClasses(suiteClass, annotation)) // .ifPresent(this::selectors); - findRepeatableAnnotations(suiteClass, SelectMethod.class) - .stream() - .map(annotation -> selectMethod(suiteClass, annotation)) + findRepeatableAnnotations(suiteClass, SelectMethod.class) // + .stream() // + .map(annotation -> selectMethod(suiteClass, annotation)) // .forEach(this::selectors); - findAnnotationValues(suiteClass, IncludeClassNamePatterns.class, IncludeClassNamePatterns::value) - .flatMap(SuiteLauncherDiscoveryRequestBuilder::trimmed) - .map(this::createIncludeClassNameFilter) + } + + private void addIncludeFilters(Class suiteClass) { + findAnnotationValues(suiteClass, IncludeClassNamePatterns.class, IncludeClassNamePatterns::value) // + .flatMap(SuiteLauncherDiscoveryRequestBuilder::trimmed) // + .map(this::createIncludeClassNameFilter) // .ifPresent(filters -> { this.includeClassNamePatternsUsed = true; filters(filters); }); - findAnnotationValues(suiteClass, IncludeEngines.class, IncludeEngines::value) - .map(EngineFilter::includeEngines) + findAnnotationValues(suiteClass, IncludeEngines.class, IncludeEngines::value) // + .map(EngineFilter::includeEngines) // .ifPresent(this::filters); - findAnnotationValues(suiteClass, IncludePackages.class, IncludePackages::value) - .map(PackageNameFilter::includePackageNames) + findAnnotationValues(suiteClass, IncludePackages.class, IncludePackages::value) // + .map(PackageNameFilter::includePackageNames) // .ifPresent(this::filters); - findAnnotationValues(suiteClass, IncludeTags.class, IncludeTags::value) - .map(TagFilter::includeTags) + findAnnotationValues(suiteClass, IncludeTags.class, IncludeTags::value) // + .map(TagFilter::includeTags) // .ifPresent(this::filters); - findRepeatableAnnotations(suiteClass, SelectClasspathResource.class) - .stream() - .map(annotation -> selectClasspathResource(annotation.value(), annotation.line(), annotation.column())) + } + + private void addOtherSelectors(Class suiteClass) { + findRepeatableAnnotations(suiteClass, SelectClasspathResource.class) // + .stream() // + .map(annotation -> selectClasspathResource(annotation.value(), annotation.line(), annotation.column())) // .forEach(this::selectors); - findAnnotationValues(suiteClass, SelectDirectories.class, SelectDirectories::value) - .map(AdditionalDiscoverySelectors::selectDirectories) + findAnnotationValues(suiteClass, SelectDirectories.class, SelectDirectories::value) // + .map(AdditionalDiscoverySelectors::selectDirectories) // .ifPresent(this::selectors); - findRepeatableAnnotations(suiteClass, SelectFile.class) - .stream() - .map(annotation -> selectFile(annotation.value(), annotation.line(), annotation.column())) + findRepeatableAnnotations(suiteClass, SelectFile.class) // + .stream() // + .map(annotation -> selectFile(annotation.value(), annotation.line(), annotation.column())) // .forEach(this::selectors); - findAnnotationValues(suiteClass, SelectModules.class, SelectModules::value) - .map(AdditionalDiscoverySelectors::selectModules) + findAnnotationValues(suiteClass, SelectModules.class, SelectModules::value) // + .map(AdditionalDiscoverySelectors::selectModules) // .ifPresent(this::selectors); - findAnnotationValues(suiteClass, SelectUris.class, SelectUris::value) - .map(AdditionalDiscoverySelectors::selectUris) + findAnnotationValues(suiteClass, SelectUris.class, SelectUris::value) // + .map(AdditionalDiscoverySelectors::selectUris) // .ifPresent(this::selectors); - findAnnotationValues(suiteClass, SelectPackages.class, SelectPackages::value) - .map(AdditionalDiscoverySelectors::selectPackages) + findAnnotationValues(suiteClass, SelectPackages.class, SelectPackages::value) // + .map(AdditionalDiscoverySelectors::selectPackages) // .ifPresent(this::selectors); - findAnnotationValues(suiteClass, Select.class, Select::value) - .map(AdditionalDiscoverySelectors::parseIdentifiers) + findAnnotationValues(suiteClass, Select.class, Select::value) // + .map(AdditionalDiscoverySelectors::parseIdentifiers) // .ifPresent(this::selectors); - // @formatter:on - return this; } /** @@ -450,23 +478,7 @@ private MethodSelector toMethodSelector(Class suiteClass, SelectMethod annotation) { if (!annotation.value().isEmpty()) { - Preconditions.condition(annotation.type() == Class.class, - () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, - "type must not be set in conjunction with fully qualified method name")); - Preconditions.condition(annotation.typeName().isEmpty(), - () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, - "type name must not be set in conjunction with fully qualified method name")); - Preconditions.condition(annotation.name().isEmpty(), - () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, - "method name must not be set in conjunction with fully qualified method name")); - Preconditions.condition(annotation.parameterTypes().length == 0, - () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, - "parameter types must not be set in conjunction with fully qualified method name")); - Preconditions.condition(annotation.parameterTypeNames().isEmpty(), - () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, - "parameter type names must not be set in conjunction with fully qualified method name")); - - return DiscoverySelectors.selectMethod(annotation.value()); + return toMethodSelectorFromFQMN(suiteClass, annotation); } Class type = annotation.type() == Class.class ? null : annotation.type(); @@ -480,25 +492,44 @@ () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, "either parameter type names or parameter types must be set but not both")); } + return toMethodSelector(suiteClass, type, typeName, parameterTypes, methodName, parameterTypeNames); + } + + private static MethodSelector toMethodSelectorFromFQMN(Class suiteClass, SelectMethod annotation) { + Preconditions.condition(annotation.type() == Class.class, + () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, + "type must not be set in conjunction with fully qualified method name")); + Preconditions.condition(annotation.typeName().isEmpty(), + () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, + "type name must not be set in conjunction with fully qualified method name")); + Preconditions.condition(annotation.name().isEmpty(), + () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, + "method name must not be set in conjunction with fully qualified method name")); + Preconditions.condition(annotation.parameterTypes().length == 0, + () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, + "parameter types must not be set in conjunction with fully qualified method name")); + Preconditions.condition(annotation.parameterTypeNames().isEmpty(), + () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, + "parameter type names must not be set in conjunction with fully qualified method name")); + + return DiscoverySelectors.selectMethod(annotation.value()); + } + + private static MethodSelector toMethodSelector(Class suiteClass, Class type, String typeName, + Class[] parameterTypes, String methodName, String parameterTypeNames) { if (type == null) { Preconditions.notBlank(typeName, () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, "type must be set or type name must not be blank")); - if (parameterTypes == null) { - return DiscoverySelectors.selectMethod(typeName, methodName, parameterTypeNames); - } - else { - return DiscoverySelectors.selectMethod(typeName, methodName, parameterTypes); - } + return parameterTypes == null // + ? DiscoverySelectors.selectMethod(typeName, methodName, parameterTypeNames) // + : DiscoverySelectors.selectMethod(typeName, methodName, parameterTypes); } else { Preconditions.condition(typeName == null, () -> prefixErrorMessageForInvalidSelectMethodUsage(suiteClass, "either type name or type must be set but not both")); - if (parameterTypes == null) { - return DiscoverySelectors.selectMethod(type, methodName, parameterTypeNames); - } - else { - return DiscoverySelectors.selectMethod(type, methodName, parameterTypes); - } + return parameterTypes == null // + ? DiscoverySelectors.selectMethod(type, methodName, parameterTypeNames) // + : DiscoverySelectors.selectMethod(type, methodName, parameterTypes); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-commons/src/module/org.junit.platform.suite.commons/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/module/org.junit.platform.suite.commons/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-commons/src/module/org.junit.platform.suite.commons/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-commons/src/module/org.junit.platform.suite.commons/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2020 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,8 +8,9 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** - * Common support utilities for declarative test suite executors. + * Common support utilities for declarative test suites. * * @since 1.8 */ diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/ClassSelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/ClassSelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/ClassSelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/ClassSelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,15 +16,19 @@ import java.util.Optional; import java.util.function.Predicate; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.EngineDiscoveryListener; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.UniqueId.Segment; import org.junit.platform.engine.discovery.ClassSelector; import org.junit.platform.engine.discovery.UniqueIdSelector; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.discovery.SelectorResolver; /** @@ -32,19 +36,25 @@ */ final class ClassSelectorResolver implements SelectorResolver { - private static final Logger log = LoggerFactory.getLogger(ClassSelectorResolver.class); - - private static final IsSuiteClass isSuiteClass = new IsSuiteClass(); - + private final IsSuiteClass isSuiteClass; private final Predicate classNameFilter; private final SuiteEngineDescriptor suiteEngineDescriptor; private final ConfigurationParameters configurationParameters; + private final OutputDirectoryCreator outputDirectoryCreator; + private final EngineDiscoveryListener discoveryListener; + private final DiscoveryIssueReporter issueReporter; ClassSelectorResolver(Predicate classNameFilter, SuiteEngineDescriptor suiteEngineDescriptor, - ConfigurationParameters configurationParameters) { + ConfigurationParameters configurationParameters, OutputDirectoryCreator outputDirectoryCreator, + EngineDiscoveryListener discoveryListener, DiscoveryIssueReporter issueReporter) { + + this.isSuiteClass = new IsSuiteClass(issueReporter); this.classNameFilter = classNameFilter; this.suiteEngineDescriptor = suiteEngineDescriptor; this.configurationParameters = configurationParameters; + this.outputDirectoryCreator = outputDirectoryCreator; + this.discoveryListener = discoveryListener; + this.issueReporter = issueReporter; } @Override @@ -89,7 +99,7 @@ } private static Optional> tryLoadSuiteClass(UniqueId.Segment segment) { - return ReflectionUtils.tryToLoadClass(segment.getValue()).toOptional(); + return ReflectionSupport.tryToLoadClass(segment.getValue()).toOptional(); } private static Resolution toResolution(Optional suite) { @@ -99,11 +109,14 @@ private Optional newSuiteDescriptor(Class suiteClass, TestDescriptor parent) { UniqueId id = parent.getUniqueId().append(SuiteTestDescriptor.SEGMENT_TYPE, suiteClass.getName()); if (containsCycle(id)) { - log.config(() -> createConfigContainsCycleMessage(suiteClass, id)); + issueReporter.reportIssue( + DiscoveryIssue.builder(Severity.INFO, createConfigContainsCycleMessage(suiteClass, id)) // + .source(ClassSource.from(suiteClass))); return Optional.empty(); } - return Optional.of(new SuiteTestDescriptor(id, suiteClass, configurationParameters)); + return Optional.of(new SuiteTestDescriptor(id, suiteClass, configurationParameters, outputDirectoryCreator, + discoveryListener, issueReporter)); } private static boolean containsCycle(UniqueId id) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/DiscoverySelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/DiscoverySelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/DiscoverySelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/DiscoverySelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,7 @@ import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver; /** @@ -21,11 +22,14 @@ // @formatter:off private static final EngineDiscoveryRequestResolver resolver = EngineDiscoveryRequestResolver.builder() - .addClassContainerSelectorResolver(new IsSuiteClass()) + .addClassContainerSelectorResolverWithContext(context -> new IsSuiteClass(context.getIssueReporter())) .addSelectorResolver(context -> new ClassSelectorResolver( context.getClassNameFilter(), context.getEngineDescriptor(), - context.getDiscoveryRequest().getConfigurationParameters())) + context.getDiscoveryRequest().getConfigurationParameters(), + context.getDiscoveryRequest().getOutputDirectoryCreator(), + context.getDiscoveryRequest().getDiscoveryListener(), + context.getIssueReporter())) .build(); // @formatter:on @@ -38,7 +42,9 @@ } void resolveSelectors(EngineDiscoveryRequest request, SuiteEngineDescriptor engineDescriptor) { - resolver.resolve(request, engineDescriptor); + DiscoveryIssueReporter issueReporter = DiscoveryIssueReporter.deduplicating( + DiscoveryIssueReporter.forwarding(request.getDiscoveryListener(), engineDescriptor.getUniqueId())); + resolver.resolve(request, engineDescriptor, issueReporter); discoverSuites(engineDescriptor); engineDescriptor.accept(TestDescriptor::prune); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsPotentialTestContainer.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsPotentialTestContainer.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsPotentialTestContainer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsPotentialTestContainer.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.suite.engine; - -import static org.junit.platform.commons.util.ReflectionUtils.isAbstract; -import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; -import static org.junit.platform.commons.util.ReflectionUtils.isPrivate; - -import java.util.function.Predicate; - -/** - * @since 1.8 - */ -final class IsPotentialTestContainer implements Predicate> { - - @Override - public boolean test(Class candidate) { - // Please do not collapse the following into a single statement. - if (isPrivate(candidate)) { - return false; - } - if (isAbstract(candidate)) { - return false; - } - if (candidate.isLocalClass()) { - return false; - } - if (candidate.isAnonymousClass()) { - return false; - } - return !isInnerClass(candidate); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsSuiteClass.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsSuiteClass.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsSuiteClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/IsSuiteClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,9 +10,18 @@ package org.junit.platform.suite.engine; +import static org.junit.platform.commons.support.ModifierSupport.isAbstract; +import static org.junit.platform.commons.support.ModifierSupport.isNotAbstract; +import static org.junit.platform.commons.support.ModifierSupport.isNotPrivate; + import java.util.function.Predicate; import org.junit.platform.commons.support.AnnotationSupport; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter.Condition; import org.junit.platform.suite.api.Suite; /** @@ -20,15 +29,47 @@ */ final class IsSuiteClass implements Predicate> { - private static final IsPotentialTestContainer isPotentialTestContainer = new IsPotentialTestContainer(); + private final Condition> condition; + + IsSuiteClass(DiscoveryIssueReporter issueReporter) { + this.condition = isNotPrivateUnlessAbstract(issueReporter) // + .and(isNotLocal(issueReporter)) // + .and(isNotInner(issueReporter)); + } @Override public boolean test(Class testClass) { - return isPotentialTestContainer.test(testClass) && hasSuiteAnnotation(testClass); + return hasSuiteAnnotation(testClass) // + && condition.check(testClass) // + && isNotAbstract(testClass); } private boolean hasSuiteAnnotation(Class testClass) { return AnnotationSupport.isAnnotated(testClass, Suite.class); } + private static Condition> isNotPrivateUnlessAbstract(DiscoveryIssueReporter issueReporter) { + // Allow abstract test classes to be private because @Suite is inherited and subclasses may widen access. + return issueReporter.createReportingCondition(testClass -> isNotPrivate(testClass) || isAbstract(testClass), + testClass -> createIssue(testClass, "must not be private.")); + } + + private static Condition> isNotLocal(DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(testClass -> !testClass.isLocalClass(), + testClass -> createIssue(testClass, "must not be a local class.")); + } + + private static Condition> isNotInner(DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(testClass -> !ReflectionUtils.isInnerClass(testClass), + testClass -> createIssue(testClass, "must not be an inner class. Did you forget to declare it static?")); + } + + private static DiscoveryIssue createIssue(Class testClass, String detailMessage) { + String message = String.format("@Suite class '%s' %s It will not be executed.", testClass.getName(), + detailMessage); + return DiscoveryIssue.builder(DiscoveryIssue.Severity.WARNING, message) // + .source(ClassSource.from(testClass)) // + .build(); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/LifecycleMethodUtils.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/LifecycleMethodUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/LifecycleMethodUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/LifecycleMethodUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,17 +10,20 @@ package org.junit.platform.suite.engine; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedMethods; -import static org.junit.platform.commons.util.ReflectionUtils.returnsPrimitiveVoid; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedMethods; +import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.List; -import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ModifierSupport; import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode; -import org.junit.platform.engine.support.hierarchical.ThrowableCollector; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.suite.api.AfterSuite; import org.junit.platform.suite.api.BeforeSuite; @@ -35,56 +38,68 @@ /* no-op */ } - static List findBeforeSuiteMethods(Class testClass, ThrowableCollector throwableCollector) { - return findMethodsAndAssertStaticAndNonPrivate(testClass, BeforeSuite.class, HierarchyTraversalMode.TOP_DOWN, - throwableCollector); + static List findBeforeSuiteMethods(Class testClass, DiscoveryIssueReporter issueReporter) { + return findMethodsAndCheckStaticAndNonPrivate(testClass, BeforeSuite.class, HierarchyTraversalMode.TOP_DOWN, + issueReporter); } - static List findAfterSuiteMethods(Class testClass, ThrowableCollector throwableCollector) { - return findMethodsAndAssertStaticAndNonPrivate(testClass, AfterSuite.class, HierarchyTraversalMode.BOTTOM_UP, - throwableCollector); + static List findAfterSuiteMethods(Class testClass, DiscoveryIssueReporter issueReporter) { + return findMethodsAndCheckStaticAndNonPrivate(testClass, AfterSuite.class, HierarchyTraversalMode.BOTTOM_UP, + issueReporter); } - private static List findMethodsAndAssertStaticAndNonPrivate(Class testClass, + private static List findMethodsAndCheckStaticAndNonPrivate(Class testClass, Class annotationType, HierarchyTraversalMode traversalMode, - ThrowableCollector throwableCollector) { + DiscoveryIssueReporter issueReporter) { - List methods = findAnnotatedMethods(testClass, annotationType, traversalMode); - throwableCollector.execute(() -> methods.forEach(method -> { - assertVoid(annotationType, method); - assertStatic(annotationType, method); - assertNonPrivate(annotationType, method); - assertNoParameters(annotationType, method); - })); - return methods; - } - - private static void assertStatic(Class annotationType, Method method) { - if (ReflectionUtils.isNotStatic(method)) { - throw new JUnitException(String.format("@%s method '%s' must be static.", annotationType.getSimpleName(), - method.toGenericString())); - } - } - - private static void assertNonPrivate(Class annotationType, Method method) { - if (ReflectionUtils.isPrivate(method)) { - throw new JUnitException(String.format("@%s method '%s' must not be private.", - annotationType.getSimpleName(), method.toGenericString())); - } - } - - private static void assertVoid(Class annotationType, Method method) { - if (!returnsPrimitiveVoid(method)) { - throw new JUnitException(String.format("@%s method '%s' must not return a value.", - annotationType.getSimpleName(), method.toGenericString())); - } - } - - private static void assertNoParameters(Class annotationType, Method method) { - if (method.getParameterCount() > 0) { - throw new JUnitException(String.format("@%s method '%s' must not accept parameters.", - annotationType.getSimpleName(), method.toGenericString())); - } + return findAnnotatedMethods(testClass, annotationType, traversalMode).stream() // + .filter(// + returnsPrimitiveVoid(annotationType, issueReporter) // + .and(isStatic(annotationType, issueReporter)) // + .and(isNotPrivate(annotationType, issueReporter)) // + .and(hasNoParameters(annotationType, issueReporter)) // + .toPredicate()) // + .collect(toUnmodifiableList()); + } + + private static DiscoveryIssueReporter.Condition isStatic(Class annotationType, + DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ModifierSupport::isStatic, method -> { + String message = String.format("@%s method '%s' must be static.", annotationType.getSimpleName(), + method.toGenericString()); + return createError(message, method); + }); + } + + private static DiscoveryIssueReporter.Condition isNotPrivate(Class annotationType, + DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ModifierSupport::isNotPrivate, method -> { + String message = String.format("@%s method '%s' must not be private.", annotationType.getSimpleName(), + method.toGenericString()); + return createError(message, method); + }); + } + + private static DiscoveryIssueReporter.Condition returnsPrimitiveVoid( + Class annotationType, DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(ReflectionUtils::returnsPrimitiveVoid, method -> { + String message = String.format("@%s method '%s' must not return a value.", annotationType.getSimpleName(), + method.toGenericString()); + return createError(message, method); + }); + } + + private static DiscoveryIssueReporter.Condition hasNoParameters(Class annotationType, + DiscoveryIssueReporter issueReporter) { + return issueReporter.createReportingCondition(method -> method.getParameterCount() == 0, method -> { + String message = String.format("@%s method '%s' must not accept parameters.", + annotationType.getSimpleName(), method.toGenericString()); + return createError(message, method); + }); + } + + private static DiscoveryIssue createError(String message, Method method) { + return DiscoveryIssue.builder(Severity.ERROR, message).source(MethodSource.from(method)).build(); } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/NoTestsDiscoveredException.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/NoTestsDiscoveredException.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/NoTestsDiscoveredException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/NoTestsDiscoveredException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteEngineDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteEngineDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteEngineDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteEngineDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteLauncher.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteLauncher.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteLauncher.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteLauncher.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,9 +19,10 @@ import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.core.EngineDiscoveryOrchestrator; -import org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.Phase; import org.junit.platform.launcher.core.EngineExecutionOrchestrator; import org.junit.platform.launcher.core.LauncherDiscoveryResult; import org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry; @@ -54,13 +55,14 @@ } LauncherDiscoveryResult discover(LauncherDiscoveryRequest discoveryRequest, UniqueId parentId) { - return discoveryOrchestrator.discover(discoveryRequest, Phase.DISCOVERY, parentId); + return discoveryOrchestrator.discover(discoveryRequest, parentId); } TestExecutionSummary execute(LauncherDiscoveryResult discoveryResult, - EngineExecutionListener parentEngineExecutionListener) { + EngineExecutionListener parentEngineExecutionListener, + NamespacedHierarchicalStore requestLevelStore) { SummaryGeneratingListener listener = new SummaryGeneratingListener(); - executionOrchestrator.execute(discoveryResult, parentEngineExecutionListener, listener); + executionOrchestrator.execute(discoveryResult, parentEngineExecutionListener, listener, requestLevelStore); return listener.getSummary(); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,26 +10,39 @@ package org.junit.platform.suite.engine; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static java.util.function.Predicate.isEqual; +import static java.util.stream.Collectors.joining; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; +import static org.junit.platform.commons.util.FunctionUtils.where; import static org.junit.platform.suite.commons.SuiteLauncherDiscoveryRequestBuilder.request; import java.lang.reflect.Method; import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Predicate; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.Preconditions; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.EngineDiscoveryListener; import org.junit.platform.engine.EngineExecutionListener; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.UniqueId.Segment; import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor; import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.hierarchical.OpenTest4JAwareThrowableCollector; import org.junit.platform.engine.support.hierarchical.ThrowableCollector; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; +import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.core.LauncherDiscoveryResult; import org.junit.platform.launcher.listeners.TestExecutionSummary; @@ -53,17 +66,24 @@ private final SuiteLauncherDiscoveryRequestBuilder discoveryRequestBuilder = request(); private final ConfigurationParameters configurationParameters; + private final OutputDirectoryCreator outputDirectoryCreator; private final Boolean failIfNoTests; private final Class suiteClass; + private final LifecycleMethods lifecycleMethods; private LauncherDiscoveryResult launcherDiscoveryResult; private SuiteLauncher launcher; - SuiteTestDescriptor(UniqueId id, Class suiteClass, ConfigurationParameters configurationParameters) { - super(id, getSuiteDisplayName(suiteClass), ClassSource.from(suiteClass)); + SuiteTestDescriptor(UniqueId id, Class suiteClass, ConfigurationParameters configurationParameters, + OutputDirectoryCreator outputDirectoryCreator, EngineDiscoveryListener discoveryListener, + DiscoveryIssueReporter issueReporter) { + super(id, getSuiteDisplayName(suiteClass, issueReporter), ClassSource.from(suiteClass)); this.configurationParameters = configurationParameters; + this.outputDirectoryCreator = outputDirectoryCreator; this.failIfNoTests = getFailIfNoTests(suiteClass); this.suiteClass = suiteClass; + this.lifecycleMethods = new LifecycleMethods(suiteClass, issueReporter); + this.discoveryRequestBuilder.listener(DiscoveryIssueForwardingListener.create(id, discoveryListener)); } private static Boolean getFailIfNoTests(Class suiteClass) { @@ -99,6 +119,7 @@ .enableImplicitConfigurationParameters(false) .parentConfigurationParameters(configurationParameters) .applyConfigurationParametersFromSuite(suiteClass) + .outputDirectoryCreator(outputDirectoryCreator) .build(); // @formatter:on this.launcher = SuiteLauncher.create(); @@ -116,38 +137,45 @@ return Type.CONTAINER; } - private static String getSuiteDisplayName(Class testClass) { + private static String getSuiteDisplayName(Class suiteClass, DiscoveryIssueReporter issueReporter) { // @formatter:off - return findAnnotation(testClass, SuiteDisplayName.class) + Predicate nonBlank = issueReporter.createReportingCondition(StringUtils::isNotBlank, __ -> { + String message = String.format("@SuiteDisplayName on %s must be declared with a non-blank value.", + suiteClass.getName()); + return DiscoveryIssue.builder(DiscoveryIssue.Severity.WARNING, message) + .source(ClassSource.from(suiteClass)) + .build(); + }).toPredicate(); + + return findAnnotation(suiteClass, SuiteDisplayName.class) .map(SuiteDisplayName::value) - .filter(StringUtils::isNotBlank) - .orElse(testClass.getSimpleName()); + .filter(nonBlank) + .orElse(suiteClass.getSimpleName()); // @formatter:on } - void execute(EngineExecutionListener parentEngineExecutionListener) { + void execute(EngineExecutionListener parentEngineExecutionListener, + NamespacedHierarchicalStore requestLevelStore) { parentEngineExecutionListener.executionStarted(this); ThrowableCollector throwableCollector = new OpenTest4JAwareThrowableCollector(); - List beforeSuiteMethods = LifecycleMethodUtils.findBeforeSuiteMethods(suiteClass, throwableCollector); - List afterSuiteMethods = LifecycleMethodUtils.findAfterSuiteMethods(suiteClass, throwableCollector); - - executeBeforeSuiteMethods(beforeSuiteMethods, throwableCollector); + executeBeforeSuiteMethods(throwableCollector); - TestExecutionSummary summary = executeTests(parentEngineExecutionListener, throwableCollector); + TestExecutionSummary summary = executeTests(parentEngineExecutionListener, requestLevelStore, + throwableCollector); - executeAfterSuiteMethods(afterSuiteMethods, throwableCollector); + executeAfterSuiteMethods(throwableCollector); TestExecutionResult testExecutionResult = computeTestExecutionResult(summary, throwableCollector); parentEngineExecutionListener.executionFinished(this, testExecutionResult); } - private void executeBeforeSuiteMethods(List beforeSuiteMethods, ThrowableCollector throwableCollector) { + private void executeBeforeSuiteMethods(ThrowableCollector throwableCollector) { if (throwableCollector.isNotEmpty()) { return; } - for (Method beforeSuiteMethod : beforeSuiteMethods) { - throwableCollector.execute(() -> ReflectionUtils.invokeMethod(beforeSuiteMethod, null)); + for (Method beforeSuiteMethod : lifecycleMethods.beforeSuite) { + throwableCollector.execute(() -> ReflectionSupport.invokeMethod(beforeSuiteMethod, null)); if (throwableCollector.isNotEmpty()) { return; } @@ -155,7 +183,7 @@ } private TestExecutionSummary executeTests(EngineExecutionListener parentEngineExecutionListener, - ThrowableCollector throwableCollector) { + NamespacedHierarchicalStore requestLevelStore, ThrowableCollector throwableCollector) { if (throwableCollector.isNotEmpty()) { return null; } @@ -165,12 +193,12 @@ // be pruned accordingly. LauncherDiscoveryResult discoveryResult = this.launcherDiscoveryResult.withRetainedEngines( getChildren()::contains); - return launcher.execute(discoveryResult, parentEngineExecutionListener); + return launcher.execute(discoveryResult, parentEngineExecutionListener, requestLevelStore); } - private void executeAfterSuiteMethods(List afterSuiteMethods, ThrowableCollector throwableCollector) { - for (Method afterSuiteMethod : afterSuiteMethods) { - throwableCollector.execute(() -> ReflectionUtils.invokeMethod(afterSuiteMethod, null)); + private void executeAfterSuiteMethods(ThrowableCollector throwableCollector) { + for (Method afterSuiteMethod : lifecycleMethods.afterSuite) { + throwableCollector.execute(() -> ReflectionSupport.invokeMethod(afterSuiteMethod, null)); } } @@ -193,4 +221,56 @@ return true; } + private static class LifecycleMethods { + + final List beforeSuite; + final List afterSuite; + + LifecycleMethods(Class suiteClass, DiscoveryIssueReporter issueReporter) { + beforeSuite = LifecycleMethodUtils.findBeforeSuiteMethods(suiteClass, issueReporter); + afterSuite = LifecycleMethodUtils.findAfterSuiteMethods(suiteClass, issueReporter); + } + } + + private static class DiscoveryIssueForwardingListener implements LauncherDiscoveryListener { + + private static final Predicate SUITE_SEGMENTS = where(Segment::getType, isEqual(SEGMENT_TYPE)); + + static DiscoveryIssueForwardingListener create(UniqueId id, EngineDiscoveryListener discoveryListener) { + boolean isNestedSuite = id.getSegments().stream().filter(SUITE_SEGMENTS).count() > 1; + if (isNestedSuite) { + return new DiscoveryIssueForwardingListener(discoveryListener, (__, issue) -> issue); + } + return new DiscoveryIssueForwardingListener(discoveryListener, + (engineUniqueId, issue) -> issue.withMessage(message -> { + String engineId = engineUniqueId.getLastSegment().getValue(); + if (SuiteEngineDescriptor.ENGINE_ID.equals(engineId)) { + return message; + } + String suitePath = engineUniqueId.getSegments().stream() // + .filter(SUITE_SEGMENTS) // + .map(Segment::getValue) // + .collect(joining(" > ")); + if (message.endsWith(".")) { + message = message.substring(0, message.length() - 1); + } + return String.format("[%s] %s (via @Suite %s).", engineId, message, suitePath); + })); + } + + private final EngineDiscoveryListener discoveryListener; + private final BiFunction issueTransformer; + + private DiscoveryIssueForwardingListener(EngineDiscoveryListener discoveryListener, + BiFunction issueTransformer) { + this.discoveryListener = discoveryListener; + this.issueTransformer = issueTransformer; + } + + @Override + public void issueEncountered(UniqueId engineUniqueId, DiscoveryIssue issue) { + DiscoveryIssue transformedIssue = this.issueTransformer.apply(engineUniqueId, issue); + this.discoveryListener.issueEncountered(engineUniqueId, transformedIssue); + } + } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestEngine.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestEngine.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestEngine.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestEngine.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -22,6 +22,8 @@ import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; /** * The JUnit Platform Suite {@link org.junit.platform.engine.TestEngine TestEngine}. @@ -63,6 +65,7 @@ public void execute(ExecutionRequest request) { SuiteEngineDescriptor suiteEngineDescriptor = (SuiteEngineDescriptor) request.getRootTestDescriptor(); EngineExecutionListener engineExecutionListener = request.getEngineExecutionListener(); + NamespacedHierarchicalStore requestLevelStore = request.getStore(); engineExecutionListener.executionStarted(suiteEngineDescriptor); @@ -70,7 +73,7 @@ suiteEngineDescriptor.getChildren() .stream() .map(SuiteTestDescriptor.class::cast) - .forEach(suiteTestDescriptor -> suiteTestDescriptor.execute(engineExecutionListener)); + .forEach(suiteTestDescriptor -> suiteTestDescriptor.execute(engineExecutionListener, requestLevelStore)); // @formatter:on engineExecutionListener.executionFinished(suiteEngineDescriptor, TestExecutionResult.successful()); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/module/org.junit.platform.suite.engine/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/module/org.junit.platform.suite.engine/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-suite-engine/src/module/org.junit.platform.suite.engine/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-suite-engine/src/module/org.junit.platform.suite.engine/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2020 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,8 +8,9 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** - * Provides a {@linkplain org.junit.platform.engine.TestEngine} for running + * Provides a {@link org.junit.platform.engine.TestEngine} for running * declarative test suites. * * @since 1.8 diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Assertions.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Assertions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Assertions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Assertions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineDiscoveryResults.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineDiscoveryResults.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineDiscoveryResults.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineDiscoveryResults.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.testkit.engine; + +import static java.util.Collections.unmodifiableList; +import static org.apiguardian.api.API.Status.MAINTAINED; + +import java.util.List; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.Preconditions; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.TestDescriptor; + +/** + * {@code EngineDiscoveryResults} represents the results of test discovery + * by a {@link org.junit.platform.engine.TestEngine TestEngine} on the JUnit + * Platform and provides access to the {@link TestDescriptor} of the engine + * and any {@link DiscoveryIssue DiscoveryIssues} that were encountered. + * + * @since 1.13 + */ +@API(status = MAINTAINED, since = "1.13.3") +public class EngineDiscoveryResults { + + private final TestDescriptor engineDescriptor; + private final List discoveryIssues; + + EngineDiscoveryResults(TestDescriptor engineDescriptor, List discoveryIssues) { + this.engineDescriptor = Preconditions.notNull(engineDescriptor, "Engine descriptor must not be null"); + this.discoveryIssues = unmodifiableList( + Preconditions.notNull(discoveryIssues, "Discovery issues list must not be null")); + Preconditions.containsNoNullElements(discoveryIssues, "Discovery issues list must not contain null elements"); + } + + /** + * {@return the root {@link TestDescriptor} of the engine} + */ + public TestDescriptor getEngineDescriptor() { + return engineDescriptor; + } + + /** + * {@return the issues that were encountered during discovery} + */ + public List getDiscoveryIssues() { + return discoveryIssues; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineExecutionResults.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineExecutionResults.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineExecutionResults.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineExecutionResults.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineTestKit.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineTestKit.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineTestKit.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EngineTestKit.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,25 +15,33 @@ import static org.apiguardian.api.API.Status.DEPRECATED; import static org.apiguardian.api.API.Status.MAINTAINED; import static org.apiguardian.api.API.Status.STABLE; -import static org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.Phase.EXECUTION; +import static org.junit.platform.engine.support.store.NamespacedHierarchicalStore.CloseAction.closeAutoCloseables; +import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.ServiceLoader; +import java.util.function.Consumer; import java.util.stream.Stream; import org.apiguardian.api.API; +import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.CollectionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.DiscoveryFilter; +import org.junit.platform.engine.DiscoveryIssue; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.ExecutionRequest; import org.junit.platform.engine.Filter; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.core.EngineDiscoveryOrchestrator; import org.junit.platform.launcher.core.EngineExecutionOrchestrator; @@ -42,15 +50,24 @@ import org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry; /** - * {@code EngineTestKit} provides support for executing a test plan for a given - * {@link TestEngine} and then accessing the results via - * {@linkplain EngineExecutionResults a fluent API} to verify the expected results. + * {@code EngineTestKit} provides support for discovering and executing tests + * for a given {@link TestEngine} and provides convenient access to the results. + * + *

    For discovery, {@link EngineDiscoveryResults} provides access to + * the {@link TestDescriptor} of the engine and any {@link DiscoveryIssue + * DiscoveryIssues} that were encountered. + * + *

    For execution, {@link EngineExecutionResults} provides a fluent + * API to verify the expected results. * * @since 1.4 * @see #engine(String) * @see #engine(TestEngine) + * @see #discover(String, LauncherDiscoveryRequest) + * @see #discover(TestEngine, LauncherDiscoveryRequest) * @see #execute(String, LauncherDiscoveryRequest) * @see #execute(TestEngine, LauncherDiscoveryRequest) + * @see EngineDiscoveryResults * @see EngineExecutionResults */ @API(status = MAINTAINED, since = "1.7") @@ -118,6 +135,65 @@ } /** + * Discover tests for the given {@link LauncherDiscoveryRequest} using the + * {@link TestEngine} with the supplied ID. + * + *

    The {@code TestEngine} will be loaded via Java's {@link ServiceLoader} + * mechanism, analogous to the manner in which test engines are loaded in + * the JUnit Platform Launcher API. + * + *

    {@link org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder} + * provides a convenient way to build an appropriate discovery request to + * supply to this method. As an alternative, consider using + * {@link #engine(TestEngine)} for a more fluent API. + * + * @param engineId the ID of the {@code TestEngine} to use; must not be + * {@code null} or blank + * @param discoveryRequest the {@code LauncherDiscoveryRequest} to use + * @return the results of the discovery + * @throws PreconditionViolationException for invalid arguments or if the + * {@code TestEngine} with the supplied ID cannot be loaded + * @since 1.13 + * @see #discover(TestEngine, LauncherDiscoveryRequest) + * @see #engine(String) + * @see #engine(TestEngine) + */ + @API(status = MAINTAINED, since = "1.13.3") + public static EngineDiscoveryResults discover(String engineId, LauncherDiscoveryRequest discoveryRequest) { + Preconditions.notBlank(engineId, "TestEngine ID must not be null or blank"); + return discover(loadTestEngine(engineId.trim()), discoveryRequest); + } + + /** + * Discover tests for the given {@link LauncherDiscoveryRequest} using the + * supplied {@link TestEngine}. + * + *

    {@link org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder} + * provides a convenient way to build an appropriate discovery request to + * supply to this method. As an alternative, consider using + * {@link #engine(TestEngine)} for a more fluent API. + * + * @param testEngine the {@code TestEngine} to use; must not be {@code null} + * @param discoveryRequest the {@code EngineDiscoveryResults} to use; must + * not be {@code null} + * @return the recorded {@code EngineExecutionResults} + * @throws PreconditionViolationException for invalid arguments + * @since 1.13 + * @see #discover(String, LauncherDiscoveryRequest) + * @see #engine(String) + * @see #engine(TestEngine) + */ + @API(status = MAINTAINED, since = "1.13.3") + public static EngineDiscoveryResults discover(TestEngine testEngine, LauncherDiscoveryRequest discoveryRequest) { + Preconditions.notNull(testEngine, "TestEngine must not be null"); + Preconditions.notNull(discoveryRequest, "EngineDiscoveryRequest must not be null"); + LauncherDiscoveryResult discoveryResult = discoverUsingOrchestrator(testEngine, discoveryRequest); + TestDescriptor engineDescriptor = discoveryResult.getEngineTestDescriptor(testEngine); + List discoveryIssues = discoveryResult.getDiscoveryIssues(testEngine); + return new EngineDiscoveryResults(engineDescriptor, discoveryIssues); + } + + /** * Execute tests for the given {@link EngineDiscoveryRequest} using the * {@link TestEngine} with the supplied ID. * @@ -249,18 +325,36 @@ EngineExecutionListener listener) { UniqueId engineUniqueId = UniqueId.forEngine(testEngine.getId()); TestDescriptor engineTestDescriptor = testEngine.discover(discoveryRequest, engineUniqueId); - ExecutionRequest request = new ExecutionRequest(engineTestDescriptor, listener, - discoveryRequest.getConfigurationParameters()); - testEngine.execute(request); + withRequestLevelStore(store -> { + ExecutionRequest request = ExecutionRequest.create(engineTestDescriptor, listener, + discoveryRequest.getConfigurationParameters(), discoveryRequest.getOutputDirectoryCreator(), store); + testEngine.execute(request); + }); } private static void executeUsingLauncherOrchestration(TestEngine testEngine, LauncherDiscoveryRequest discoveryRequest, EngineExecutionListener listener) { - LauncherDiscoveryResult discoveryResult = new EngineDiscoveryOrchestrator(singleton(testEngine), - emptySet()).discover(discoveryRequest, EXECUTION); + LauncherDiscoveryResult discoveryResult = discoverUsingOrchestrator(testEngine, discoveryRequest); TestDescriptor engineTestDescriptor = discoveryResult.getEngineTestDescriptor(testEngine); Preconditions.notNull(engineTestDescriptor, "TestEngine did not yield a TestDescriptor"); - new EngineExecutionOrchestrator().execute(discoveryResult, listener); + withRequestLevelStore(store -> new EngineExecutionOrchestrator().execute(discoveryResult, listener, store)); + } + + private static void withRequestLevelStore(Consumer> action) { + try (NamespacedHierarchicalStore sessionLevelStore = newStore(null); + NamespacedHierarchicalStore requestLevelStore = newStore(sessionLevelStore)) { + action.accept(requestLevelStore); + } + } + + private static NamespacedHierarchicalStore newStore(NamespacedHierarchicalStore parentStore) { + return new NamespacedHierarchicalStore<>(parentStore, closeAutoCloseables()); + } + + private static LauncherDiscoveryResult discoverUsingOrchestrator(TestEngine testEngine, + LauncherDiscoveryRequest discoveryRequest) { + return new EngineDiscoveryOrchestrator(singleton(testEngine), emptySet()) // + .discover(discoveryRequest); } @SuppressWarnings("unchecked") @@ -295,7 +389,8 @@ public static final class Builder { private final LauncherDiscoveryRequestBuilder requestBuilder = LauncherDiscoveryRequestBuilder.request() // - .enableImplicitConfigurationParameters(false); + .enableImplicitConfigurationParameters(false) // + .outputDirectoryCreator(DisabledOutputDirectoryCreator.INSTANCE); private final TestEngine testEngine; private Builder(TestEngine testEngine) { @@ -423,6 +518,69 @@ } /** + * Set the + * {@link org.junit.platform.engine.reporting.OutputDirectoryProvider} + * to use. + * + *

    If not specified, a default provider will be used that throws an + * exception when attempting to create output directories. This is done + * to avoid accidentally writing output files to the file system. + * + * @param outputDirectoryProvider the output directory provider to use; + * never {@code null} + * @return this builder for method chaining + * @since 1.12 + * @see org.junit.platform.engine.reporting.OutputDirectoryProvider + * @deprecated Please use + * {@link #outputDirectoryCreator(OutputDirectoryCreator)} instead + */ + @Deprecated + @API(status = DEPRECATED, since = "1.14") + public Builder outputDirectoryProvider( + org.junit.platform.engine.reporting.OutputDirectoryProvider outputDirectoryProvider) { + return outputDirectoryCreator(outputDirectoryProvider); + } + + /** + * Set the {@link OutputDirectoryCreator} to use. + * + *

    If not specified, a default implementation will be used that + * throws an exception when attempting to create output directories. + * This is done to avoid accidentally writing output files to the file + * system. + * + * @param outputDirectoryCreator the output directory creator to use; + * never {@code null} + * @return this builder for method chaining + * @since 1.12 + * @see OutputDirectoryCreator + */ + @API(status = MAINTAINED, since = "1.14") + public Builder outputDirectoryCreator(OutputDirectoryCreator outputDirectoryCreator) { + this.requestBuilder.outputDirectoryCreator(outputDirectoryCreator); + return this; + } + + /** + * Discover tests for the configured {@link TestEngine}, + * {@linkplain DiscoverySelector discovery selectors}, + * {@linkplain DiscoveryFilter discovery filters}, and + * configuration parameters. + * + * @return the recorded {@code EngineDiscoveryResults} + * @since 1.13 + * @see #selectors(DiscoverySelector...) + * @see #filters(Filter...) + * @see #configurationParameter(String, String) + * @see #configurationParameters(Map) + */ + @API(status = MAINTAINED, since = "1.13.3") + public EngineDiscoveryResults discover() { + LauncherDiscoveryRequest request = this.requestBuilder.build(); + return EngineTestKit.discover(this.testEngine, request); + } + + /** * Execute tests for the configured {@link TestEngine}, * {@linkplain DiscoverySelector discovery selectors}, * {@linkplain DiscoveryFilter discovery filters}, and @@ -441,6 +599,27 @@ return executionRecorder.getExecutionResults(); } + private static class DisabledOutputDirectoryCreator implements OutputDirectoryCreator { + + public static final OutputDirectoryCreator INSTANCE = new DisabledOutputDirectoryCreator(); + + private static final String FAILURE_MESSAGE = "Writing outputs is disabled by default when using EngineTestKit. " + + "To enable, configure a custom OutputDirectoryCreator via EngineTestKit#outputDirectoryCreator."; + + private DisabledOutputDirectoryCreator() { + } + + @Override + public Path getRootDirectory() { + throw new JUnitException(FAILURE_MESSAGE); + } + + @Override + public Path createOutputDirectory(TestDescriptor testDescriptor) { + throw new JUnitException(FAILURE_MESSAGE); + } + + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Event.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Event.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Event.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Event.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -22,6 +22,7 @@ import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; /** @@ -52,6 +53,23 @@ } /** + * Create an {@code Event} for a published file for the supplied + * {@link TestDescriptor} and {@link FileEntry}. + * + * @param testDescriptor the {@code TestDescriptor} associated with the event; + * never {@code null} + * @param file the {@code FileEntry} that was published; never {@code null} + * @return the newly created {@code Event} + * @since 1.12 + * @see EventType#FILE_ENTRY_PUBLISHED + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Event fileEntryPublished(TestDescriptor testDescriptor, FileEntry file) { + Preconditions.notNull(file, "FileEntry must not be null"); + return new Event(EventType.FILE_ENTRY_PUBLISHED, testDescriptor, file); + } + + /** * Create an {@code Event} for the dynamic registration of the * supplied {@link TestDescriptor}. * @@ -82,8 +100,8 @@ * Create a started {@code Event} for the supplied * {@link TestDescriptor}. * - * @param testDescriptor the {@code TestDescriptor} associated with the - * event; never {@code null} + * @param testDescriptor the {@code TestDescriptor} associated with the event; + * never {@code null} * @return the newly created {@code Event} * @see EventType#STARTED */ @@ -95,8 +113,8 @@ * Create a finished {@code Event} for the supplied * {@link TestDescriptor} and {@link TestExecutionResult}. * - * @param testDescriptor the {@code TestDescriptor} associated with the - * event; never {@code null} + * @param testDescriptor the {@code TestDescriptor} associated with the event; + * never {@code null} * @param result the {@code TestExecutionResult} for the supplied * {@code TestDescriptor}; never {@code null} * @return the newly created {@code Event} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventConditions.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventConditions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventConditions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventConditions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -42,6 +42,7 @@ import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.TestExecutionResult.Status; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.descriptor.EngineDescriptor; @@ -249,6 +250,32 @@ /** * Create a new {@link Condition} that matches if and only if the + * {@linkplain TestDescriptor#getUniqueId() unique id} of an {@link Event}'s + * {@linkplain Event#getTestDescriptor() test descriptor} is equal to the + * {@link UniqueId} parsed from the supplied {@link String}. + * + * @since 1.13 + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Condition uniqueId(String uniqueId) { + return uniqueId(UniqueId.parse(uniqueId)); + } + + /** + * Create a new {@link Condition} that matches if and only if the + * {@linkplain TestDescriptor#getUniqueId() unique id} of an {@link Event}'s + * {@linkplain Event#getTestDescriptor() test descriptor} is equal to the + * supplied {@link UniqueId}. + * + * @since 1.13 + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Condition uniqueId(UniqueId uniqueId) { + return uniqueId(new Condition<>(isEqual(uniqueId), "equal to '%s'", uniqueId)); + } + + /** + * Create a new {@link Condition} that matches if and only if the * {@linkplain TestDescriptor#getUniqueId() unique id} of an * {@link Event}'s {@linkplain Event#getTestDescriptor() test descriptor} * contains the supplied {@link String}. @@ -258,11 +285,22 @@ String text = segment.getType() + ":" + segment.getValue(); return text.contains(uniqueIdSubstring); }; + return uniqueId(new Condition<>(uniqueId -> uniqueId.getSegments().stream().anyMatch(predicate), + "substring '%s'", uniqueIdSubstring)); + } - return new Condition<>( - byTestDescriptor( - where(TestDescriptor::getUniqueId, uniqueId -> uniqueId.getSegments().stream().anyMatch(predicate))), - "descriptor with uniqueId substring '%s'", uniqueIdSubstring); + /** + * Create a new {@link Condition} that matches if and only if the + * {@linkplain TestDescriptor#getUniqueId() unique id} of an {@link Event}'s + * {@linkplain Event#getTestDescriptor() test descriptor} matches the + * supplied {@link Condition}. + * + * @since 1.13 + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Condition uniqueId(Condition condition) { + return new Condition<>(byTestDescriptor(where(TestDescriptor::getUniqueId, condition::matches)), + "descriptor with uniqueId %s", condition.description().value()); } /** @@ -314,6 +352,21 @@ } /** + * Create a new {@link Condition} that matches if and only if the + * {@linkplain TestDescriptor#getLegacyReportingName()} () legacy reporting name} + * of an {@link Event}'s {@linkplain Event#getTestDescriptor() test descriptor} + * is equal to the supplied {@link String}. + * + * @since 1.13 + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Condition legacyReportingName(String legacyReportingName) { + return new Condition<>( + byTestDescriptor(where(TestDescriptor::getLegacyReportingName, isEqual(legacyReportingName))), + "descriptor with legacy reporting name '%s'", legacyReportingName); + } + + /** * Create a new {@link Condition} that matches if and only if an * {@link Event}'s {@linkplain Event#getType() type} is * {@link EventType#SKIPPED} and the @@ -470,4 +523,17 @@ "event for report entry with key-value pairs %s", keyValuePairs); } + /** + * Create a new {@link Condition} that matches if and only if an + * {@link Event}'s {@linkplain Event#getPayload() payload} is an instance of + * {@link FileEntry} that contains a file that matches the supplied + * {@link Predicate}. + * + * @since 1.12 + */ + @API(status = MAINTAINED, since = "1.13.3") + public static Condition fileEntry(Predicate predicate) { + return new Condition<>(byPayload(FileEntry.class, predicate), "event for file entry with custom predicate"); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventStatistics.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventStatistics.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventStatistics.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventStatistics.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -127,6 +127,20 @@ return this; } + /** + * Specify the number of expected file entry publication events. + * + * @param expected the expected number of events + * @return this {@code EventStatistics} for method chaining + * @since 1.12 + */ + @API(status = MAINTAINED, since = "1.13.3") + public EventStatistics fileEntryPublished(long expected) { + this.executables.add( + () -> assertEquals(expected, this.events.fileEntryPublished().count(), "file entry published")); + return this; + } + /** * Specify the number of expected dynamic registration events. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventType.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventType.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventType.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/EventType.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,6 +15,7 @@ import org.apiguardian.api.API; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; /** @@ -60,6 +61,15 @@ * * @see org.junit.platform.engine.EngineExecutionListener#reportingEntryPublished(TestDescriptor, ReportEntry) */ - REPORTING_ENTRY_PUBLISHED + REPORTING_ENTRY_PUBLISHED, + + /** + * Signals that a {@link TestDescriptor} published a file entry. + * + * @since 1.12 + * @see org.junit.platform.engine.EngineExecutionListener#fileEntryPublished(TestDescriptor, FileEntry) + */ + @API(status = MAINTAINED, since = "1.13.3") + FILE_ENTRY_PUBLISHED } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Events.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Events.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Events.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Events.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -208,6 +208,18 @@ } /** + * Get the file entry publication {@link Events} contained in this + * {@code Events} object. + * + * @return the filtered {@code Events}; never {@code null} + * @since 1.12 + */ + @API(status = MAINTAINED, since = "1.13.3") + public Events fileEntryPublished() { + return new Events(eventsByType(EventType.FILE_ENTRY_PUBLISHED), this.category + " File Entry Published"); + } + + /** * Get the dynamic registration {@link Events} contained in this * {@code Events} object. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Execution.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Execution.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Execution.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Execution.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/ExecutionRecorder.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/ExecutionRecorder.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/ExecutionRecorder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/ExecutionRecorder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,6 +19,7 @@ import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; /** @@ -83,6 +84,17 @@ } /** + * Record an {@link Event} for a published {@link FileEntry}. + * + * @since 1.12 + */ + @API(status = MAINTAINED, since = "1.13.3") + @Override + public void fileEntryPublished(TestDescriptor testDescriptor, FileEntry file) { + this.events.add(Event.fileEntryPublished(testDescriptor, file)); + } + + /** * Get the state of the engine's execution in the form of {@link EngineExecutionResults}. * * @return the {@code EngineExecutionResults} containing all current state information diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Executions.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Executions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Executions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/Executions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TerminationInfo.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TerminationInfo.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TerminationInfo.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TerminationInfo.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TestExecutionResultConditions.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TestExecutionResultConditions.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TestExecutionResultConditions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/main/java/org/junit/platform/testkit/engine/TestExecutionResultConditions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,7 +12,6 @@ import static java.util.function.Predicate.isEqual; import static java.util.stream.Collectors.toList; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.MAINTAINED; import static org.junit.platform.commons.util.FunctionUtils.where; @@ -95,7 +94,7 @@ * @see #cause(Condition...) * @see #suppressed(int, Condition...) */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = MAINTAINED, since = "1.13.3") @SafeVarargs @SuppressWarnings("varargs") public static Condition rootCause(Condition... conditions) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/module/org.junit.platform.testkit/module-info.java jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/module/org.junit.platform.testkit/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-platform-testkit/src/module/org.junit.platform.testkit/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-platform-testkit/src/module/org.junit.platform.testkit/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** * Defines the Test Kit API for the JUnit Platform. * diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/junit-vintage-engine.gradle.kts jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/junit-vintage-engine.gradle.kts --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/junit-vintage-engine.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/junit-vintage-engine.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -22,7 +22,10 @@ testImplementation(projects.junitPlatformLauncher) testImplementation(projects.junitPlatformSuiteEngine) testImplementation(projects.junitPlatformTestkit) + testImplementation(testFixtures(projects.junitPlatformCommons)) testImplementation(testFixtures(projects.junitJupiterApi)) + testImplementation(testFixtures(projects.junitPlatformLauncher)) + testImplementation(testFixtures(projects.junitPlatformReporting)) osgiVerification(projects.junitPlatformLauncher) } @@ -88,3 +91,10 @@ dependsOn(testWithoutJUnit4) } } + +eclipse { + classpath { + // Avoid exposing test resources to dependent projects + containsTestFixtures = false + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/Constants.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/Constants.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/Constants.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/Constants.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.vintage.engine; + +import static org.apiguardian.api.API.Status.MAINTAINED; +import static org.apiguardian.api.API.Status.STABLE; + +import org.apiguardian.api.API; + +/** + * Collection of constants related to the {@link VintageTestEngine}. + * + * @since 5.12 + */ +@API(status = STABLE, since = "5.12") +public final class Constants { + + /** + * Indicates whether parallel execution is enabled for the JUnit Vintage engine. + * + *

    Set this property to {@code true} to enable parallel execution of tests. + * Defaults to {@code false}. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String PARALLEL_EXECUTION_ENABLED = "junit.vintage.execution.parallel.enabled"; + + /** + * Specifies the size of the thread pool to be used for parallel execution. + * + *

    Set this property to an integer value to specify the number of threads + * to be used for parallel execution. Defaults to the number of available + * processors. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String PARALLEL_POOL_SIZE = "junit.vintage.execution.parallel.pool-size"; + + /** + * Indicates whether parallel execution is enabled for test classes in the + * JUnit Vintage engine. + * + *

    Set this property to {@code true} to enable parallel execution of test + * classes. Defaults to {@code false}. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String PARALLEL_CLASS_EXECUTION = "junit.vintage.execution.parallel.classes"; + + /** + * Indicates whether parallel execution is enabled for test methods in the + * JUnit Vintage engine. + * + *

    Set this property to {@code true} to enable parallel execution of test + * methods. Defaults to {@code false}. + * + * @since 5.12 + */ + @API(status = MAINTAINED, since = "5.13.3") + public static final String PARALLEL_METHOD_EXECUTION = "junit.vintage.execution.parallel.methods"; + + private Constants() { + /* no-op */ + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/JUnit4VersionCheck.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/JUnit4VersionCheck.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/JUnit4VersionCheck.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/JUnit4VersionCheck.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/VintageTestEngine.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/VintageTestEngine.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/VintageTestEngine.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/VintageTestEngine.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,7 +14,6 @@ import static org.junit.platform.engine.TestExecutionResult.successful; import static org.junit.vintage.engine.descriptor.VintageTestDescriptor.ENGINE_ID; -import java.util.Iterator; import java.util.Optional; import org.apiguardian.api.API; @@ -24,10 +23,9 @@ import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; -import org.junit.vintage.engine.descriptor.RunnerTestDescriptor; import org.junit.vintage.engine.descriptor.VintageEngineDescriptor; import org.junit.vintage.engine.discovery.VintageDiscoverer; -import org.junit.vintage.engine.execution.RunnerExecutor; +import org.junit.vintage.engine.execution.VintageExecutor; /** * The JUnit Vintage {@link TestEngine}. @@ -69,17 +67,7 @@ EngineExecutionListener engineExecutionListener = request.getEngineExecutionListener(); VintageEngineDescriptor engineDescriptor = (VintageEngineDescriptor) request.getRootTestDescriptor(); engineExecutionListener.executionStarted(engineDescriptor); - executeAllChildren(engineDescriptor, engineExecutionListener); + new VintageExecutor(engineDescriptor, engineExecutionListener, request).executeAllChildren(); engineExecutionListener.executionFinished(engineDescriptor, successful()); } - - private void executeAllChildren(VintageEngineDescriptor engineDescriptor, - EngineExecutionListener engineExecutionListener) { - RunnerExecutor runnerExecutor = new RunnerExecutor(engineExecutionListener); - for (Iterator iterator = engineDescriptor.getModifiableChildren().iterator(); iterator.hasNext();) { - runnerExecutor.execute((RunnerTestDescriptor) iterator.next()); - iterator.remove(); - } - } - } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/DescriptionUtils.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/DescriptionUtils.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/DescriptionUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/DescriptionUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/OrFilter.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/OrFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/OrFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/OrFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerDecorator.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerDecorator.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerDecorator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerDecorator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerRequest.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerRequest.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerRequest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerRequest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,6 +18,11 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import org.apiguardian.api.API; @@ -26,12 +31,16 @@ import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.hierarchical.OpenTest4JAwareThrowableCollector; +import org.junit.platform.engine.support.hierarchical.ThrowableCollector; import org.junit.runner.Description; import org.junit.runner.Request; import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.Filterable; import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runners.ParentRunner; +import org.junit.runners.model.RunnerScheduler; /** * @since 4.12 @@ -161,6 +170,47 @@ return ignored; } + public void setExecutorService(ExecutorService executorService) { + Runner runner = getRunnerToReport(); + if (runner instanceof ParentRunner) { + ((ParentRunner) runner).setScheduler(new RunnerScheduler() { + + private final List> futures = new CopyOnWriteArrayList<>(); + + @Override + public void schedule(Runnable childStatement) { + futures.add(executorService.submit(childStatement)); + } + + @Override + public void finished() { + ThrowableCollector collector = new OpenTest4JAwareThrowableCollector(); + AtomicBoolean wasInterrupted = new AtomicBoolean(false); + for (Future future : futures) { + collector.execute(() -> { + // We're calling `Future.get()` individually to allow for work stealing + // in case `ExecutorService` is a `ForkJoinPool` + try { + future.get(); + } + catch (ExecutionException e) { + throw e.getCause(); + } + catch (InterruptedException e) { + wasInterrupted.set(true); + } + }); + } + collector.assertEmpty(); + if (wasInterrupted.get()) { + logger.warn(() -> "Interrupted while waiting for runner to finish"); + Thread.currentThread().interrupt(); + } + } + }); + } + } + private static class ExcludeDescriptionFilter extends Filter { private final Description description; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/TestSourceProvider.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/TestSourceProvider.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/TestSourceProvider.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/TestSourceProvider.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,8 +14,9 @@ import static java.util.function.Predicate.isEqual; import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN; +import static org.junit.platform.commons.support.ReflectionSupport.findMethods; import static org.junit.platform.commons.util.FunctionUtils.where; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; import java.lang.reflect.Method; import java.util.List; @@ -72,7 +73,8 @@ } private Method findMethod(Class testClass, String methodName) { - List methods = methodsCache.computeIfAbsent(testClass, clazz -> findMethods(clazz, m -> true)).stream() // + List methods = methodsCache.computeIfAbsent(testClass, + clazz -> findMethods(clazz, m -> true, TOP_DOWN)).stream() // .filter(where(Method::getName, isEqual(methodName))) // .collect(toList()); if (methods.isEmpty()) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageEngineDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageEngineDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageEngineDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageEngineDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageTestDescriptor.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/VintageTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,8 +17,8 @@ import java.util.Optional; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.util.ClassFilter; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.support.scanning.ClassFilter; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.UniqueId.Segment; @@ -43,7 +43,10 @@ @Override public Resolution resolve(ClassSelector selector, Context context) { - return resolveTestClass(selector.getJavaClass(), context); + if (classFilter.match(selector.getClassName())) { + return resolveTestClassThatPassedNameFilter(selector.getJavaClass(), context); + } + return unresolved(); } @Override @@ -51,15 +54,17 @@ Segment lastSegment = selector.getUniqueId().getLastSegment(); if (SEGMENT_TYPE_RUNNER.equals(lastSegment.getType())) { String testClassName = lastSegment.getValue(); - Class testClass = ReflectionUtils.tryToLoadClass(testClassName)// - .getOrThrow(cause -> new JUnitException("Unknown class: " + testClassName, cause)); - return resolveTestClass(testClass, context); + if (classFilter.match(testClassName)) { + Class testClass = ReflectionSupport.tryToLoadClass(testClassName)// + .getOrThrow(cause -> new JUnitException("Unknown class: " + testClassName, cause)); + return resolveTestClassThatPassedNameFilter(testClass, context); + } } return unresolved(); } - private Resolution resolveTestClass(Class testClass, Context context) { - if (!classFilter.test(testClass)) { + private Resolution resolveTestClassThatPassedNameFilter(Class testClass, Context context) { + if (!classFilter.match(testClass)) { return unresolved(); } Runner runner = RUNNER_BUILDER.safeRunnerForClass(testClass); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/FilterableIgnoringRunnerDecorator.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/FilterableIgnoringRunnerDecorator.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/FilterableIgnoringRunnerDecorator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/FilterableIgnoringRunnerDecorator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IgnoringRunnerDecorator.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IgnoringRunnerDecorator.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IgnoringRunnerDecorator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IgnoringRunnerDecorator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,9 +11,9 @@ package org.junit.vintage.engine.discovery; import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.ReflectionUtils.isAbstract; +import static org.junit.platform.commons.support.ModifierSupport.isAbstract; +import static org.junit.platform.commons.support.ModifierSupport.isPublic; import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass; -import static org.junit.platform.commons.util.ReflectionUtils.isPublic; import java.util.function.Predicate; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestMethod.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/MethodSelectorResolver.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/MethodSelectorResolver.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/MethodSelectorResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/MethodSelectorResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessor.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessor.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/UniqueIdFilter.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/UniqueIdFilter.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/UniqueIdFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/UniqueIdFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/VintageDiscoverer.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/VintageDiscoverer.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/VintageDiscoverer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/VintageDiscoverer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import static org.apiguardian.api.API.Status.INTERNAL; import org.apiguardian.api.API; -import org.junit.platform.commons.util.ClassFilter; +import org.junit.platform.commons.support.scanning.ClassFilter; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/EventType.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/EventType.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/EventType.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/EventType.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunnerExecutor.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunnerExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunnerExecutor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunnerExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/TestRun.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/TestRun.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/TestRun.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/TestRun.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/VintageExecutor.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/VintageExecutor.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/VintageExecutor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/VintageExecutor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,190 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.vintage.engine.execution; + +import static java.util.stream.Collectors.toList; +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.junit.vintage.engine.Constants.PARALLEL_CLASS_EXECUTION; +import static org.junit.vintage.engine.Constants.PARALLEL_EXECUTION_ENABLED; +import static org.junit.vintage.engine.Constants.PARALLEL_METHOD_EXECUTION; +import static org.junit.vintage.engine.Constants.PARALLEL_POOL_SIZE; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.apiguardian.api.API; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.util.ExceptionUtils; +import org.junit.platform.engine.EngineExecutionListener; +import org.junit.platform.engine.ExecutionRequest; +import org.junit.platform.engine.TestDescriptor; +import org.junit.vintage.engine.descriptor.RunnerTestDescriptor; +import org.junit.vintage.engine.descriptor.VintageEngineDescriptor; + +/** + * @since 5.12 + */ +@API(status = INTERNAL, since = "5.12") +public class VintageExecutor { + + private static final Logger logger = LoggerFactory.getLogger(VintageExecutor.class); + + private static final int DEFAULT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors(); + private static final int SHUTDOWN_TIMEOUT_SECONDS = 30; + + private final VintageEngineDescriptor engineDescriptor; + private final EngineExecutionListener engineExecutionListener; + private final ExecutionRequest request; + + private final boolean parallelExecutionEnabled; + private final boolean classes; + private final boolean methods; + + public VintageExecutor(VintageEngineDescriptor engineDescriptor, EngineExecutionListener engineExecutionListener, + ExecutionRequest request) { + this.engineDescriptor = engineDescriptor; + this.engineExecutionListener = engineExecutionListener; + this.request = request; + this.parallelExecutionEnabled = request.getConfigurationParameters().getBoolean( + PARALLEL_EXECUTION_ENABLED).orElse(false); + this.classes = request.getConfigurationParameters().getBoolean(PARALLEL_CLASS_EXECUTION).orElse(false); + this.methods = request.getConfigurationParameters().getBoolean(PARALLEL_METHOD_EXECUTION).orElse(false); + } + + public void executeAllChildren() { + + if (!parallelExecutionEnabled) { + executeClassesAndMethodsSequentially(); + return; + } + + if (!classes && !methods) { + logger.warn(() -> "Parallel execution is enabled but no scope is defined. " + + "Falling back to sequential execution."); + executeClassesAndMethodsSequentially(); + return; + } + + boolean wasInterrupted = executeInParallel(); + if (wasInterrupted) { + Thread.currentThread().interrupt(); + } + } + + private void executeClassesAndMethodsSequentially() { + RunnerExecutor runnerExecutor = new RunnerExecutor(engineExecutionListener); + for (Iterator iterator = engineDescriptor.getModifiableChildren().iterator(); iterator.hasNext();) { + runnerExecutor.execute((RunnerTestDescriptor) iterator.next()); + iterator.remove(); + } + } + + private boolean executeInParallel() { + ExecutorService executorService = Executors.newWorkStealingPool(getThreadPoolSize()); + RunnerExecutor runnerExecutor = new RunnerExecutor(engineExecutionListener); + + List runnerTestDescriptors = collectRunnerTestDescriptors(executorService); + + if (!classes) { + executeClassesSequentially(runnerTestDescriptors, runnerExecutor); + return false; + } + + return executeClassesInParallel(runnerTestDescriptors, runnerExecutor, executorService); + } + + private int getThreadPoolSize() { + Optional optionalPoolSize = request.getConfigurationParameters().get(PARALLEL_POOL_SIZE); + if (optionalPoolSize.isPresent()) { + try { + int poolSize = Integer.parseInt(optionalPoolSize.get()); + if (poolSize > 0) { + return poolSize; + } + logger.warn(() -> "Invalid value for parallel pool size: " + poolSize); + } + catch (NumberFormatException e) { + logger.warn(() -> "Invalid value for parallel pool size: " + optionalPoolSize.get()); + } + } + return DEFAULT_THREAD_POOL_SIZE; + } + + private List collectRunnerTestDescriptors(ExecutorService executorService) { + return engineDescriptor.getModifiableChildren().stream() // + .map(RunnerTestDescriptor.class::cast) // + .map(it -> methods ? parallelMethodExecutor(it, executorService) : it) // + .collect(toList()); + } + + private RunnerTestDescriptor parallelMethodExecutor(RunnerTestDescriptor runnerTestDescriptor, + ExecutorService executorService) { + runnerTestDescriptor.setExecutorService(executorService); + return runnerTestDescriptor; + } + + private void executeClassesSequentially(List runnerTestDescriptors, + RunnerExecutor runnerExecutor) { + for (RunnerTestDescriptor runnerTestDescriptor : runnerTestDescriptors) { + runnerExecutor.execute(runnerTestDescriptor); + } + } + + private boolean executeClassesInParallel(List runnerTestDescriptors, + RunnerExecutor runnerExecutor, ExecutorService executorService) { + List> futures = new ArrayList<>(); + for (RunnerTestDescriptor runnerTestDescriptor : runnerTestDescriptors) { + CompletableFuture future = CompletableFuture.runAsync( + () -> runnerExecutor.execute(runnerTestDescriptor), executorService); + futures.add(future); + } + + CompletableFuture allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + boolean wasInterrupted = false; + try { + allOf.get(); + } + catch (InterruptedException e) { + logger.warn(e, () -> "Interruption while waiting for parallel test execution to finish"); + wasInterrupted = true; + } + catch (ExecutionException e) { + throw ExceptionUtils.throwAsUncheckedException(e.getCause()); + } + finally { + shutdownExecutorService(executorService); + } + return wasInterrupted; + } + + private void shutdownExecutorService(ExecutorService executorService) { + try { + executorService.shutdown(); + if (!executorService.awaitTermination(SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { + logger.warn(() -> "Executor service did not terminate within the specified timeout"); + executorService.shutdownNow(); + } + } + catch (InterruptedException e) { + logger.warn(e, () -> "Interruption while waiting for executor service to shut down"); + Thread.currentThread().interrupt(); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdReader.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdReader.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdReader.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdReader.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdStringifier.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdStringifier.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdStringifier.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/main/java/org/junit/vintage/engine/support/UniqueIdStringifier.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/module/org.junit.vintage.engine/module-info.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/module/org.junit.vintage.engine/module-info.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/module/org.junit.vintage.engine/module-info.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/module/org.junit.vintage.engine/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,13 +8,14 @@ * https://www.eclipse.org/legal/epl-v20.html */ + /** - * Provides a {@linkplain org.junit.platform.engine.TestEngine} for running - * JUnit 3 and 4 based tests on the platform. + * Provides a {@link org.junit.platform.engine.TestEngine} for running JUnit 3 + * and 4 based tests on the platform. * * @since 4.12 * @provides org.junit.platform.engine.TestEngine The {@code VintageTestEngine} - * runs JUnit 3 and 4 based tests on the platform. + * runs JUnit 3 and 4 based tests on the platform. */ module org.junit.vintage.engine { requires junit; // 4 diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4ParameterizedTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4ParameterizedTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4ParameterizedTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4ParameterizedTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4VersionCheckTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4VersionCheckTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4VersionCheckTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/JUnit4VersionCheckTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineBasicTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineBasicTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineBasicTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineBasicTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineDiscoveryTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineDiscoveryTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineDiscoveryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineDiscoveryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -212,7 +212,7 @@ List testMethodDescriptors = new ArrayList<>(runnerDescriptor.getChildren()); assertThat(testMethodDescriptors).hasSize(2); - var testMethodDescriptor = testMethodDescriptors.get(0); + var testMethodDescriptor = testMethodDescriptors.getFirst(); assertEquals("theory", testMethodDescriptor.getDisplayName()); assertEquals(VintageUniqueIdBuilder.uniqueIdForMethod(testClass, "theory", "0"), testMethodDescriptor.getUniqueId()); diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,8 @@ import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; +import static org.junit.platform.launcher.core.NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStore; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.junit.platform.testkit.engine.EventConditions.abortedWithReason; import static org.junit.platform.testkit.engine.EventConditions.container; import static org.junit.platform.testkit.engine.EventConditions.displayName; @@ -40,13 +42,13 @@ import org.assertj.core.api.Condition; import org.junit.AssumptionViolatedException; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.DisabledInEclipse; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.ExecutionRequest; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import org.junit.platform.testkit.engine.EngineExecutionResults; @@ -182,7 +184,7 @@ String commonNestedClassPrefix = EnclosedWithParameterizedChildrenJUnit4TestCase.class.getName() + "$NestedTestCase"; - execute(testClass).allEvents().debug().assertEventsMatchExactly( // + execute(testClass).allEvents().assertEventsMatchExactly( // event(engine(), started()), // event(container(testClass), started()), // event(container(commonNestedClassPrefix), started()), // @@ -397,14 +399,6 @@ PlainJUnit4TestCaseWithLifecycleMethods.EVENTS.add( "executionSkipped:" + testDescriptor.getDisplayName()); } - - @Override - public void dynamicTestRegistered(TestDescriptor testDescriptor) { - } - - @Override - public void reportingEntryPublished(TestDescriptor testDescriptor, ReportEntry entry) { - } }; execute(testClass, listener); @@ -506,7 +500,7 @@ Class testClass = ParameterizedTimingTestCase.class; - var events = execute(testClass).allEvents().debug(); + var events = execute(testClass).allEvents(); var firstParamStartedEvent = events.filter(event(container("[foo]"), started())::matches).findFirst() // .orElseThrow(() -> new AssertionError("No start event for [foo]")); @@ -647,7 +641,7 @@ @Override public void run(RunNotifier notifier) { - var staticDescription = getDescription().getChildren().get(0); + var staticDescription = getDescription().getChildren().getFirst(); notifier.fireTestStarted(staticDescription); notifier.fireTestFinished(staticDescription); var dynamicDescription = createTestDescription(testClass, "dynamicTest"); @@ -869,6 +863,7 @@ } @Test + @DisabledInEclipse void executesUnrolledSpockFeatureMethod() { Class testClass = SpockTestCaseWithUnrolledAndRegularFeatureMethods.class; var request = LauncherDiscoveryRequestBuilder.request().selectors( @@ -887,6 +882,7 @@ } @Test + @DisabledInEclipse void executesRegularSpockFeatureMethod() { Class testClass = SpockTestCaseWithUnrolledAndRegularFeatureMethods.class; var request = LauncherDiscoveryRequestBuilder.request().selectors(selectMethod(testClass, "regular")).build(); @@ -933,7 +929,8 @@ var discoveryRequest = request(testClass); var engineTestDescriptor = testEngine.discover(discoveryRequest, UniqueId.forEngine(testEngine.getId())); testEngine.execute( - new ExecutionRequest(engineTestDescriptor, listener, discoveryRequest.getConfigurationParameters())); + ExecutionRequest.create(engineTestDescriptor, listener, discoveryRequest.getConfigurationParameters(), + dummyOutputDirectoryCreator(), dummyNamespacedHierarchicalStore())); } private static LauncherDiscoveryRequest request(Class testClass) { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineTestSuite.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineTestSuite.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineTestSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageUniqueIdBuilder.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageUniqueIdBuilder.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageUniqueIdBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageUniqueIdBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/DescriptionUtilsTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/DescriptionUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/DescriptionUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/DescriptionUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,8 +20,7 @@ import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; -import org.junit.platform.commons.util.ClassFilter; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.runner.Description; import org.junit.vintage.engine.discovery.IsPotentialJUnit4TestClass; @@ -32,8 +31,8 @@ @TestFactory Stream computedMethodNameCorrectly() { - var classFilter = ClassFilter.of(new IsPotentialJUnit4TestClass()); - var testClasses = ReflectionUtils.findAllClassesInPackage("org.junit.vintage.engine.samples", classFilter); + var testClasses = ReflectionSupport.findAllClassesInPackage("org.junit.vintage.engine.samples", + new IsPotentialJUnit4TestClass(), name -> true); return testClasses.stream().flatMap(this::toDynamicTests); } diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/OrFilterTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/OrFilterTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/OrFilterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/OrFilterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/TestSourceProviderTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/TestSourceProviderTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/TestSourceProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/TestSourceProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/VintageTestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/VintageTestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/VintageTestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/descriptor/VintageTestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClassTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClassTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClassTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/IsPotentialJUnit4TestClassTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessorTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessorTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/RunnerTestDescriptorPostProcessorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/VintageDiscovererTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/VintageDiscovererTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/VintageDiscovererTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/discovery/VintageDiscovererTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -125,6 +125,7 @@ return new VintageDiscoverer().discover(request, engineId()); } + @SuppressWarnings("JUnitMalformedDeclaration") public static class Foo { @org.junit.Test @@ -133,6 +134,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") public static class Bar { @org.junit.Test diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/ParallelExecutionIntegrationTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/ParallelExecutionIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/ParallelExecutionIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/ParallelExecutionIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,204 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.vintage.engine.execution; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.testkit.engine.EventConditions.container; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully; +import static org.junit.platform.testkit.engine.EventConditions.started; +import static org.junit.platform.testkit.engine.EventConditions.test; +import static org.junit.vintage.engine.Constants.PARALLEL_CLASS_EXECUTION; +import static org.junit.vintage.engine.Constants.PARALLEL_EXECUTION_ENABLED; +import static org.junit.vintage.engine.Constants.PARALLEL_METHOD_EXECUTION; +import static org.junit.vintage.engine.Constants.PARALLEL_POOL_SIZE; +import static org.junit.vintage.engine.descriptor.VintageTestDescriptor.SEGMENT_TYPE_RUNNER; +import static org.junit.vintage.engine.descriptor.VintageTestDescriptor.SEGMENT_TYPE_TEST; +import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelClassesTestCase.FirstClassTestCase; +import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelClassesTestCase.SecondClassTestCase; +import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelClassesTestCase.ThirdClassTestCase; +import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelMethodsTestCase.FirstMethodTestCase; +import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelMethodsTestCase.SecondMethodTestCase; +import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelMethodsTestCase.ThirdMethodTestCase; + +import java.time.Instant; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +import org.assertj.core.api.Condition; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.fixtures.TrackLogRecords; +import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.engine.discovery.ClassSelector; +import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; +import org.junit.platform.testkit.engine.EngineExecutionResults; +import org.junit.platform.testkit.engine.EngineTestKit; +import org.junit.platform.testkit.engine.Event; +import org.junit.platform.testkit.engine.Events; +import org.junit.vintage.engine.VintageTestEngine; +import org.junit.vintage.engine.samples.junit4.JUnit4ParallelClassesTestCase; +import org.junit.vintage.engine.samples.junit4.JUnit4ParallelMethodsTestCase; + +class ParallelExecutionIntegrationTests { + + @Test + void executesTestClassesInParallel(TestReporter reporter) { + JUnit4ParallelClassesTestCase.AbstractBlockingTestCase.threadNames.clear(); + JUnit4ParallelClassesTestCase.AbstractBlockingTestCase.countDownLatch = new CountDownLatch(3); + + var events = executeInParallelSuccessfully(3, true, false, FirstClassTestCase.class, SecondClassTestCase.class, + ThirdClassTestCase.class).list(); + + var startedTimestamps = getTimestampsFor(events, event(container(SEGMENT_TYPE_RUNNER), started())); + var finishedTimestamps = getTimestampsFor(events, + event(container(SEGMENT_TYPE_RUNNER), finishedSuccessfully())); + var threadNames = new HashSet<>(JUnit4ParallelClassesTestCase.AbstractBlockingTestCase.threadNames); + + reporter.publishEntry("startedTimestamps", startedTimestamps.toString()); + reporter.publishEntry("finishedTimestamps", finishedTimestamps.toString()); + + assertThat(startedTimestamps).hasSize(3); + assertThat(finishedTimestamps).hasSize(3); + assertThat(startedTimestamps).allMatch(startTimestamp -> finishedTimestamps.stream().noneMatch( + finishedTimestamp -> finishedTimestamp.isBefore(startTimestamp))); + assertThat(threadNames).hasSize(3); + } + + @Test + void executesTestMethodsInParallel(TestReporter reporter) { + JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.threadNames.clear(); + JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.countDownLatch = new CountDownLatch(3); + + var events = executeInParallelSuccessfully(3, false, true, FirstMethodTestCase.class).list(); + + var startedTimestamps = getTimestampsFor(events, event(test(SEGMENT_TYPE_TEST), started())); + var finishedTimestamps = getTimestampsFor(events, event(test(SEGMENT_TYPE_TEST), finishedSuccessfully())); + var threadNames = new HashSet<>(JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.threadNames); + + reporter.publishEntry("startedTimestamps", startedTimestamps.toString()); + reporter.publishEntry("finishedTimestamps", finishedTimestamps.toString()); + + assertThat(startedTimestamps).hasSize(3); + assertThat(finishedTimestamps).hasSize(3); + assertThat(startedTimestamps).allMatch(startTimestamp -> finishedTimestamps.stream().noneMatch( + finishedTimestamp -> finishedTimestamp.isBefore(startTimestamp))); + assertThat(threadNames).hasSize(3); + } + + @Test + void executesTestClassesAndMethodsInParallel(TestReporter reporter) { + JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.threadNames.clear(); + JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.countDownLatch = new CountDownLatch(9); + + var events = executeInParallelSuccessfully(3, true, true, FirstMethodTestCase.class, SecondMethodTestCase.class, + ThirdMethodTestCase.class).list(); + + var startedClassesTimestamps = getTimestampsFor(events, event(container(SEGMENT_TYPE_RUNNER), started())); + var finishedClassesTimestamps = getTimestampsFor(events, + event(container(SEGMENT_TYPE_RUNNER), finishedSuccessfully())); + var startedMethodsTimestamps = getTimestampsFor(events, event(test(SEGMENT_TYPE_TEST), started())); + var finishedMethodsTimestamps = getTimestampsFor(events, + event(test(SEGMENT_TYPE_TEST), finishedSuccessfully())); + + var threadNames = new HashSet<>(JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.threadNames); + + reporter.publishEntry("startedClassesTimestamps", startedClassesTimestamps.toString()); + reporter.publishEntry("finishedClassesTimestamps", finishedClassesTimestamps.toString()); + reporter.publishEntry("startedMethodsTimestamps", startedMethodsTimestamps.toString()); + reporter.publishEntry("finishedMethodsTimestamps", finishedMethodsTimestamps.toString()); + + assertThat(startedClassesTimestamps).hasSize(3); + assertThat(finishedClassesTimestamps).hasSize(3); + assertThat(startedMethodsTimestamps).hasSize(9); + assertThat(finishedMethodsTimestamps).hasSize(9); + + assertThat(threadNames).hasSize(3); + } + + @Test + void executesInParallelWhenNoScopeIsDefined(@TrackLogRecords LogRecordListener listener) { + JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.threadNames.clear(); + JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.countDownLatch = new CountDownLatch(9); + execute(3, false, false, FirstMethodTestCase.class, SecondMethodTestCase.class, ThirdMethodTestCase.class); + + // @formatter:off + assertTrue(listener.stream(Level.WARNING) + .map(LogRecord::getMessage) + .anyMatch(m -> m.startsWith( + "Parallel execution is enabled but no scope is defined. Falling back to sequential execution."))); + // @formatter:on + + var threadNames = new HashSet<>(JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase.threadNames); + assertThat(threadNames).hasSize(1); + } + + @Test + void executesInParallelWhenInvalidPoolSizeIsDefined(@TrackLogRecords LogRecordListener listener) { + execute(-1, true, true, FirstMethodTestCase.class, SecondMethodTestCase.class, ThirdMethodTestCase.class); + + // @formatter:off + assertTrue(listener.stream(Level.WARNING) + .map(LogRecord::getMessage) + .anyMatch(m -> m.startsWith("Invalid value for parallel pool size: -1"))); + // @formatter:on + } + + private List getTimestampsFor(List events, Condition condition) { + // @formatter:off + return events.stream() + .filter(condition::matches) + .map(Event::getTimestamp) + .toList(); + // @formatter:on + } + + private Events executeInParallelSuccessfully(int poolSize, boolean parallelClasses, boolean parallelMethods, + Class... testClasses) { + var events = execute(poolSize, parallelClasses, parallelMethods, testClasses).allEvents(); + try { + return events.assertStatistics(it -> it.failed(0)); + } + catch (AssertionError error) { + events.debug(); + throw error; + } + } + + private static EngineExecutionResults execute(int poolSize, boolean parallelClasses, boolean parallelMethods, + Class... testClass) { + return EngineTestKit.execute(new VintageTestEngine(), + request(poolSize, parallelClasses, parallelMethods, testClass)); + } + + private static LauncherDiscoveryRequest request(int poolSize, boolean parallelClasses, boolean parallelMethods, + Class... testClasses) { + var classSelectors = Arrays.stream(testClasses) // + .map(DiscoverySelectors::selectClass) // + .toArray(ClassSelector[]::new); + + return LauncherDiscoveryRequestBuilder.request() // + .selectors(classSelectors) // + .configurationParameter(PARALLEL_EXECUTION_ENABLED, String.valueOf(true)) // + .configurationParameter(PARALLEL_POOL_SIZE, String.valueOf(poolSize)) // + .configurationParameter(PARALLEL_CLASS_EXECUTION, String.valueOf(parallelClasses)) // + .configurationParameter(PARALLEL_METHOD_EXECUTION, String.valueOf(parallelMethods)) // + .build(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdReaderTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdReaderTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdReaderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdReaderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdStringifierTests.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdStringifierTests.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdStringifierTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/java/org/junit/vintage/engine/support/UniqueIdStringifierTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/resources/junit-platform.properties jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/resources/junit-platform.properties --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/test/resources/junit-platform.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/test/resources/junit-platform.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +junit.jupiter.extensions.autodetection.enabled=true diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/groovy/org/junit/vintage/engine/samples/spock/SpockTestCaseWithUnrolledAndRegularFeatureMethods.groovy jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/groovy/org/junit/vintage/engine/samples/spock/SpockTestCaseWithUnrolledAndRegularFeatureMethods.groovy --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/groovy/org/junit/vintage/engine/samples/spock/SpockTestCaseWithUnrolledAndRegularFeatureMethods.groovy 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/groovy/org/junit/vintage/engine/samples/spock/SpockTestCaseWithUnrolledAndRegularFeatureMethods.groovy 2026-06-21 20:26:05.000000000 +0000 @@ -1,3 +1,14 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + package org.junit.vintage.engine.samples.spock import spock.lang.Specification diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/PlainOldJavaClassWithoutAnyTestsTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/PlainOldJavaClassWithoutAnyTestsTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/PlainOldJavaClassWithoutAnyTestsTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/PlainOldJavaClassWithoutAnyTestsTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/AbstractJUnit3TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/AbstractJUnit3TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/AbstractJUnit3TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/AbstractJUnit3TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3ParallelSuiteWithSubsuites.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3ParallelSuiteWithSubsuites.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3ParallelSuiteWithSubsuites.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3ParallelSuiteWithSubsuites.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import junit.framework.TestCase; import junit.framework.TestSuite; +@SuppressWarnings("JUnitMalformedDeclaration") public class JUnit3ParallelSuiteWithSubsuites extends TestCase { private final String arg; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSingleTestCaseWithSingleTestWhichFails.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSingleTestCaseWithSingleTestWhichFails.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSingleTestCaseWithSingleTestWhichFails.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSingleTestCaseWithSingleTestWhichFails.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSubsuites.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSubsuites.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSubsuites.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit3SuiteWithSubsuites.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import junit.framework.TestCase; import junit.framework.TestSuite; +@SuppressWarnings("JUnitMalformedDeclaration") public class JUnit3SuiteWithSubsuites extends TestCase { private final String arg; diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/PlainJUnit3TestCaseWithSingleTestWhichFails.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/PlainJUnit3TestCaseWithSingleTestWhichFails.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/PlainJUnit3TestCaseWithSingleTestWhichFails.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/PlainJUnit3TestCaseWithSingleTestWhichFails.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJunit4TestCaseWithConstructorParameter.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJunit4TestCaseWithConstructorParameter.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJunit4TestCaseWithConstructorParameter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/AbstractJunit4TestCaseWithConstructorParameter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/Categories.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/Categories.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/Categories.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/Categories.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/CompletelyDynamicTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/CompletelyDynamicTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/CompletelyDynamicTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/CompletelyDynamicTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConcreteJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConcreteJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConcreteJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConcreteJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConfigurableRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConfigurableRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConfigurableRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ConfigurableRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/DynamicRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/DynamicRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/DynamicRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/DynamicRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EmptyIgnoredTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EmptyIgnoredTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EmptyIgnoredTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EmptyIgnoredTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedWithParameterizedChildrenJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedWithParameterizedChildrenJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedWithParameterizedChildrenJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/EnclosedWithParameterizedChildrenJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,7 +19,7 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -// Source: https://github.com/junit-team/junit5/issues/3083 +// Source: https://github.com/junit-team/junit-framework/issues/3083 @RunWith(Enclosed.class) public class EnclosedWithParameterizedChildrenJUnit4TestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ExceptionThrowingRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ExceptionThrowingRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ExceptionThrowingRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ExceptionThrowingRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCaseWithNotFilterableRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCaseWithNotFilterableRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCaseWithNotFilterableRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredJUnit4TestCaseWithNotFilterableRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredParameterizedTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredParameterizedTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredParameterizedTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/IgnoredParameterizedTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelClassesTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelClassesTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelClassesTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelClassesTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.vintage.engine.samples.junit4; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; +import org.junit.runner.RunWith; + +@RunWith(Enclosed.class) +public class JUnit4ParallelClassesTestCase { + + public static class AbstractBlockingTestCase { + + public static final Set threadNames = ConcurrentHashMap.newKeySet(); + public static CountDownLatch countDownLatch; + + @Rule + public final TestWatcher testWatcher = new TestWatcher() { + @Override + protected void starting(Description description) { + AbstractBlockingTestCase.threadNames.add(Thread.currentThread().getName()); + } + }; + + @Test + public void test() throws Exception { + countDownAndBlock(countDownLatch); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private static void countDownAndBlock(CountDownLatch countDownLatch) throws InterruptedException { + countDownLatch.countDown(); + countDownLatch.await(estimateSimulatedTestDurationInMilliseconds(), MILLISECONDS); + } + + private static long estimateSimulatedTestDurationInMilliseconds() { + var runningInCi = Boolean.parseBoolean(System.getenv("CI")); + return runningInCi ? 1000 : 100; + } + } + + public static class FirstClassTestCase extends AbstractBlockingTestCase { + } + + public static class SecondClassTestCase extends AbstractBlockingTestCase { + } + + public static class ThirdClassTestCase extends AbstractBlockingTestCase { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelMethodsTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelMethodsTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelMethodsTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelMethodsTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.vintage.engine.samples.junit4; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; +import org.junit.runner.RunWith; + +@RunWith(Enclosed.class) +public class JUnit4ParallelMethodsTestCase { + + public static class AbstractBlockingTestCase { + + public static final Set threadNames = ConcurrentHashMap.newKeySet(); + public static CountDownLatch countDownLatch; + + @Rule + public final TestWatcher testWatcher = new TestWatcher() { + @Override + protected void starting(Description description) { + AbstractBlockingTestCase.threadNames.add(Thread.currentThread().getName()); + } + }; + + @Test + public void fistTest() throws Exception { + countDownAndBlock(countDownLatch); + } + + @Test + public void secondTest() throws Exception { + countDownAndBlock(countDownLatch); + } + + @Test + public void thirdTest() throws Exception { + countDownAndBlock(countDownLatch); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private static void countDownAndBlock(CountDownLatch countDownLatch) throws InterruptedException { + countDownLatch.countDown(); + countDownLatch.await(estimateSimulatedTestDurationInMilliseconds(), MILLISECONDS); + } + + private static long estimateSimulatedTestDurationInMilliseconds() { + var runningInCi = Boolean.parseBoolean(System.getenv("CI")); + return runningInCi ? 1000 : 100; + } + } + + public static class FirstMethodTestCase extends JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase { + } + + public static class SecondMethodTestCase extends JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase { + } + + public static class ThirdMethodTestCase extends JUnit4ParallelMethodsTestCase.AbstractBlockingTestCase { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParameterizedTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParameterizedTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParameterizedTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParameterizedTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithFilterableChildRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithFilterableChildRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithFilterableChildRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithFilterableChildRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithIgnoredJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithIgnoredJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithIgnoredJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithIgnoredJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithErrorInBeforeClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithErrorInBeforeClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithErrorInBeforeClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteOfSuiteWithJUnit4TestCaseWithErrorInBeforeClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithExceptionThrowingRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithExceptionThrowingRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithExceptionThrowingRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithExceptionThrowingRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithIgnoredJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithIgnoredJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithIgnoredJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithIgnoredJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit3SuiteWithSingleTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit3SuiteWithSingleTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit3SuiteWithSingleTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit3SuiteWithSingleTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithAssumptionFailureInBeforeClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithErrorInBeforeClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithErrorInBeforeClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithErrorInBeforeClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithErrorInBeforeClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithJUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithPlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithPlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithPlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithPlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithTwoTestCases.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithTwoTestCases.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithTwoTestCases.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4SuiteWithTwoTestCases.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithAssumptionFailureInBeforeClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithAssumptionFailureInBeforeClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithAssumptionFailureInBeforeClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithAssumptionFailureInBeforeClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithDistinguishableOverloadedMethod.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithDistinguishableOverloadedMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithDistinguishableOverloadedMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithDistinguishableOverloadedMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorCollectorStoringMultipleFailures.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorCollectorStoringMultipleFailures.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorCollectorStoringMultipleFailures.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorCollectorStoringMultipleFailures.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInAfterClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInAfterClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInAfterClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInAfterClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInBeforeClass.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInBeforeClass.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInBeforeClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithErrorInBeforeClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithExceptionThrowingRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithExceptionThrowingRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithExceptionThrowingRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithExceptionThrowingRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithFailingDescriptionThatIsNotReportedAsFinished.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithIndistinguishableOverloadedMethod.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithIndistinguishableOverloadedMethod.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithIndistinguishableOverloadedMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithIndistinguishableOverloadedMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithNotFilterableRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithNotFilterableRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithNotFilterableRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithNotFilterableRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithCustomUniqueIdsAndDisplayNames.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithDuplicateChangingChildDescriptions.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithDuplicateChangingChildDescriptions.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithDuplicateChangingChildDescriptions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4TestCaseWithRunnerWithDuplicateChangingChildDescriptions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/MalformedJUnit4TestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/MalformedJUnit4TestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/MalformedJUnit4TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/MalformedJUnit4TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/NotFilterableRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/NotFilterableRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/NotFilterableRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/NotFilterableRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTimingTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTimingTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTimingTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedTimingTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithAfterParamFailureTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithAfterParamFailureTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithAfterParamFailureTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithAfterParamFailureTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithBeforeParamFailureTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithBeforeParamFailureTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithBeforeParamFailureTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/ParameterizedWithBeforeParamFailureTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithFiveTestMethods.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithFiveTestMethods.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithFiveTestMethods.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithFiveTestMethods.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithLifecycleMethods.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithLifecycleMethods.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithLifecycleMethods.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithLifecycleMethods.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleInheritedTestWhichFails.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleInheritedTestWhichFails.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleInheritedTestWhichFails.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleInheritedTestWhichFails.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichFails.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichFails.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichFails.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichFails.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithSingleTestWhichIsIgnored.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithTwoTestMethods.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithTwoTestMethods.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithTwoTestMethods.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/PlainJUnit4TestCaseWithTwoTestMethods.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerThatOnlyReportsFailures.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerThatOnlyReportsFailures.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerThatOnlyReportsFailures.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerThatOnlyReportsFailures.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerWithCustomUniqueIdsAndDisplayNames.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerWithCustomUniqueIdsAndDisplayNames.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerWithCustomUniqueIdsAndDisplayNames.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/RunnerWithCustomUniqueIdsAndDisplayNames.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/SingleFailingTheoryTestCase.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/SingleFailingTheoryTestCase.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/SingleFailingTheoryTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/SingleFailingTheoryTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/TestCaseRunWithJUnitPlatformRunner.java jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/TestCaseRunWithJUnitPlatformRunner.java --- jtreg8-8.1+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/TestCaseRunWithJUnitPlatformRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit4/TestCaseRunWithJUnitPlatformRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/jupiter-tests.gradle.kts jtreg8-8.3+1+ds1/junit5/jupiter-tests/jupiter-tests.gradle.kts --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/jupiter-tests.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/jupiter-tests.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -23,6 +23,8 @@ testImplementation(libs.memoryfilesystem) testImplementation(testFixtures(projects.junitJupiterApi)) testImplementation(testFixtures(projects.junitJupiterEngine)) + testImplementation(testFixtures(projects.junitPlatformLauncher)) + testImplementation(testFixtures(projects.junitPlatformReporting)) } tasks { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreConditionTests.java.jte jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreConditionTests.java.jte --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreConditionTests.java.jte 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreConditionTests.java.jte 2026-06-21 20:26:05.000000000 +0000 @@ -7,19 +7,18 @@ ${licenseHeader} package org.junit.jupiter.api.condition; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; @for(var jre : jresSortedByStringValue)<%-- --%>import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava${jre.getVersion()}; @endfor<%-- --%>import static org.junit.jupiter.api.condition.JavaVersionPredicates.onKnownVersion; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.PreconditionViolationException; /** - * Unit tests for {@link DisabledOnJreCondition}. + * Unit tests for {@link DisabledOnJreCondition}, generated from + * {@code DisabledOnJreConditionTests.java.jte}. * *

    Note that test method names MUST match the test method names in * {@link DisabledOnJreIntegrationTests}. @@ -28,6 +27,8 @@ */ class DisabledOnJreConditionTests extends AbstractExecutionConditionTests { + private static final String JAVA_VERSION = System.getProperty("java.version"); + @Override protected ExecutionCondition getExecutionCondition() { return new DisabledOnJreCondition(); @@ -49,12 +50,30 @@ } /** - * @see DisabledOnJreIntegrationTests#missingJreDeclaration() + * @see DisabledOnJreIntegrationTests#missingVersionDeclaration() + */ + @Test + void missingVersionDeclaration() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("You must declare at least one JRE or version in @DisabledOnJre"); + } + + /** + * @see DisabledOnJreIntegrationTests#jreUndefined() + */ + @Test + void jreUndefined() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("JRE.UNDEFINED is not supported in @DisabledOnJre"); + } + + /** + * @see DisabledOnJreIntegrationTests#version7() */ @Test - void missingJreDeclaration() { - Exception exception = assertThrows(PreconditionViolationException.class, this::evaluateCondition); - assertThat(exception).hasMessageContaining("You must declare at least one JRE"); + void version7() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("Version [7] in @DisabledOnJre must be greater than or equal to 8"); } /** @@ -68,10 +87,20 @@ } @for(var jre : jres) /** - * @see DisabledOnJreIntegrationTests#java${jre.getVersion()}() + * @see DisabledOnJreIntegrationTests#jre${jre.getVersion()}() + */ + @Test + void jre${jre.getVersion()}() { + evaluateCondition(); + assertDisabledOnCurrentJreIf(onJava${jre.getVersion()}()); + } +@endfor<%-- +--%>@for(var jre : jres) + /** + * @see DisabledOnJreIntegrationTests#version${jre.getVersion()}() */ @Test - void java${jre.getVersion()}() { + void version${jre.getVersion()}() { evaluateCondition(); assertDisabledOnCurrentJreIf(onJava${jre.getVersion()}()); } @@ -88,11 +117,11 @@ private void assertDisabledOnCurrentJreIf(boolean condition) { if (condition) { assertDisabled(); - assertReasonContains("Disabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Disabled on JRE version: " + JAVA_VERSION); } else { assertEnabled(); - assertReasonContains("Enabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Enabled on JRE version: " + JAVA_VERSION); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreIntegrationTests.java.jte jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreIntegrationTests.java.jte --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreIntegrationTests.java.jte 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/DisabledOnJreIntegrationTests.java.jte 2026-06-21 20:26:05.000000000 +0000 @@ -14,6 +14,7 @@ --%>import static org.junit.jupiter.api.condition.JRE.JAVA_${jre.getVersion()}; @endfor<%-- --%>import static org.junit.jupiter.api.condition.JRE.OTHER; +import static org.junit.jupiter.api.condition.JRE.UNDEFINED; @for(var jre : jresSortedByStringValue)<%-- --%>import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava${jre.getVersion()}; @endfor<%-- @@ -23,7 +24,8 @@ import org.junit.jupiter.api.Test; /** - * Integration tests for {@link DisabledOnJre}. + * Integration tests for {@link DisabledOnJre @DisabledOnJre}, generated from + * {@code DisabledOnJreIntegrationTests.java.jte}. * * @since 5.1 */ @@ -37,7 +39,19 @@ @Test @Disabled("Only used in a unit test via reflection") @DisabledOnJre({}) - void missingJreDeclaration() { + void missingVersionDeclaration() { + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledOnJre(UNDEFINED) + void jreUndefined() { + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledOnJre(value = JAVA_17, versions = { 21, 7 }) + void version7() { } @Test @@ -53,7 +67,14 @@ @for(var jre : jres) @Test @DisabledOnJre(JAVA_${jre.getVersion()}) - void java${jre.getVersion()}() { + void jre${jre.getVersion()}() { + assertFalse(onJava${jre.getVersion()}()); + } +@endfor<%-- +--%>@for(var jre : jres) + @Test + @DisabledOnJre(versions = ${jre.getVersion()}) + void version${jre.getVersion()}() { assertFalse(onJava${jre.getVersion()}()); } @endfor diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreConditionTests.java.jte jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreConditionTests.java.jte --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreConditionTests.java.jte 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreConditionTests.java.jte 2026-06-21 20:26:05.000000000 +0000 @@ -7,19 +7,18 @@ ${licenseHeader} package org.junit.jupiter.api.condition; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; @for(var jre : jresSortedByStringValue)<%-- --%>import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava${jre.getVersion()}; @endfor<%-- --%>import static org.junit.jupiter.api.condition.JavaVersionPredicates.onKnownVersion; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.PreconditionViolationException; /** - * Unit tests for {@link EnabledOnJreCondition}. + * Unit tests for {@link EnabledOnJreCondition}, generated from + * {@code EnabledOnJreConditionTests.java.jte}. * *

    Note that test method names MUST match the test method names in * {@link EnabledOnJreIntegrationTests}. @@ -28,6 +27,8 @@ */ class EnabledOnJreConditionTests extends AbstractExecutionConditionTests { + private static final String JAVA_VERSION = System.getProperty("java.version"); + @Override protected ExecutionCondition getExecutionCondition() { return new EnabledOnJreCondition(); @@ -49,12 +50,30 @@ } /** - * @see EnabledOnJreIntegrationTests#missingJreDeclaration() + * @see EnabledOnJreIntegrationTests#missingVersionDeclaration() + */ + @Test + void missingVersionDeclaration() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("You must declare at least one JRE or version in @EnabledOnJre"); + } + + /** + * @see EnabledOnJreIntegrationTests#jreUndefined() + */ + @Test + void jreUndefined() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("JRE.UNDEFINED is not supported in @EnabledOnJre"); + } + + /** + * @see EnabledOnJreIntegrationTests#version7() */ @Test - void missingJreDeclaration() { - Exception exception = assertThrows(PreconditionViolationException.class, this::evaluateCondition); - assertThat(exception).hasMessageContaining("You must declare at least one JRE"); + void version7() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("Version [7] in @EnabledOnJre must be greater than or equal to 8"); } /** @@ -67,10 +86,20 @@ } @for(var jre : jres) /** - * @see EnabledOnJreIntegrationTests#java${jre.getVersion()}() + * @see EnabledOnJreIntegrationTests#jre${jre.getVersion()}() + */ + @Test + void jre${jre.getVersion()}() { + evaluateCondition(); + assertEnabledOnCurrentJreIf(onJava${jre.getVersion()}()); + } +@endfor<%-- +--%>@for(var jre : jres) + /** + * @see EnabledOnJreIntegrationTests#version${jre.getVersion()}() */ @Test - void java${jre.getVersion()}() { + void version${jre.getVersion()}() { evaluateCondition(); assertEnabledOnCurrentJreIf(onJava${jre.getVersion()}()); } @@ -88,11 +117,11 @@ private void assertEnabledOnCurrentJreIf(boolean condition) { if (condition) { assertEnabled(); - assertReasonContains("Enabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Enabled on JRE version: " + JAVA_VERSION); } else { assertDisabled(); - assertReasonContains("Disabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Disabled on JRE version: " + JAVA_VERSION); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreIntegrationTests.java.jte jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreIntegrationTests.java.jte --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreIntegrationTests.java.jte 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/templates/resources/test/org/junit/jupiter/api/condition/EnabledOnJreIntegrationTests.java.jte 2026-06-21 20:26:05.000000000 +0000 @@ -13,6 +13,7 @@ --%>import static org.junit.jupiter.api.condition.JRE.JAVA_${jre.getVersion()}; @endfor<%-- --%>import static org.junit.jupiter.api.condition.JRE.OTHER; +import static org.junit.jupiter.api.condition.JRE.UNDEFINED; @for(var jre : jresSortedByStringValue)<%-- --%>import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava${jre.getVersion()}; @endfor<%-- @@ -22,7 +23,8 @@ import org.junit.jupiter.api.Test; /** - * Integration tests for {@link EnabledOnJre}. + * Integration tests for {@link EnabledOnJre @EnabledOnJre}, generated from + * {@code EnabledOnJreIntegrationTests.java.jte}. * * @since 5.1 */ @@ -36,7 +38,19 @@ @Test @Disabled("Only used in a unit test via reflection") @EnabledOnJre({}) - void missingJreDeclaration() { + void missingVersionDeclaration() { + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledOnJre(UNDEFINED) + void jreUndefined() { + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledOnJre(value = JAVA_17, versions = { 21, 7 }) + void version7() { } @Test @@ -51,7 +65,14 @@ @for(var jre : jres) @Test @EnabledOnJre(JAVA_${jre.getVersion()}) - void java${jre.getVersion()}() { + void jre${jre.getVersion()}() { + assertTrue(onJava${jre.getVersion()}()); + } +@endfor<%-- +--%>@for(var jre : jres) + @Test + @EnabledOnJre(versions = ${jre.getVersion()}) + void version${jre.getVersion()}() { assertTrue(onJava${jre.getVersion()}()); } @endfor diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertEqualsTests.groovy jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertEqualsTests.groovy --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertEqualsTests.groovy 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertEqualsTests.groovy 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.api import java.util.function.Supplier diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertNotEqualsTests.groovy jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertNotEqualsTests.groovy --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertNotEqualsTests.groovy 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/GroovyAssertNotEqualsTests.groovy 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.api import org.opentest4j.AssertionFailedError diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/PrimitiveAndWrapperTypeHelpers.groovy jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/PrimitiveAndWrapperTypeHelpers.groovy --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/PrimitiveAndWrapperTypeHelpers.groovy 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/groovy/org/junit/jupiter/api/PrimitiveAndWrapperTypeHelpers.groovy 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.api class PrimitiveAndWrapperTypeHelpers { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/DefaultPackageTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/DefaultPackageTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/DefaultPackageTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/DefaultPackageTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,5 @@ - /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +7,7 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/example/B_TestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/example/B_TestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/example/B_TestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/example/B_TestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/JupiterTestSuite.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/JupiterTestSuite.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/JupiterTestSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/JupiterTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertAllAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertAllAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertAllAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertAllAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -208,7 +208,7 @@ assertEquals(exceptionTypes.length, failures.size(), "number of failures"); // Verify that exceptions are also present as suppressed exceptions. - // https://github.com/junit-team/junit5/issues/1602 + // https://github.com/junit-team/junit-framework/issues/1602 Throwable[] suppressed = multipleFailuresError.getSuppressed(); assertEquals(exceptionTypes.length, suppressed.length, "number of suppressed exceptions"); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertArrayEqualsAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertArrayEqualsAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertArrayEqualsAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertArrayEqualsAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertDoesNotThrowAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertDoesNotThrowAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertDoesNotThrowAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertDoesNotThrowAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertEqualsAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertEqualsAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertEqualsAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertEqualsAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -752,6 +752,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("overrides") private static class EqualsThrowsException { @Override diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertFalseAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertFalseAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertFalseAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertFalseAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertInstanceOfAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertInstanceOfAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertInstanceOfAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertInstanceOfAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertIterableEqualsAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertIterableEqualsAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertIterableEqualsAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertIterableEqualsAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -445,7 +445,7 @@ } @Test - // https://github.com/junit-team/junit5/issues/2157 + // https://github.com/junit-team/junit-framework/issues/2157 void assertIterableEqualsWithListOfPath() { var expected = listOf(Path.of("1")); var actual = listOf(Path.of("1")); @@ -462,7 +462,7 @@ } @Test - // https://github.com/junit-team/junit5/issues/2915 + // https://github.com/junit-team/junit-framework/issues/2915 void assertIterableEqualsWithDifferentListOfPath() { try { var expected = listOf(Path.of("1").resolve("2")); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertLinesMatchAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertLinesMatchAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertLinesMatchAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertLinesMatchAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotEqualsAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotEqualsAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotEqualsAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotEqualsAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -757,6 +757,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("overrides") private static class EqualsThrowsExceptionClass { @Override diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotNullAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotNullAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotNullAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotNullAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotSameAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotSameAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotSameAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNotSameAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNullAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNullAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNullAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertNullAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertSameAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertSameAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertSameAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertSameAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsExactlyAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsExactlyAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsExactlyAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertThrowsExactlyAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutPreemptivelyAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutPreemptivelyAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutPreemptivelyAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTimeoutPreemptivelyAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -40,8 +40,8 @@ class AssertTimeoutPreemptivelyAssertionsTests { private static final Duration PREEMPTIVE_TIMEOUT = ofMillis(WINDOWS.isCurrentOs() ? 1000 : 100); - private static final Assertions.TimeoutFailureFactory TIMEOUT_EXCEPTION_FACTORY = (__, ___, - ____) -> new TimeoutException(); + private static final Assertions.TimeoutFailureFactory TIMEOUT_EXCEPTION_FACTORY = (__, ___, ____, + _____) -> new TimeoutException(); private static final ThreadLocal changed = ThreadLocal.withInitial(() -> new AtomicBoolean(false)); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTrueAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTrueAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTrueAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertTrueAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertionTestUtils.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertionTestUtils.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertionTestUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssertionTestUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssumptionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssumptionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssumptionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/AssumptionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -165,7 +165,7 @@ List list = new ArrayList<>(); assumingThat(true, () -> list.add("test")); assertEquals(1, list.size()); - assertEquals("test", list.get(0)); + assertEquals("test", list.getFirst()); } @Test @@ -173,7 +173,7 @@ List list = new ArrayList<>(); assumingThat(() -> true, () -> list.add("test")); assertEquals(1, list.size()); - assertEquals("test", list.get(0)); + assertEquals("test", list.getFirst()); } @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationInheritanceTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationInheritanceTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationInheritanceTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationInheritanceTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -26,6 +26,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class StaticNestedTestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,14 +16,23 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; -import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; import java.lang.reflect.Method; import java.util.EmptyStackException; +import java.util.List; import java.util.Stack; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayNameGenerator.IndicativeSentences.SentenceFragment; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContextProvider; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; -import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.testkit.engine.EngineExecutionResults; +import org.junit.platform.testkit.engine.Event; /** * Check generated display names. @@ -146,10 +155,10 @@ } @Test - void checkDisplayNameGeneratedForIndicativeGeneratorTestCase() { + void checkDisplayNameGeneratedForIndicativeGenerator() { check(IndicativeGeneratorTestCase.class, // "CONTAINER: A stack", // - "TEST: A stack, is instantiated with new constructor", // + "TEST: A stack, is instantiated with its constructor", // "CONTAINER: A stack, when new", // "TEST: A stack, when new, throws EmptyStackException when peeked", // "CONTAINER: A stack, when new, after pushing an element to an empty stack", // @@ -158,10 +167,10 @@ } @Test - void checkDisplayNameGeneratedForIndicativeGeneratorWithCustomSeparatorTestCase() { + void checkDisplayNameGeneratedForIndicativeGeneratorWithCustomSeparator() { check(IndicativeGeneratorWithCustomSeparatorTestCase.class, // "CONTAINER: A stack", // - "TEST: A stack >> is instantiated with new constructor", // + "TEST: A stack >> is instantiated with its constructor", // "CONTAINER: A stack >> when new", // "TEST: A stack >> when new >> throws EmptyStackException when peeked", // "CONTAINER: A stack >> when new >> after pushing an element to an empty stack", // @@ -170,6 +179,42 @@ } @Test + void checkDisplayNameGeneratedForIndicativeGeneratorWithCustomSentenceFragments() { + check(IndicativeGeneratorWithCustomSentenceFragmentsTestCase.class, // + "CONTAINER: A stack", // + "TEST: A stack, is instantiated with its constructor", // + "CONTAINER: A stack, when new", // + "TEST: A stack, when new, throws EmptyStackException when peeked", // + "CONTAINER: A stack, when new, after pushing an element to an empty stack", // + "TEST: A stack, when new, after pushing an element to an empty stack, is no longer empty" // + ); + } + + @Test + void blankSentenceFragmentOnClassYieldsError() { + var results = discoverTests(selectClass(BlankSentenceFragmentOnClassTestCase.class)); + + var discoveryIssues = results.getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().severity()).isEqualTo(Severity.ERROR); + assertThat(discoveryIssues.getFirst().cause().orElseThrow()) // + .hasMessage("@SentenceFragment on [%s] must be declared with a non-blank value.", + BlankSentenceFragmentOnClassTestCase.class); + } + + @Test + void blankSentenceFragmentOnMethodYieldsError() throws Exception { + var results = discoverTests(selectMethod(BlankSentenceFragmentOnMethodTestCase.class, "test")); + + var discoveryIssues = results.getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().severity()).isEqualTo(Severity.ERROR); + assertThat(discoveryIssues.getFirst().cause().orElseThrow()) // + .hasMessage("@SentenceFragment on [%s] must be declared with a non-blank value.", + BlankSentenceFragmentOnMethodTestCase.class.getDeclaredMethod("test")); + } + + @Test void displayNameGenerationInheritance() { check(DisplayNameGenerationInheritanceTestCase.InnerNestedTestCase.class, // "CONTAINER: DisplayNameGenerationInheritanceTestCase", // @@ -197,17 +242,76 @@ ); } + @Test + void indicativeSentencesRuntimeEnclosingType() { + check(IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.class, // + "CONTAINER: Scenario 1", // + "CONTAINER: Scenario 1 -> Level 1", // + "CONTAINER: Scenario 1 -> Level 1 -> Level 2", // + "TEST: Scenario 1 -> Level 1 -> Level 2 -> this is a test"// + ); + + check(IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.class, // + "CONTAINER: Scenario 2", // + "CONTAINER: Scenario 2 -> Level 1", // + "CONTAINER: Scenario 2 -> Level 1 -> Level 2", // + "TEST: Scenario 2 -> Level 1 -> Level 2 -> this is a test"// + ); + } + + @Test + void indicativeSentencesOnSubClass() { + check(IndicativeSentencesOnSubClassScenarioOneTestCase.class, // + "CONTAINER: IndicativeSentencesOnSubClassScenarioOneTestCase", // + "CONTAINER: IndicativeSentencesOnSubClassScenarioOneTestCase -> Level 1", // + "CONTAINER: IndicativeSentencesOnSubClassScenarioOneTestCase -> Level 1 -> Level 2", // + "TEST: IndicativeSentencesOnSubClassScenarioOneTestCase -> Level 1 -> Level 2 -> this is a test"// + ); + } + + @Test + void indicativeSentencesOnClassTemplate() { + check(ClassTemplateTestCase.class, // + "CONTAINER: Class template", // + "CONTAINER: [1] Class template", // + "TEST: Class template, some test", // + "CONTAINER: Class template, Regular Nested Test Case", // + "TEST: Class template, Regular Nested Test Case, some nested test", // + "CONTAINER: Class template, Nested Class Template", // + "CONTAINER: [1] Class template, Nested Class Template", // + "TEST: Class template, Nested Class Template, some nested test" // + ); + + assertThat(executeTestsForClass(ClassTemplateTestCase.class).allEvents().started().stream()) // + .map(event -> event.getTestDescriptor().getDisplayName()) // + .containsExactly( // + "JUnit Jupiter", // + "Class template", // + "[1] Class template", // + "Class template, some test", // + "Class template, Regular Nested Test Case", // + "Class template, Regular Nested Test Case, some nested test", // + "Class template, Nested Class Template", // + "[1] Class template, Nested Class Template", // + "Class template, Nested Class Template, some nested test" // + ); + } + private void check(Class testClass, String... expectedDisplayNames) { - var request = request().selectors(selectClass(testClass)).build(); - var descriptors = discoverTests(request).getDescendants(); - assertThat(descriptors).map(this::describe).containsExactlyInAnyOrder(expectedDisplayNames); + var results = executeTestsForClass(testClass); + check(results, expectedDisplayNames); } - private String describe(TestDescriptor descriptor) { - return descriptor.getType() + ": " + descriptor.getDisplayName(); + private void check(EngineExecutionResults results, String[] expectedDisplayNames) { + var descriptors = results.allEvents().started().stream() // + .map(Event::getTestDescriptor) // + .skip(1); // Skip engine descriptor + assertThat(descriptors) // + .map(it -> it.getType() + ": " + it.getDisplayName()) // + .containsExactlyInAnyOrder(expectedDisplayNames); } - // ------------------------------------------------------------------- + // ------------------------------------------------------------------------- static class NoNameGenerator implements DisplayNameGenerator { @@ -217,12 +321,13 @@ } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return "nn"; } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return "nn"; } } @@ -285,8 +390,9 @@ static class UnderscoreStyleInheritedFromSuperClassTestCase extends UnderscoreStyleTestCase { } - // ------------------------------------------------------------------- + // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("A stack") @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) static class StackTestCase { @@ -351,8 +457,9 @@ } } - // ------------------------------------------------------------------- + // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("A stack") @IndicativeSentencesGeneration(generator = DisplayNameGenerator.ReplaceUnderscores.class) static class IndicativeGeneratorTestCase { @@ -360,7 +467,7 @@ Stack stack; @Test - void is_instantiated_with_new_constructor() { + void is_instantiated_with_its_constructor() { new Stack<>(); } @@ -395,8 +502,9 @@ } } - // ------------------------------------------------------------------- + // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("A stack") @IndicativeSentencesGeneration(separator = " >> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) static class IndicativeGeneratorWithCustomSeparatorTestCase { @@ -404,7 +512,7 @@ Stack stack; @Test - void is_instantiated_with_new_constructor() { + void is_instantiated_with_its_constructor() { new Stack<>(); } @@ -438,4 +546,125 @@ } } } + + // ------------------------------------------------------------------------- + + @SuppressWarnings("JUnitMalformedDeclaration") + @SentenceFragment("A stack") + @IndicativeSentencesGeneration + static class IndicativeGeneratorWithCustomSentenceFragmentsTestCase { + + Stack stack; + + @SentenceFragment("is instantiated with its constructor") + @Test + void instantiateViaConstructor() { + new Stack<>(); + } + + @SentenceFragment("when new") + @Nested + class NewStackTestCase { + + @BeforeEach + void createNewStack() { + stack = new Stack<>(); + } + + @SentenceFragment("throws EmptyStackException when peeked") + @Test + void throwsExceptionWhenPeeked() { + assertThrows(EmptyStackException.class, () -> stack.peek()); + } + + @SentenceFragment("after pushing an element to an empty stack") + @Nested + class ElementPushedOntoStackTestCase { + + String anElement = "an element"; + + @BeforeEach + void pushElementOntoStack() { + stack.push(anElement); + } + + @SentenceFragment("is no longer empty") + @Test + void nonEmptyStack() { + assertFalse(stack.isEmpty()); + } + } + } + } + + // ------------------------------------------------------------------------- + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(ClassTemplateTestCase.Once.class) + @DisplayName("Class template") + @IndicativeSentencesGeneration(generator = DisplayNameGenerator.ReplaceUnderscores.class) + @TestClassOrder(ClassOrderer.OrderAnnotation.class) + static class ClassTemplateTestCase { + + @Test + void some_test() { + } + + @Nested + @Order(1) + class Regular_Nested_Test_Case { + @Test + void some_nested_test() { + } + } + + @Nested + @Order(2) + @ClassTemplate + class Nested_Class_Template { + @Test + void some_nested_test() { + } + } + + private static class Once implements ClassTemplateInvocationContextProvider { + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts( + ExtensionContext context) { + return Stream.of(new ClassTemplateInvocationContext() { + @Override + public String getDisplayName(int invocationIndex) { + return "%s %s".formatted(ClassTemplateInvocationContext.super.getDisplayName(invocationIndex), + context.getDisplayName()); + } + }); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @IndicativeSentencesGeneration + @SentenceFragment("") + static class BlankSentenceFragmentOnClassTestCase { + @Test + void test() { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @IndicativeSentencesGeneration + static class BlankSentenceFragmentOnMethodTestCase { + @SentenceFragment("\t") + @Test + void test() { + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DynamicTestTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DynamicTestTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DynamicTestTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/DynamicTestTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/EnigmaThrowable.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/EnigmaThrowable.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/EnigmaThrowable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/EnigmaThrowable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/FailAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/FailAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/FailAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/FailAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesGenerationInheritanceTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesGenerationInheritanceTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesGenerationInheritanceTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesGenerationInheritanceTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -26,6 +26,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class StaticNestedTestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesNestedTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesNestedTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesNestedTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesNestedTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassScenarioOneTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassScenarioOneTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassScenarioOneTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassScenarioOneTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +/** + * @since 5.12 + */ +@IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) +class IndicativeSentencesOnSubClassScenarioOneTestCase extends IndicativeSentencesOnSubClassTestCase { +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesOnSubClassTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +/** + * @since 5.12 + */ +@DisplayName("Base Scenario") +abstract class IndicativeSentencesOnSubClassTestCase { + + @Nested + class Level_1 { + + @Nested + class Level_2 { + + @Test + void this_is_a_test() { + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +/** + * @since 5.12 + */ +@DisplayName("Scenario 1") +class IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase + extends IndicativeSentencesRuntimeEnclosingTypeTestCase { +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +/** + * @since 5.12 + */ +@DisplayName("Scenario 2") +class IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase + extends IndicativeSentencesRuntimeEnclosingTypeTestCase { +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; + +/** + * @since 5.12 + */ +@DisplayName("Base Scenario") +@IndicativeSentencesGeneration(separator = " -> ", generator = ReplaceUnderscores.class) +abstract class IndicativeSentencesRuntimeEnclosingTypeTestCase { + + @Nested + class Level_1 { + + @Nested + class Level_2 { + + @Test + void this_is_a_test() { + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesTopLevelTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesTopLevelTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesTopLevelTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesTopLevelTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IterableFactory.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IterableFactory.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IterableFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/IterableFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/MediaTypeTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/MediaTypeTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/MediaTypeTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/MediaTypeTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,156 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullOrBlankFor; + +import java.nio.charset.Charset; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * Unit tests for {@link MediaType}. + * + * @since 1.14 + * @see org.junit.jupiter.api.extension.DeprecatedMediaTypeTests + */ +class MediaTypeTests { + + @Test + void pseudoSealedType() { + + class CustomMediaType extends MediaType { + + CustomMediaType(String value) { + super(value); + } + + CustomMediaType(String type, String subtype, Charset charset) { + super(type, subtype, charset); + } + } + + String message = "Type '%s' is not permitted to extend MediaType".formatted(CustomMediaType.class.getName()); + + assertThatIllegalStateException()// + .isThrownBy(() -> new CustomMediaType("text/plain"))// + .withMessage(message); + + assertThatIllegalStateException()// + .isThrownBy(() -> new CustomMediaType("text", "plain", UTF_8))// + .withMessage(message); + } + + @Test + void equals() { + var mediaType1 = MediaType.TEXT_PLAIN; + var mediaType2 = MediaType.parse(mediaType1.toString()); + var mediaType3 = MediaType.APPLICATION_JSON; + + assertEqualsAndHashCode(mediaType1, mediaType2, mediaType3); + } + + @Nested + class ParseTests { + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void parseWithNullOrBlankMediaType(String mediaType) { + assertPreconditionViolationNotNullOrBlankFor("value", () -> MediaType.parse(mediaType)); + } + + @ParameterizedTest + @ValueSource(strings = { "/", " / ", "type", "type/", "/subtype" }) + void parseWithInvalidMediaType(String mediaType) { + assertPreconditionViolationFor(() -> MediaType.parse(mediaType))// + .withMessage("Invalid media type: '%s'", mediaType.strip()); + } + + @ParameterizedTest + @ValueSource(strings = { "text/plain", " text/plain ", "text/plain; charset=UTF-8", + "\t text/plain; charset=UTF-8 \t" }) + void parse(String value) { + assertThat(MediaType.parse(value)).hasToString(value.strip()); + } + } + + @Nested + class CreateTests { + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankType(String type) { + assertPreconditionViolationNotNullOrBlankFor("type", () -> MediaType.create(type, "json")); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankTypeAndCharset(String type) { + assertPreconditionViolationNotNullOrBlankFor("type", () -> MediaType.create(type, "json", UTF_8)); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankSubtype(String subtype) { + assertPreconditionViolationNotNullOrBlankFor("subtype", () -> MediaType.create("application", subtype)); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankSubtypeAndCharset(String subtype) { + assertPreconditionViolationNotNullOrBlankFor("subtype", + () -> MediaType.create("application", subtype, UTF_8)); + } + + @Test + void createWithNullCharset() { + assertPreconditionViolationNotNullFor("charset", () -> MediaType.create("application", "json", null)); + } + + @ParameterizedTest + @ValueSource(strings = { "/", " / ", "type/", "/subtype" }) + void createWithInvalidType(String type) { + assertPreconditionViolationFor(() -> MediaType.create(type, "json"))// + .withMessage("Invalid media type: '%s/json'", type.strip()); + } + + @ParameterizedTest + @ValueSource(strings = { "/", " / ", "type/", "/subtype" }) + void createWithInvalidSubtype(String subtype) { + assertPreconditionViolationFor(() -> MediaType.create("application", subtype))// + .withMessage("Invalid media type: 'application/%s'", subtype.strip()); + } + + @Test + void create() { + assertThat(MediaType.create("application", "json")).hasToString("application/json"); + } + + @Test + void createWithCharset() { + assertThat(MediaType.create("text", "plain", UTF_8)).hasToString("text/plain; charset=UTF-8"); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,13 +10,13 @@ package org.junit.jupiter.api.condition; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.platform.commons.util.ReflectionUtils.findMethod; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; -import static org.junit.platform.commons.util.ReflectionUtils.newInstance; +import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN; +import static org.junit.platform.commons.support.ReflectionSupport.findMethod; +import static org.junit.platform.commons.support.ReflectionSupport.findMethods; +import static org.junit.platform.commons.support.ReflectionSupport.newInstance; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -59,13 +59,13 @@ void ensureAllTestMethodsAreCovered() { Predicate isTestMethod = method -> method.isAnnotationPresent(Test.class); - List methodsToTest = findMethods(getTestClass(), isTestMethod).stream()// - .map(Method::getName).sorted().collect(toList()); + List methodsToTest = findMethods(getTestClass(), isTestMethod, TOP_DOWN).stream()// + .map(Method::getName).sorted().toList(); - List localTestMethods = findMethods(getClass(), isTestMethod).stream()// - .map(Method::getName).sorted().collect(toList()); + List localTestMethods = findMethods(getClass(), isTestMethod, TOP_DOWN).stream()// + .map(Method::getName).sorted().toList(); - assertThat(localTestMethods).isEqualTo(methodsToTest); + assertThat(localTestMethods).containsExactlyElementsOf(methodsToTest); } @BeforeEach diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/ConditionEvaluationResultTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/ConditionEvaluationResultTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/ConditionEvaluationResultTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/ConditionEvaluationResultTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.condition; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * Unit tests for {@link ConditionEvaluationResult}. + * + * @since 5.13.3 + */ +class ConditionEvaluationResultTests { + + @Test + void enabledWithReason() { + var result = ConditionEvaluationResult.enabled("reason"); + + assertThat(result.isDisabled()).isFalse(); + assertThat(result.getReason()).contains("reason"); + assertThat(result).asString()// + .isEqualTo("ConditionEvaluationResult [enabled = true, reason = 'reason']"); + } + + @BlankReasonsTest + void enabledWithBlankReason(String reason) { + var result = ConditionEvaluationResult.enabled(reason); + + assertThat(result.isDisabled()).isFalse(); + assertThat(result.getReason()).isEmpty(); + assertThat(result).asString()// + .isEqualTo("ConditionEvaluationResult [enabled = true, reason = '']"); + } + + @Test + void disabledWithDefaultReason() { + var result = ConditionEvaluationResult.disabled("default"); + + assertThat(result.isDisabled()).isTrue(); + assertThat(result.getReason()).contains("default"); + assertThat(result).asString()// + .isEqualTo("ConditionEvaluationResult [enabled = false, reason = 'default']"); + } + + @BlankReasonsTest + void disabledWithBlankDefaultReason(String reason) { + var result = ConditionEvaluationResult.disabled(reason); + + assertThat(result.isDisabled()).isTrue(); + assertThat(result.getReason()).isEmpty(); + assertThat(result).asString()// + .isEqualTo("ConditionEvaluationResult [enabled = false, reason = '']"); + } + + @BlankReasonsTest + void disabledWithDefaultReasonAndBlankCustomReason(String customReason) { + var result = ConditionEvaluationResult.disabled("default", customReason); + + assertThat(result.isDisabled()).isTrue(); + assertThat(result.getReason()).contains("default"); + assertThat(result).asString()// + .isEqualTo("ConditionEvaluationResult [enabled = false, reason = 'default']"); + } + + @BlankReasonsTest + void disabledWithBlankDefaultReasonAndCustomReason(String reason) { + var result = ConditionEvaluationResult.disabled(reason, "custom"); + + assertThat(result.isDisabled()).isTrue(); + assertThat(result.getReason()).contains("custom"); + assertThat(result).asString().isEqualTo("ConditionEvaluationResult [enabled = false, reason = 'custom']"); + } + + @BlankReasonsTest + void disabledWithBlankDefaultReasonAndBlankCustomReason(String reason) { + // We intentionally use the reason as both the default and custom reason. + var result = ConditionEvaluationResult.disabled(reason, reason); + + assertThat(result.isDisabled()).isTrue(); + assertThat(result.getReason()).isEmpty(); + assertThat(result).asString()// + .isEqualTo("ConditionEvaluationResult [enabled = false, reason = '']"); + } + + @Test + void disabledWithDefaultReasonAndCustomReason() { + disabledWithDefaultReasonAndCustomReason("default", "custom"); + } + + @Test + void disabledWithDefaultReasonAndCustomReasonWithLeadingAndTrailingWhitespace() { + disabledWithDefaultReasonAndCustomReason(" default ", " custom "); + } + + private static void disabledWithDefaultReasonAndCustomReason(String defaultReason, String customReason) { + var result = ConditionEvaluationResult.disabled(defaultReason, customReason); + + assertThat(result.isDisabled()).isTrue(); + assertThat(result.getReason()).contains("default ==> custom"); + assertThat(result).asString()// + .isEqualTo("ConditionEvaluationResult [enabled = false, reason = 'default ==> custom']"); + } + + @Retention(RetentionPolicy.RUNTIME) + @ParameterizedTest(name = "[{index}] reason=\"{0}\"") + @NullSource + @ValueSource(strings = { "", " ", " ", "\t", "\n" }) + @interface BlankReasonsTest { + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.jupiter.api.condition; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava10; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava11; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava12; @@ -24,10 +23,10 @@ import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava8; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava9; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onKnownVersion; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.PreconditionViolationException; /** * Unit tests for {@link DisabledForJreRange}. @@ -39,6 +38,8 @@ */ class DisabledForJreRangeConditionTests extends AbstractExecutionConditionTests { + private static final String JAVA_VERSION = System.getProperty("java.version"); + @Override protected ExecutionCondition getExecutionCondition() { return new DisabledForJreRangeCondition(); @@ -64,66 +65,226 @@ */ @Test void defaultValues() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(this::evaluateCondition)// - .withMessageContaining("You must declare a non-default value for min or max in @DisabledForJreRange"); + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "You must declare a non-default value for the minimum or maximum value in @DisabledForJreRange"); } /** - * @see DisabledForJreRangeIntegrationTests#java17() + * @see DisabledForJreRangeIntegrationTests#effectiveJreDefaultValues() */ @Test - void java17() { - evaluateCondition(); - assertDisabledOnCurrentJreIf(onJava17()); + void effectiveJreDefaultValues() { + defaultValues(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#effectiveVersionDefaultValues() + */ + @Test + void effectiveVersionDefaultValues() { + defaultValues(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#min8() + */ + @Test + void min8() { + defaultValues(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minVersion8() + */ + @Test + void minVersion8() { + defaultValues(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#maxOther() + */ + @Test + void maxOther() { + defaultValues(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#maxVersionMaxInteger() + */ + @Test + void maxVersionMaxInteger() { + defaultValues(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minVersion7() + */ + @Test + void minVersion7() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("@DisabledForJreRange's minVersion [7] must be greater than or equal to 8"); + } + + /** + * @see DisabledForJreRangeIntegrationTests#maxVersion7() + */ + @Test + void maxVersion7() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("@DisabledForJreRange's maxVersion [7] must be greater than or equal to 8"); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minAndMinVersion() + */ + @Test + void minAndMinVersion() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "@DisabledForJreRange's minimum value must be configured with either a JRE enum constant or numeric version, but not both"); + } + + /** + * @see DisabledForJreRangeIntegrationTests#maxAndMaxVersion() + */ + @Test + void maxAndMaxVersion() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "@DisabledForJreRange's maximum value must be configured with either a JRE enum constant or numeric version, but not both"); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minGreaterThanMax() + */ + @Test + void minGreaterThanMax() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "@DisabledForJreRange's minimum value [21] must be less than or equal to its maximum value [11]"); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minGreaterThanMaxVersion() + */ + @Test + void minGreaterThanMaxVersion() { + minGreaterThanMax(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minVersionGreaterThanMaxVersion() + */ + @Test + void minVersionGreaterThanMaxVersion() { + minGreaterThanMax(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minVersionGreaterThanMax() + */ + @Test + void minVersionGreaterThanMax() { + minGreaterThanMax(); } /** - * @see DisabledForJreRangeIntegrationTests#java18to19() + * @see DisabledForJreRangeIntegrationTests#min18() */ @Test - void java18to19() { + void min18() { evaluateCondition(); - assertDisabledOnCurrentJreIf(onJava18() || onJava19()); - assertCustomDisabledReasonIs("Disabled on some JRE"); + assertDisabledOnCurrentJreIf(!onJava17()); } /** - * @see DisabledForJreRangeIntegrationTests#javaMax18() + * @see DisabledForJreRangeIntegrationTests#minVersion18() */ @Test - void javaMax18() { + void minVersion18() { + min18(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#max18() + */ + @Test + void max18() { evaluateCondition(); assertDisabledOnCurrentJreIf(onJava8() || onJava9() || onJava10() || onJava11() || onJava12() || onJava13() || onJava14() || onJava15() || onJava16() || onJava17() || onJava18()); } /** - * @see DisabledForJreRangeIntegrationTests#javaMin18() + * @see DisabledForJreRangeIntegrationTests#maxVersion18() + */ + @Test + void maxVersion18() { + max18(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#min17Max17() */ @Test - void javaMin18() { + void min17Max17() { evaluateCondition(); - assertDisabledOnCurrentJreIf(!onJava17()); + assertDisabledOnCurrentJreIf(onJava17()); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minVersion17MaxVersion17() + */ + @Test + void minVersion17MaxVersion17() { + min17Max17(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#min18Max19() + */ + @Test + void min18Max19() { + evaluateCondition(); + assertDisabledOnCurrentJreIf(onJava18() || onJava19()); + assertCustomDisabledReasonIs("Disabled on Java 18 & 19"); } /** - * @see DisabledForJreRangeIntegrationTests#other() + * @see DisabledForJreRangeIntegrationTests#minVersion18MaxVersion19() */ @Test - void other() { + void minVersion18MaxVersion19() { + min18Max19(); + } + + /** + * @see DisabledForJreRangeIntegrationTests#minOtherMaxOther() + */ + @Test + void minOtherMaxOther() { evaluateCondition(); assertDisabledOnCurrentJreIf(!onKnownVersion()); } + /** + * @see DisabledForJreRangeIntegrationTests#minMaxIntegerMaxMaxInteger() + */ + @Test + void minMaxIntegerMaxMaxInteger() { + minOtherMaxOther(); + } + private void assertDisabledOnCurrentJreIf(boolean condition) { if (condition) { assertDisabled(); - assertReasonContains("Disabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Disabled on JRE version: " + JAVA_VERSION); } else { assertEnabled(); - assertReasonContains("Enabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Enabled on JRE version: " + JAVA_VERSION); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,9 +13,12 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.condition.JRE.JAVA_11; import static org.junit.jupiter.api.condition.JRE.JAVA_17; import static org.junit.jupiter.api.condition.JRE.JAVA_18; import static org.junit.jupiter.api.condition.JRE.JAVA_19; +import static org.junit.jupiter.api.condition.JRE.JAVA_21; +import static org.junit.jupiter.api.condition.JRE.JAVA_8; import static org.junit.jupiter.api.condition.JRE.OTHER; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava10; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava11; @@ -35,7 +38,7 @@ import org.junit.jupiter.api.Test; /** - * Integration tests for {@link DisabledForJreRange}. + * Integration tests for {@link DisabledForJreRange @DisabledForJreRange}. * * @since 5.6 */ @@ -53,35 +56,163 @@ } @Test - @DisabledForJreRange(min = JAVA_17, max = JAVA_17) - void java17() { - assertFalse(onJava17()); + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(min = JAVA_8, max = OTHER) + void effectiveJreDefaultValues() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(minVersion = 8, maxVersion = Integer.MAX_VALUE) + void effectiveVersionDefaultValues() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(min = JAVA_8) + void min8() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(minVersion = 8) + void minVersion8() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(max = OTHER) + void maxOther() { + fail("should result in a configuration exception"); } @Test - @DisabledForJreRange(min = JAVA_18, max = JAVA_19, disabledReason = "Disabled on some JRE") - void java18to19() { + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(maxVersion = Integer.MAX_VALUE) + void maxVersionMaxInteger() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(minVersion = 7) + void minVersion7() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(maxVersion = 7) + void maxVersion7() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(min = JAVA_18, minVersion = 21) + void minAndMinVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(max = JAVA_18, maxVersion = 21) + void maxAndMaxVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(min = JAVA_21, max = JAVA_11) + void minGreaterThanMax() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(min = JAVA_21, maxVersion = 11) + void minGreaterThanMaxVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(minVersion = 21, maxVersion = 11) + void minVersionGreaterThanMaxVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @DisabledForJreRange(minVersion = 21, max = JAVA_11) + void minVersionGreaterThanMax() { + fail("should result in a configuration exception"); + } + + @Test + @DisabledForJreRange(min = JAVA_18) + void min18() { assertFalse(onJava18() || onJava19()); + assertTrue(onJava17()); + } + + @Test + @DisabledForJreRange(minVersion = 18) + void minVersion18() { + min18(); } @Test @DisabledForJreRange(max = JAVA_18) - void javaMax18() { + void max18() { assertFalse(onJava8() || onJava9() || onJava10() || onJava11() || onJava12() || onJava13() || onJava14() || onJava15() || onJava16() || onJava17() || onJava18()); } @Test - @DisabledForJreRange(min = JAVA_18) - void javaMin18() { + @DisabledForJreRange(maxVersion = 18) + void maxVersion18() { + max18(); + } + + @Test + @DisabledForJreRange(min = JAVA_17, max = JAVA_17) + void min17Max17() { + assertFalse(onJava17()); + } + + @Test + @DisabledForJreRange(minVersion = 17, maxVersion = 17) + void minVersion17MaxVersion17() { + min17Max17(); + } + + @Test + @DisabledForJreRange(min = JAVA_18, max = JAVA_19, disabledReason = "Disabled on Java 18 & 19") + void min18Max19() { assertFalse(onJava18() || onJava19()); - assertTrue(onJava17()); + } + + @Test + @DisabledForJreRange(minVersion = 18, maxVersion = 19, disabledReason = "Disabled on Java 18 & 19") + void minVersion18MaxVersion19() { + min18Max19(); } @Test @DisabledForJreRange(min = OTHER, max = OTHER) - void other() { + void minOtherMaxOther() { assertTrue(onKnownVersion()); } + @Test + @DisabledForJreRange(minVersion = Integer.MAX_VALUE, maxVersion = Integer.MAX_VALUE) + void minMaxIntegerMaxMaxInteger() { + minOtherMaxOther(); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionClassLoaderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionClassLoaderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionClassLoaderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionClassLoaderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,8 +21,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.test.TestClassLoader; -import org.junit.platform.commons.util.ReflectionUtils; /** * Tests for {@link DisabledIfCondition} using custom {@link ClassLoader} arrangements. @@ -40,7 +40,7 @@ assertThat(testClass.getClassLoader()).isSameAs(testClassLoader); ExtensionContext context = mock(); - Method annotatedMethod = ReflectionUtils.findMethod(getClass(), "enabledMethod").get(); + Method annotatedMethod = ReflectionSupport.findMethod(getClass(), "enabledMethod").get(); when(context.getElement()).thenReturn(Optional.of(annotatedMethod)); doReturn(testClass).when(context).getRequiredTestClass(); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariableIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledIfSystemPropertyIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledOnOsIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.jupiter.api.condition; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava10; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava11; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava12; @@ -21,16 +20,23 @@ import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava17; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava18; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava19; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava20; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava21; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava22; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava23; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava24; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava25; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava26; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava8; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava9; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onKnownVersion; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.platform.commons.PreconditionViolationException; /** - * Unit tests for {@link EnabledForJreRange}. + * Unit tests for {@link EnabledForJreRange @EnabledForJreRange}. * *

    Note that test method names MUST match the test method names in * {@link EnabledForJreRangeIntegrationTests}. @@ -39,6 +45,8 @@ */ class EnabledForJreRangeConditionTests extends AbstractExecutionConditionTests { + private static final String JAVA_VERSION = System.getProperty("java.version"); + @Override protected ExecutionCondition getExecutionCondition() { return new EnabledForJreRangeCondition(); @@ -64,65 +72,277 @@ */ @Test void defaultValues() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(this::evaluateCondition)// - .withMessageContaining("You must declare a non-default value for min or max in @EnabledForJreRange"); + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "You must declare a non-default value for the minimum or maximum value in @EnabledForJreRange"); } /** - * @see EnabledForJreRangeIntegrationTests#java17() + * @see EnabledForJreRangeIntegrationTests#effectiveJreDefaultValues() */ @Test - void java17() { + void effectiveJreDefaultValues() { + defaultValues(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#effectiveVersionDefaultValues() + */ + @Test + void effectiveVersionDefaultValues() { + defaultValues(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#min8() + */ + @Test + void min8() { + defaultValues(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersion8() + */ + @Test + void minVersion8() { + defaultValues(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#maxOther() + */ + @Test + void maxOther() { + defaultValues(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#maxVersionMaxInteger() + */ + @Test + void maxVersionMaxInteger() { + defaultValues(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersion7() + */ + @Test + void minVersion7() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("@EnabledForJreRange's minVersion [7] must be greater than or equal to 8"); + } + + /** + * @see EnabledForJreRangeIntegrationTests#maxVersion7() + */ + @Test + void maxVersion7() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage("@EnabledForJreRange's maxVersion [7] must be greater than or equal to 8"); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minAndMinVersion() + */ + @Test + void minAndMinVersion() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "@EnabledForJreRange's minimum value must be configured with either a JRE enum constant or numeric version, but not both"); + } + + /** + * @see EnabledForJreRangeIntegrationTests#maxAndMaxVersion() + */ + @Test + void maxAndMaxVersion() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "@EnabledForJreRange's maximum value must be configured with either a JRE enum constant or numeric version, but not both"); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minGreaterThanMax() + */ + @Test + void minGreaterThanMax() { + assertPreconditionViolationFor(this::evaluateCondition)// + .withMessage( + "@EnabledForJreRange's minimum value [21] must be less than or equal to its maximum value [11]"); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minGreaterThanMaxVersion() + */ + @Test + void minGreaterThanMaxVersion() { + minGreaterThanMax(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersionGreaterThanMaxVersion() + */ + @Test + void minVersionGreaterThanMaxVersion() { + minGreaterThanMax(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersionGreaterThanMax() + */ + @Test + void minVersionGreaterThanMax() { + minGreaterThanMax(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#min20() + */ + @Test + void min20() { evaluateCondition(); - assertEnabledOnCurrentJreIf(onJava17()); + assertEnabledOnCurrentJreIf( + onJava20() || onJava21() || onJava22() || onJava23() || onJava24() || onJava25() || onJava26()); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersion20() + */ + @Test + void minVersion20() { + min20(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#max21() + */ + @Test + void max21() { + evaluateCondition(); + assertEnabledOnCurrentJreIf( + onJava8() || onJava9() || onJava10() || onJava11() || onJava12() || onJava13() || onJava14() || onJava15() + || onJava16() || onJava17() || onJava18() || onJava19() || onJava20() || onJava21()); + } + + /** + * @see EnabledForJreRangeIntegrationTests#maxVersion21() + */ + @Test + void maxVersion21() { + max21(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#min8Max21() + */ + @Test + void min8Max21() { + max21(); } /** - * @see EnabledForJreRangeIntegrationTests#java18to19() + * @see EnabledForJreRangeIntegrationTests#min17Max17() */ @Test - void java18to19() { + void min17Max17() { evaluateCondition(); - assertEnabledOnCurrentJreIf(onJava18() || onJava19()); + assertEnabledOnCurrentJreIf(onJava17()); + } + + /** + * @see EnabledForJreRangeIntegrationTests#min17MaxVersion17() + */ + @Test + void min17MaxVersion17() { + min17Max17(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersion17Max17() + */ + @Test + void minVersion17Max17() { + min17Max17(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersion17MaxVersion17() + */ + @Test + void minVersion17MaxVersion17() { + min17Max17(); } /** - * @see EnabledForJreRangeIntegrationTests#javaMax18() + * @see EnabledForJreRangeIntegrationTests#min20Max21() */ @Test - void javaMax18() { + void min20Max21() { evaluateCondition(); - assertEnabledOnCurrentJreIf(onJava8() || onJava9() || onJava10() || onJava11() || onJava12() || onJava13() - || onJava14() || onJava15() || onJava16() || onJava17() || onJava18()); + assertEnabledOnCurrentJreIf(onJava20() || onJava21()); + } + + /** + * @see EnabledForJreRangeIntegrationTests#min20MaxVersion21() + */ + @Test + void min20MaxVersion21() { + min20Max21(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersion20Max21() + */ + @Test + void minVersion20Max21() { + min20Max21(); + } + + /** + * @see EnabledForJreRangeIntegrationTests#minVersion20MaxVersion21() + */ + @Test + void minVersion20MaxVersion21() { + min20Max21(); } /** - * @see EnabledForJreRangeIntegrationTests#javaMin18() + * @see EnabledForJreRangeIntegrationTests#minVersion17MaxVersionMaxInteger() */ @Test - void javaMin18() { + void minVersion17MaxVersionMaxInteger() { evaluateCondition(); - assertEnabledOnCurrentJreIf(!(onJava17())); + assertEnabledOnCurrentJreIf(onJava17() || onJava18() || onJava19() || onJava20() || onJava21() || onJava22() + || onJava23() || onJava24() || onJava25() || onJava26()); } /** - * @see EnabledForJreRangeIntegrationTests#other() + * @see EnabledForJreRangeIntegrationTests#minOtherMaxOther() */ @Test - void other() { + void minOtherMaxOther() { evaluateCondition(); assertEnabledOnCurrentJreIf(!onKnownVersion()); } + /** + * @see EnabledForJreRangeIntegrationTests#minMaxIntegerMaxMaxInteger() + */ + @Test + void minMaxIntegerMaxMaxInteger() { + minOtherMaxOther(); + } + private void assertEnabledOnCurrentJreIf(boolean condition) { if (condition) { assertEnabled(); - assertReasonContains("Enabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Enabled on JRE version: " + JAVA_VERSION); } else { assertDisabled(); - assertReasonContains("Disabled on JRE version: " + System.getProperty("java.version")); + assertReasonContains("Disabled on JRE version: " + JAVA_VERSION); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,9 +13,12 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.condition.JRE.JAVA_11; import static org.junit.jupiter.api.condition.JRE.JAVA_17; import static org.junit.jupiter.api.condition.JRE.JAVA_18; -import static org.junit.jupiter.api.condition.JRE.JAVA_19; +import static org.junit.jupiter.api.condition.JRE.JAVA_20; +import static org.junit.jupiter.api.condition.JRE.JAVA_21; +import static org.junit.jupiter.api.condition.JRE.JAVA_8; import static org.junit.jupiter.api.condition.JRE.OTHER; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava10; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava11; @@ -27,6 +30,10 @@ import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava17; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava18; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava19; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava20; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava21; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava22; +import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava23; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava8; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onJava9; import static org.junit.jupiter.api.condition.JavaVersionPredicates.onKnownVersion; @@ -35,12 +42,14 @@ import org.junit.jupiter.api.Test; /** - * Integration tests for {@link EnabledForJreRange}. + * Integration tests for {@link EnabledForJreRange @EnabledForJreRange}. * * @since 5.6 */ class EnabledForJreRangeIntegrationTests { + private static final JRE CURRENT_JRE = JRE.currentJre(); + @Test @Disabled("Only used in a unit test via reflection") void enabledBecauseAnnotationIsNotPresent() { @@ -54,38 +63,210 @@ } @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(min = JAVA_8, max = OTHER) + void effectiveJreDefaultValues() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(minVersion = 8, maxVersion = Integer.MAX_VALUE) + void effectiveVersionDefaultValues() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(min = JAVA_8) + void min8() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(minVersion = 8) + void minVersion8() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(max = OTHER) + void maxOther() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(maxVersion = Integer.MAX_VALUE) + void maxVersionMaxInteger() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(minVersion = 7) + void minVersion7() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(maxVersion = 7) + void maxVersion7() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(min = JAVA_18, minVersion = 21) + void minAndMinVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(max = JAVA_18, maxVersion = 21) + void maxAndMaxVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(min = JAVA_21, max = JAVA_11) + void minGreaterThanMax() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(min = JAVA_21, maxVersion = 11) + void minGreaterThanMaxVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(minVersion = 21, maxVersion = 11) + void minVersionGreaterThanMaxVersion() { + fail("should result in a configuration exception"); + } + + @Test + @Disabled("Only used in a unit test via reflection") + @EnabledForJreRange(minVersion = 21, max = JAVA_11) + void minVersionGreaterThanMax() { + fail("should result in a configuration exception"); + } + + @Test + @EnabledForJreRange(min = JAVA_20) + void min20() { + assertTrue(onKnownVersion()); + assertTrue(JRE.currentVersionNumber() >= 20); + assertTrue(CURRENT_JRE.compareTo(JAVA_20) >= 0); + assertTrue(CURRENT_JRE.version() >= 20); + assertFalse(onJava19()); + } + + @Test + @EnabledForJreRange(minVersion = 20) + void minVersion20() { + min20(); + } + + @Test + @EnabledForJreRange(max = JAVA_21) + void max21() { + assertTrue(onKnownVersion()); + assertTrue(JRE.currentVersionNumber() <= 21); + assertTrue(CURRENT_JRE.compareTo(JAVA_21) <= 0); + assertTrue(CURRENT_JRE.version() <= 21); + + assertTrue(onJava8() || onJava9() || onJava10() || onJava11() || onJava12() || onJava13() || onJava14() + || onJava15() || onJava16() || onJava17() || onJava18() || onJava19() || onJava20() || onJava21()); + assertFalse(onJava22()); + } + + @Test + @EnabledForJreRange(maxVersion = 21) + void maxVersion21() { + max21(); + } + + @Test + @EnabledForJreRange(min = JAVA_8, max = JAVA_21) + void min8Max21() { + max21(); + } + + @Test @EnabledForJreRange(min = JAVA_17, max = JAVA_17) - void java17() { + void min17Max17() { assertTrue(onJava17()); } @Test - @EnabledForJreRange(min = JAVA_18, max = JAVA_19) - void java18to19() { - assertTrue(onJava18() || onJava19()); - assertFalse(onJava17()); + @EnabledForJreRange(min = JAVA_17, maxVersion = 17) + void min17MaxVersion17() { + min17Max17(); } @Test - @EnabledForJreRange(max = JAVA_18) - void javaMax18() { - assertTrue(onJava8() || onJava9() || onJava10() || onJava11() || onJava12() || onJava13() || onJava14() - || onJava15() || onJava16() || onJava17() || onJava18()); - assertFalse(onJava19()); + @EnabledForJreRange(minVersion = 17, max = JAVA_17) + void minVersion17Max17() { + min17Max17(); } @Test - @EnabledForJreRange(min = JAVA_18) - void javaMin18() { + @EnabledForJreRange(minVersion = 17, maxVersion = 17) + void minVersion17MaxVersion17() { + min17Max17(); + } + + @Test + @EnabledForJreRange(min = JAVA_20, max = JAVA_21) + void min20Max21() { + assertTrue(onJava20() || onJava21()); + assertFalse(onJava17() || onJava23()); + } + + @Test + @EnabledForJreRange(min = JAVA_20, maxVersion = 21) + void min20MaxVersion21() { + min20Max21(); + } + + @Test + @EnabledForJreRange(minVersion = 20, max = JAVA_21) + void minVersion20Max21() { + min20Max21(); + } + + @Test + @EnabledForJreRange(minVersion = 20, maxVersion = 21) + void minVersion20MaxVersion21() { + min20Max21(); + } + + @Test + @EnabledForJreRange(minVersion = 17, maxVersion = Integer.MAX_VALUE) + void minVersion17MaxVersionMaxInteger() { assertTrue(onKnownVersion()); - assertTrue(JRE.currentVersion().compareTo(JAVA_18) >= 0); - assertFalse(onJava17()); + assertTrue(JRE.currentVersionNumber() >= 17); } @Test @EnabledForJreRange(min = OTHER, max = OTHER) - void other() { + void minOtherMaxOther() { assertFalse(onKnownVersion()); } + @Test + @EnabledForJreRange(minVersion = Integer.MAX_VALUE, maxVersion = Integer.MAX_VALUE) + void minMaxIntegerMaxMaxInteger() { + minOtherMaxOther(); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionClassLoaderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionClassLoaderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionClassLoaderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionClassLoaderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -21,8 +21,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.test.TestClassLoader; -import org.junit.platform.commons.util.ReflectionUtils; /** * Tests for {@link EnabledIfCondition} using custom {@link ClassLoader} arrangements. @@ -40,7 +40,7 @@ assertThat(testClass.getClassLoader()).isSameAs(testClassLoader); ExtensionContext context = mock(); - Method annotatedMethod = ReflectionUtils.findMethod(getClass(), "enabledMethod").get(); + Method annotatedMethod = ReflectionSupport.findMethod(getClass(), "enabledMethod").get(); when(context.getElement()).thenReturn(Optional.of(annotatedMethod)); doReturn(testClass).when(context).getRequiredTestClass(); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariableIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledIfSystemPropertyIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledOnOsIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/JRETests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/JRETests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/JRETests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/JRETests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,13 +10,16 @@ package org.junit.jupiter.api.condition; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.condition.JRE.JAVA_17; import static org.junit.jupiter.api.condition.JRE.JAVA_18; import static org.junit.jupiter.api.condition.JRE.JAVA_19; import static org.junit.jupiter.api.condition.JRE.JAVA_20; import static org.junit.jupiter.api.condition.JRE.JAVA_21; import static org.junit.jupiter.api.condition.JRE.JAVA_22; +import static org.junit.jupiter.api.condition.JRE.JAVA_23; +import static org.junit.jupiter.api.condition.JRE.JAVA_24; +import static org.junit.jupiter.api.condition.JRE.JAVA_25; import static org.junit.jupiter.api.condition.JRE.OTHER; import org.junit.jupiter.api.Test; @@ -28,45 +31,136 @@ */ public class JRETests { + private static final JRE CURRENT_JRE = JRE.currentJre(); + @Test @EnabledOnJre(JAVA_17) - void java17() { - assertEquals(JAVA_17, JRE.currentVersion()); + void jre17() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_17); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(17); } @Test @EnabledOnJre(JAVA_18) - void java18() { - assertEquals(JAVA_18, JRE.currentVersion()); + void jre18() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_18); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(18); } @Test @EnabledOnJre(JAVA_19) - void java19() { - assertEquals(JAVA_19, JRE.currentVersion()); + void jre19() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_19); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(19); } @Test @EnabledOnJre(JAVA_20) - void java20() { - assertEquals(JAVA_20, JRE.currentVersion()); + void jre20() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_20); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(20); } @Test @EnabledOnJre(JAVA_21) - void java21() { - assertEquals(JAVA_21, JRE.currentVersion()); + void jre21() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_21); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(21); } @Test @EnabledOnJre(JAVA_22) - void java22() { - assertEquals(JAVA_22, JRE.currentVersion()); + void jre22() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_21); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(22); + } + + @Test + @EnabledOnJre(JAVA_23) + void jre23() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_23); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(23); + } + + @Test + @EnabledOnJre(JAVA_24) + void jre24() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_24); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(24); + } + + @Test + @EnabledOnJre(JAVA_25) + void jre25() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(JAVA_25); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(25); + } + + @Test + @EnabledOnJre(versions = 17) + void version17() { + jre17(); + } + + @Test + @EnabledOnJre(versions = 18) + void version18() { + jre18(); + } + + @Test + @EnabledOnJre(versions = 19) + void version19() { + jre19(); + } + + @Test + @EnabledOnJre(versions = 20) + void version20() { + jre20(); + } + + @Test + @EnabledOnJre(versions = 21) + void version21() { + jre21(); + } + + @Test + @EnabledOnJre(versions = 22) + void version22() { + jre22(); + } + + @Test + @EnabledOnJre(versions = 23) + void version23() { + jre23(); + } + + @Test + @EnabledOnJre(versions = 24) + void version24() { + jre24(); + } + + @Test + @EnabledOnJre(versions = 25) + void version25() { + jre25(); } @Test @EnabledOnJre(OTHER) - void other() { - assertEquals(OTHER, JRE.currentVersion()); + void jreOther() { + assertThat(CURRENT_JRE).as("current version").isEqualTo(OTHER); + assertThat(CURRENT_JRE.version()).as("current feature version").isEqualTo(Integer.MAX_VALUE); } + + @Test + @EnabledOnJre(versions = Integer.MAX_VALUE) + void versionMaxInteger() { + jreOther(); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/StaticConditionMethods.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/StaticConditionMethods.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/StaticConditionMethods.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/StaticConditionMethods.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -35,6 +35,7 @@ reportEntry(Map.of("1", "closed"))); } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExtensionContextParameterResolver.class) static class TestCase { @Test @@ -45,8 +46,7 @@ store.put("baz", reportEntryOnClose(extensionContext, "3")); } - private ExtensionContext.Store.CloseableResource reportEntryOnClose(ExtensionContext extensionContext, - String key) { + private AutoCloseable reportEntryOnClose(ExtensionContext extensionContext, String key) { return () -> extensionContext.publishReportEntry(Map.of(key, "closed")); } } @@ -64,6 +64,7 @@ )))); } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ThrowingOnCloseExtension.class) static class ExceptionInCloseableResourceTestCase { @@ -78,9 +79,16 @@ @Override public void beforeEach(ExtensionContext context) { - context.getStore(GLOBAL).put("throwingResource", (ExtensionContext.Store.CloseableResource) () -> { - throw new RuntimeException("Exception in onClose"); - }); + context.getStore(GLOBAL).put("throwingResource", new ThrowingResource()); + } + } + + @SuppressWarnings({ "deprecation", "try" }) + static class ThrowingResource implements ExtensionContext.Store.CloseableResource, AutoCloseable { + + @Override + public void close() throws Exception { + throw new RuntimeException("Exception in onClose"); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/DeprecatedMediaTypeTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/DeprecatedMediaTypeTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/DeprecatedMediaTypeTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/DeprecatedMediaTypeTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,131 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullOrBlankFor; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * Unit tests for the deprecated {@link MediaType}. + * + * @see org.junit.jupiter.api.MediaTypeTests + * @see MediaTypeInteroperabilityTests + */ +@SuppressWarnings("deprecation") +class DeprecatedMediaTypeTests { + + @Test + void equals() { + var mediaType1 = MediaType.TEXT_PLAIN; + var mediaType2 = MediaType.parse(mediaType1.toString()); + var mediaType3 = MediaType.APPLICATION_JSON; + + assertEqualsAndHashCode(mediaType1, mediaType2, mediaType3); + } + + @Nested + class ParseTests { + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void parseWithNullOrBlankMediaType(String mediaType) { + assertPreconditionViolationNotNullOrBlankFor("value", () -> MediaType.parse(mediaType)); + } + + @ParameterizedTest + @ValueSource(strings = { "/", " / ", "type", "type/", "/subtype" }) + void parseWithInvalidMediaType(String mediaType) { + assertPreconditionViolationFor(() -> MediaType.parse(mediaType))// + .withMessage("Invalid media type: '%s'", mediaType.strip()); + } + + @ParameterizedTest + @ValueSource(strings = { "text/plain", " text/plain ", "text/plain; charset=UTF-8", + "\t text/plain; charset=UTF-8 \t" }) + void parse(String value) { + assertThat(MediaType.parse(value)).hasToString(value.strip()); + } + } + + @Nested + class CreateTests { + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankType(String type) { + assertPreconditionViolationNotNullOrBlankFor("type", () -> MediaType.create(type, "json")); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankTypeAndCharset(String type) { + assertPreconditionViolationNotNullOrBlankFor("type", () -> MediaType.create(type, "json", UTF_8)); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankSubtype(String subtype) { + assertPreconditionViolationNotNullOrBlankFor("subtype", () -> MediaType.create("application", subtype)); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void createWithNullOrBlankSubtypeAndCharset(String subtype) { + assertPreconditionViolationNotNullOrBlankFor("subtype", + () -> MediaType.create("application", subtype, UTF_8)); + } + + @Test + void createWithNullCharset() { + assertPreconditionViolationNotNullFor("charset", () -> MediaType.create("application", "json", null)); + } + + @ParameterizedTest + @ValueSource(strings = { "/", " / ", "type/", "/subtype" }) + void createWithInvalidType(String type) { + assertPreconditionViolationFor(() -> MediaType.create(type, "json"))// + .withMessage("Invalid media type: '%s/json'", type.strip()); + } + + @ParameterizedTest + @ValueSource(strings = { "/", " / ", "type/", "/subtype" }) + void createWithInvalidSubtype(String subtype) { + assertPreconditionViolationFor(() -> MediaType.create("application", subtype))// + .withMessage("Invalid media type: 'application/%s'", subtype.strip()); + } + + @Test + void create() { + assertThat(MediaType.create("application", "json")).hasToString("application/json"); + } + + @Test + void createWithCharset() { + assertThat(MediaType.create("text", "plain", UTF_8)).hasToString("text/plain; charset=UTF-8"); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExecutableInvokerIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExecutableInvokerIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExecutableInvokerIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExecutableInvokerIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -39,11 +39,13 @@ assertEquals(2, ExecuteTestsTwiceTestCase.testInvocations); } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExecuteTestsTwiceExtension.class) static class ExecuteTestsTwiceTestCase { static int testInvocations = 0; + @SuppressWarnings("JUnitMalformedDeclaration") @Test void testWithResolvedParameter(TestInfo testInfo, @ExtendWith(ExtensionContextParameterResolver.class) ExtensionContext extensionContext) { @@ -54,6 +56,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExecuteConstructorTwiceExtension.class) static class ExecuteConstructorTwiceTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExtensionComposabilityTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExtensionComposabilityTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExtensionComposabilityTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/ExtensionComposabilityTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.jupiter.api.extension; import static java.util.function.Predicate.not; -import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toCollection; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -22,6 +22,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; @@ -30,8 +31,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ClassUtils; -import org.junit.platform.commons.util.ReflectionUtils; /** * Unit tests for extension composability in JUnit Jupiter. @@ -60,18 +61,18 @@ .flatMap(Arrays::stream) .filter(not(Method::isSynthetic)) .filter(not(where(Method::getModifiers, Modifier::isStatic))) - .collect(toList()); + .toList(); List expectedMethodSignatures = expectedMethods.stream() .map(this::methodSignature) .sorted() - .collect(toList()); + .toList(); List expectedMethodNames = expectedMethods.stream() .map(Method::getName) .distinct() .sorted() - .collect(toList()); + .toList(); // @formatter:on // 3) Dynamically implement all Extension APIs @@ -82,20 +83,20 @@ // @formatter:off List actualMethods = Arrays.stream(dynamicKitchenSinkExtension.getClass().getDeclaredMethods()) - .filter(ReflectionUtils::isNotStatic) - .collect(toList()); + .filter(ModifierSupport::isNotStatic) + .toList(); List actualMethodSignatures = actualMethods.stream() .map(this::methodSignature) .distinct() .sorted() - .collect(toList()); + .collect(toCollection(ArrayList::new)); List actualMethodNames = actualMethods.stream() .map(Method::getName) .distinct() .sorted() - .collect(toList()); + .collect(toCollection(ArrayList::new)); // @formatter:on // 5) Remove methods from java.lang.Object @@ -140,7 +141,7 @@ } private List> findExtensionApis() { - return ReflectionUtils.findAllClassesInPackage(Extension.class.getPackage().getName(), this::isExtensionApi, + return ReflectionSupport.findAllClassesInPackage(Extension.class.getPackage().getName(), this::isExtensionApi, name -> true); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/KitchenSinkExtension.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/KitchenSinkExtension.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/KitchenSinkExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/KitchenSinkExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -35,11 +35,13 @@ // Lifecycle Callbacks BeforeAllCallback, - BeforeEachCallback, - BeforeTestExecutionCallback, - TestExecutionExceptionHandler, - AfterTestExecutionCallback, - AfterEachCallback, + BeforeClassTemplateInvocationCallback, + BeforeEachCallback, + BeforeTestExecutionCallback, + TestExecutionExceptionHandler, + AfterTestExecutionCallback, + AfterEachCallback, + AfterClassTemplateInvocationCallback, AfterAllCallback, // Lifecycle methods exception handling @@ -55,16 +57,25 @@ // Conditional Test Execution ExecutionCondition, - // @TestTemplate + // @TestTemplate and @ClassTemplate TestTemplateInvocationContextProvider, + ClassTemplateInvocationContextProvider, // Miscellaneous TestWatcher, - InvocationInterceptor + InvocationInterceptor, + PreInterruptCallback // @formatter:on { + // --- Test Class Instantiation -------------------------------------------- + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + // --- Lifecycle Callbacks ------------------------------------------------- @Override @@ -72,6 +83,10 @@ } @Override + public void beforeClassTemplateInvocation(ExtensionContext context) { + } + + @Override public void beforeEach(ExtensionContext context) { } @@ -92,6 +107,10 @@ } @Override + public void afterClassTemplateInvocation(ExtensionContext context) { + } + + @Override public void afterAll(ExtensionContext context) { } @@ -161,6 +180,28 @@ return null; } + @Override + public boolean mayReturnZeroTestTemplateInvocationContexts(ExtensionContext context) { + return false; + } + + // --- @ClassTemplate ------------------------------------------------------- + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return false; + } + + @Override + public Stream provideClassTemplateInvocationContexts(ExtensionContext context) { + return null; + } + + @Override + public boolean mayReturnZeroClassTemplateInvocationContexts(ExtensionContext context) { + return false; + } + // --- TestWatcher --------------------------------------------------------- @Override @@ -242,4 +283,12 @@ ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { InvocationInterceptor.super.interceptAfterAllMethod(invocation, invocationContext, extensionContext); } + + // --- PreInterruptCallback ------------------------------------------------ + + @Override + public void beforeThreadInterrupt(PreInterruptContext preInterruptContext, ExtensionContext extensionContext) + throws Exception { + + } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/MediaTypeInteroperabilityTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/MediaTypeInteroperabilityTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/MediaTypeInteroperabilityTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/MediaTypeInteroperabilityTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.extension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + +import org.junit.jupiter.api.Test; + +/** + * Interoperability tests for {@link org.junit.jupiter.api.MediaType} and the + * deprecated {@link org.junit.jupiter.api.extension.MediaType}. + * + * @since 1.14 + * @see DeprecatedMediaTypeTests + */ +class MediaTypeInteroperabilityTests { + + @Test + @SuppressWarnings("deprecation") + void newAndDeprecatedMediaTypesAreLogicallyEquivalent() { + var mediaType = org.junit.jupiter.api.MediaType.TEXT_PLAIN_UTF_8; + var deprecatedMediaType = MediaType.TEXT_PLAIN_UTF_8; + var differentMediaType = MediaType.TEXT_PLAIN; + + assertThat(mediaType.getClass()).isNotEqualTo(deprecatedMediaType.getClass()); + assertEqualsAndHashCode(mediaType, deprecatedMediaType, differentMediaType); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -32,7 +32,7 @@ import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; /** * @since 5.6 @@ -98,7 +98,7 @@ } private Parameter findParameterOfMethod(String methodName, Class... parameterTypes) { - Method method = ReflectionUtils.findMethod(Sample.class, methodName, parameterTypes).get(); + Method method = ReflectionSupport.findMethod(Sample.class, methodName, parameterTypes).get(); return method.getParameters()[0]; } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/LockTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/LockTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/LockTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/LockTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.parallel; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; +import static org.junit.jupiter.api.parallel.ResourceAccessMode.READ; +import static org.junit.jupiter.api.parallel.ResourceAccessMode.READ_WRITE; +import static org.junit.jupiter.api.parallel.ResourceLocksProvider.Lock; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link Lock}. + * + * @since 5.12 + */ +class LockTests { + + @Test + void readWriteModeSetByDefault() { + assertEquals(READ_WRITE, new Lock("a").getAccessMode()); + } + + @Test + void equalsAndHashCode() { + // @formatter:off + assertEqualsAndHashCode( + new Lock("a", READ_WRITE), + new Lock("a", READ_WRITE), + new Lock("b", READ_WRITE) + ); + assertEqualsAndHashCode( + new Lock("a", READ_WRITE), + new Lock("a", READ_WRITE), + new Lock("a", READ) + ); + // @formatter:on + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,671 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.parallel; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.util.Throwables.getRootCause; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectIteration; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.engine.support.hierarchical.ExclusiveResource.LockMode; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.ClassTemplate; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; +import org.junit.jupiter.engine.descriptor.JupiterTestDescriptor; +import org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor; +import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.hierarchical.ExclusiveResource; +import org.junit.platform.testkit.engine.Event; + +/** + * Integration tests for {@link ResourceLock} and {@link ResourceLocksProvider}. + * + * @since 5.12 + */ +class ResourceLockAnnotationTests extends AbstractJupiterTestEngineTests { + + private static final UniqueId uniqueId = UniqueId.root("enigma", "foo"); + + private final JupiterConfiguration configuration = mock(); + + @BeforeEach + void setUp() { + when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); + when(configuration.getDefaultExecutionMode()).thenReturn(ExecutionMode.SAME_THREAD); + } + + @Test + void noSharedResources() { + // @formatter:off + var classResources = getClassResources( + NoSharedResourcesTestCase.class + ); + assertThat(classResources).isEmpty(); + + var methodResources = getMethodResources( + NoSharedResourcesTestCase.class + ); + assertThat(methodResources).isEmpty(); + + var nestedClassResources = getNestedClassResources( + NoSharedResourcesTestCase.NestedClass.class + ); + assertThat(nestedClassResources).isEmpty(); + // @formatter:on + } + + @Test + void addSharedResourcesViaAnnotationValue() { + // @formatter:off + var classResources = getClassResources( + SharedResourcesViaAnnotationValueTestCase.class + ); + assertThat(classResources).containsExactlyInAnyOrder( + new ExclusiveResource("a1", LockMode.READ_WRITE), + new ExclusiveResource("a2", LockMode.READ_WRITE) + ); + + var methodResources = getMethodResources( + SharedResourcesViaAnnotationValueTestCase.class + ); + assertThat(methodResources).containsExactlyInAnyOrder( + new ExclusiveResource("a3", LockMode.READ_WRITE), + new ExclusiveResource("b1", LockMode.READ), + new ExclusiveResource("b2", LockMode.READ_WRITE) + ); + + var nestedClassResources = getNestedClassResources( + SharedResourcesViaAnnotationValueTestCase.NestedClass.class + ); + assertThat(nestedClassResources).containsExactlyInAnyOrder( + new ExclusiveResource("a3", LockMode.READ_WRITE), + new ExclusiveResource("c1", LockMode.READ) + ); + + var nestedClassMethodResources = getMethodResources( + SharedResourcesViaAnnotationValueTestCase.NestedClass.class + ); + assertThat(nestedClassMethodResources).containsExactlyInAnyOrder( + new ExclusiveResource("c2", LockMode.READ) + ); + // @formatter:on + } + + @Test + void addSharedResourcesViaAnnotationProviders() { + // @formatter:off + var classResources = getClassResources( + SharedResourcesViaAnnotationProvidersTestCase.class + ); + assertThat(classResources).containsExactlyInAnyOrder( + new ExclusiveResource("a1", LockMode.READ), + new ExclusiveResource("a2", LockMode.READ) + ); + + var methodResources = getMethodResources( + SharedResourcesViaAnnotationProvidersTestCase.class + ); + assertThat(methodResources).containsExactlyInAnyOrder( + new ExclusiveResource("b1", LockMode.READ_WRITE), + new ExclusiveResource("b2", LockMode.READ_WRITE) + ); + + var nestedClassResources = getNestedClassResources( + SharedResourcesViaAnnotationProvidersTestCase.NestedClass.class + ); + assertThat(nestedClassResources).containsExactlyInAnyOrder( + new ExclusiveResource("c1", LockMode.READ_WRITE), + new ExclusiveResource("c2", LockMode.READ) + ); + // @formatter:on + } + + @Test + void addSharedResourcesViaAnnotationValueAndProviders() { + // @formatter:off + var classResources = getClassResources( + SharedResourcesViaAnnotationValueAndProvidersTestCase.class + ); + assertThat(classResources).containsExactlyInAnyOrder( + new ExclusiveResource("a1", LockMode.READ_WRITE), + new ExclusiveResource("a3", LockMode.READ) + ); + + var methodResources = getMethodResources( + SharedResourcesViaAnnotationValueAndProvidersTestCase.class + ); + assertThat(methodResources).containsExactlyInAnyOrder( + new ExclusiveResource("a2", LockMode.READ_WRITE), + new ExclusiveResource("b1", LockMode.READ), + new ExclusiveResource("b2", LockMode.READ) + ); + + var nestedClassResources = getNestedClassResources( + SharedResourcesViaAnnotationValueAndProvidersTestCase.NestedClass.class + ); + assertThat(nestedClassResources).containsExactlyInAnyOrder( + new ExclusiveResource("a2", LockMode.READ_WRITE), + new ExclusiveResource("c1", LockMode.READ_WRITE), + new ExclusiveResource("c2", LockMode.READ_WRITE), + new ExclusiveResource("c3", LockMode.READ_WRITE) + ); + // @formatter:on + } + + @Test + void addSharedResourcesViaAnnotationValueAndProvidersForClassTemplate() { + var selector = selectClass(SharedResourcesViaAnnotationValueAndProvidersClassTemplateTestCase.class); + var engineDescriptor = discoverTests(selector).getEngineDescriptor(); + engineDescriptor.accept(TestDescriptor::prune); + + var classTemplateTestDescriptor = (JupiterTestDescriptor) getOnlyElement(engineDescriptor.getChildren()); + + var expectedResources = List.of( // + new ExclusiveResource("a1", LockMode.READ_WRITE), // + new ExclusiveResource("a2", LockMode.READ_WRITE), // + new ExclusiveResource("a3", LockMode.READ), // + new ExclusiveResource("b1", LockMode.READ), // + new ExclusiveResource("b2", LockMode.READ), // + new ExclusiveResource("c1", LockMode.READ_WRITE), // + new ExclusiveResource("c2", LockMode.READ_WRITE), // + new ExclusiveResource("c3", LockMode.READ_WRITE), // + new ExclusiveResource("d1", LockMode.READ_WRITE), // + new ExclusiveResource("d2", LockMode.READ) // + ); + + assertThat(classTemplateTestDescriptor.getExclusiveResources()) // + .containsExactlyInAnyOrderElementsOf(expectedResources); + } + + @Test + void addSharedResourcesViaAnnotationValueAndProvidersForClassTemplateInvocation() { + var selector = selectIteration( + selectClass(SharedResourcesViaAnnotationValueAndProvidersClassTemplateTestCase.class), 0); + var engineDescriptor = discoverTests(selector).getEngineDescriptor(); + engineDescriptor.accept(TestDescriptor::prune); + + var classTemplateTestDescriptor = (JupiterTestDescriptor) getOnlyElement(engineDescriptor.getChildren()); + + var expectedResources = List.of( // + new ExclusiveResource("a1", LockMode.READ_WRITE), // + new ExclusiveResource("a2", LockMode.READ_WRITE), // + new ExclusiveResource("a3", LockMode.READ), // + new ExclusiveResource("b1", LockMode.READ), // + new ExclusiveResource("b2", LockMode.READ), // + new ExclusiveResource("c1", LockMode.READ_WRITE), // + new ExclusiveResource("c2", LockMode.READ_WRITE), // + new ExclusiveResource("c3", LockMode.READ_WRITE), // + new ExclusiveResource("d1", LockMode.READ_WRITE), // + new ExclusiveResource("d2", LockMode.READ) // + ); + + assertThat(classTemplateTestDescriptor.getExclusiveResources()) // + .containsExactlyInAnyOrderElementsOf(expectedResources); + } + + @Test + void addSharedResourcesViaAnnotationValueAndProvidersForMethodInClassTemplate() { + var selector = selectMethod(SharedResourcesViaAnnotationValueAndProvidersClassTemplateTestCase.class, "test"); + var engineDescriptor = discoverTests(selector).getEngineDescriptor(); + engineDescriptor.accept(TestDescriptor::prune); + + var classTemplateTestDescriptor = (JupiterTestDescriptor) getOnlyElement(engineDescriptor.getChildren()); + + var expectedResources = List.of( // + new ExclusiveResource("a1", LockMode.READ_WRITE), // + new ExclusiveResource("a2", LockMode.READ_WRITE), // + new ExclusiveResource("a3", LockMode.READ), // + new ExclusiveResource("b1", LockMode.READ), // + new ExclusiveResource("b2", LockMode.READ) // + ); + + assertThat(classTemplateTestDescriptor.getExclusiveResources()) // + .containsExactlyInAnyOrderElementsOf(expectedResources); + } + + @Test + void sharedResourcesHavingTheSameValueAndModeAreDeduplicated() { + // @formatter:off + var methodResources = getMethodResources( + SharedResourcesHavingTheSameValueAndModeAreDeduplicatedTestCase.class + ); + assertThat(methodResources).containsExactlyInAnyOrder( + new ExclusiveResource("a1", LockMode.READ_WRITE) + ); + // @formatter:on + } + + @Test + void sharedResourcesHavingTheSameValueButDifferentModeAreNotDeduplicated() { + // @formatter:off + var methodResources = getMethodResources( + SharedResourcesHavingTheSameValueButDifferentModeAreNotDeduplicatedTestCase.class + ); + assertThat(methodResources).containsExactlyInAnyOrder( + new ExclusiveResource("a1", LockMode.READ), + new ExclusiveResource("a1", LockMode.READ_WRITE) + ); + // @formatter:on + } + + static Stream> testMethodsCanNotDeclareSharedResourcesForChildrenArguments() { + // @formatter:off + return Stream.of( + TestCanNotDeclareSharedResourcesForChildrenTestCase.class, + ParameterizedTestCanNotDeclareSharedResourcesForChildrenTestCase.class, + RepeatedTestCanNotDeclareSharedResourcesForChildrenTestCase.class, + TestFactoryCanNotDeclareSharedResourcesForChildrenTestCase.class + ); + // @formatter:on + } + + @ParameterizedTest + @MethodSource("testMethodsCanNotDeclareSharedResourcesForChildrenArguments") + void testMethodsCanNotDeclareSharedResourcesForChildren(Class testClass) { + var messageTemplate = "'ResourceLockTarget.CHILDREN' is not supported for methods. Invalid method: %s"; + assertThrowsJunitExceptionWithMessage( // + testClass, // + messageTemplate.formatted(getDeclaredTestMethod(testClass)) // + ); + } + + @Test + void emptyAnnotation() { + // @formatter:off + var classResources = getClassResources( + EmptyAnnotationTestCase.class + ); + assertThat(classResources).isEmpty(); + + var methodResources = getMethodResources( + EmptyAnnotationTestCase.class + ); + assertThat(methodResources).isEmpty(); + + var nestedClassResources = getNestedClassResources( + EmptyAnnotationTestCase.NestedClass.class + ); + assertThat(nestedClassResources).isEmpty(); + // @formatter:on + } + + private Set getClassResources(Class testClass) { + return getClassTestDescriptor(testClass).getExclusiveResources(); + } + + private ClassTestDescriptor getClassTestDescriptor(Class testClass) { + return new ClassTestDescriptor(uniqueId, testClass, configuration); + } + + private Set getMethodResources(Class testClass) { + var descriptor = new TestMethodTestDescriptor( // + uniqueId, testClass, getDeclaredTestMethod(testClass), List::of, configuration // + ); + descriptor.setParent(getClassTestDescriptor(testClass)); + return descriptor.getExclusiveResources(); + } + + private static Method getDeclaredTestMethod(Class testClass) { + try { + return testClass.getDeclaredMethod("test"); + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private Set getNestedClassResources(Class testClass) { + var descriptor = new NestedClassTestDescriptor(uniqueId, testClass, List::of, configuration); + descriptor.setParent(getClassTestDescriptor(testClass.getEnclosingClass())); + return descriptor.getExclusiveResources(); + } + + private void assertThrowsJunitExceptionWithMessage(Class testClass, String message) { + // @formatter:off + var events = executeTestsForClass(testClass).allEvents(); + assertThat(events.filter(finishedWithFailure(instanceOf(JUnitException.class))::matches)) + .hasSize(1) + .map(Event::getPayload) + .map(payload -> (TestExecutionResult) payload.orElseThrow()) + .map(payload -> getRootCause(payload.getThrowable().orElseThrow())) + .first() + .is(instanceOf(JUnitException.class)) + .has(message(message)); + // @formatter:on + } + + // ------------------------------------------------------------------------- + + @SuppressWarnings("JUnitMalformedDeclaration") + static class NoSharedResourcesTestCase { + + @Test + void test() { + } + + @Nested + class NestedClass { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ResourceLock("a1") + @ResourceLock(value = "a2", mode = ResourceAccessMode.READ_WRITE) + @ResourceLock(value = "a3", mode = ResourceAccessMode.READ_WRITE, target = ResourceLockTarget.CHILDREN) + static class SharedResourcesViaAnnotationValueTestCase { + + @Test + @ResourceLock(value = "b1", mode = ResourceAccessMode.READ) + @ResourceLock(value = "b2", target = ResourceLockTarget.SELF) + void test() { + } + + @Nested + @ResourceLock(value = "c1", mode = ResourceAccessMode.READ) + @ResourceLock(value = "c2", mode = ResourceAccessMode.READ, target = ResourceLockTarget.CHILDREN) + class NestedClass { + + @Test + void test() { + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ResourceLock(providers = { // + SharedResourcesViaAnnotationProvidersTestCase.FirstClassLevelProvider.class, // + SharedResourcesViaAnnotationProvidersTestCase.SecondClassLevelProvider.class // + }) + static class SharedResourcesViaAnnotationProvidersTestCase { + + @Test + @ResourceLock(providers = MethodLevelProvider.class) + void test() { + } + + @Nested + @ResourceLock(providers = NestedClassLevelProvider.class) + class NestedClass { + } + + static class FirstClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForClass(Class testClass) { + return Set.of(new Lock("a1", ResourceAccessMode.READ)); + } + } + + static class SecondClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForClass(Class testClass) { + return Set.of(new Lock("a2", ResourceAccessMode.READ)); + } + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return Set.of(new Lock("b1")); + } + } + + static class MethodLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return Set.of(new Lock("b2")); + } + } + + static class NestedClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + return Set.of(new Lock("c1"), new Lock("c2", ResourceAccessMode.READ)); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ResourceLock( // + value = "a1", // + providers = SharedResourcesViaAnnotationValueAndProvidersTestCase.FirstClassLevelProvider.class // + ) + @ResourceLock( // + value = "a2", // + target = ResourceLockTarget.CHILDREN, // + providers = SharedResourcesViaAnnotationValueAndProvidersTestCase.SecondClassLevelProvider.class // + ) + static class SharedResourcesViaAnnotationValueAndProvidersTestCase { + + @Test + @ResourceLock(value = "b1", mode = ResourceAccessMode.READ) + void test() { + } + + @Nested + @ResourceLock("c1") + @ResourceLock(providers = NestedClassLevelProvider.class) + class NestedClass { + } + + static class FirstClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForClass(Class testClass) { + return Set.of(new Lock("a3", ResourceAccessMode.READ)); + } + } + + static class SecondClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return Set.of(new Lock("b2", ResourceAccessMode.READ)); + } + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + return Set.of(new Lock("c2")); + } + } + + static class NestedClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + return Set.of(new Lock("c3")); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ResourceLock( // + value = "a1", // + target = ResourceLockTarget.CHILDREN, // + providers = SharedResourcesHavingTheSameValueAndModeAreDeduplicatedTestCase.Provider.class // + ) + static class SharedResourcesHavingTheSameValueAndModeAreDeduplicatedTestCase { + + @Test + @ResourceLock(value = "a1") + void test() { + } + + static class Provider implements ResourceLocksProvider { + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return Set.of(new Lock("a1")); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ResourceLock(value = "a1", mode = ResourceAccessMode.READ_WRITE, target = ResourceLockTarget.CHILDREN) + static class SharedResourcesHavingTheSameValueButDifferentModeAreNotDeduplicatedTestCase { + + @Test + @ResourceLock(value = "a1", mode = ResourceAccessMode.READ) + void test() { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class TestCanNotDeclareSharedResourcesForChildrenTestCase { + + @Test + @ResourceLock(value = "a1", target = ResourceLockTarget.CHILDREN) + void test() { + } + } + + static class ParameterizedTestCanNotDeclareSharedResourcesForChildrenTestCase { + + @ParameterizedTest + @ValueSource(ints = { 1, 2, 3 }) + @ResourceLock(value = "a1", target = ResourceLockTarget.CHILDREN) + void test() { + } + } + + static class RepeatedTestCanNotDeclareSharedResourcesForChildrenTestCase { + + @RepeatedTest(5) + @ResourceLock(value = "a1", target = ResourceLockTarget.CHILDREN) + void test() { + } + } + + static class TestFactoryCanNotDeclareSharedResourcesForChildrenTestCase { + + @TestFactory + @ResourceLock(value = "a1", target = ResourceLockTarget.CHILDREN) + Stream test() { + return Stream.of(DynamicTest.dynamicTest("Dynamic test", () -> { + })); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ResourceLock + static class EmptyAnnotationTestCase { + + @Test + @ResourceLock + void test() { + } + + @Nested + @ResourceLock + class NestedClass { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ResourceLock( // + value = "a1", // + providers = SharedResourcesViaAnnotationValueAndProvidersClassTemplateTestCase.FirstClassLevelProvider.class // + ) + @ResourceLock( // + value = "a2", // + target = ResourceLockTarget.CHILDREN, // + providers = SharedResourcesViaAnnotationValueAndProvidersClassTemplateTestCase.SecondClassLevelProvider.class // + ) + static class SharedResourcesViaAnnotationValueAndProvidersClassTemplateTestCase { + + @Test + @ResourceLock(value = "b1", mode = ResourceAccessMode.READ) + void test() { + } + + @Nested + @ResourceLock(providers = NestedClassLevelProvider.class) + class NestedClass { + @Test + @ResourceLock("c1") + void test() { + } + } + + @Nested + @ClassTemplate + @ResourceLock(value = "d1", target = ResourceLockTarget.CHILDREN) + class NestedClassTemplate { + @Test + @ResourceLock(value = "d2", mode = ResourceAccessMode.READ) + void test() { + } + } + + static class FirstClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForClass(Class testClass) { + return Set.of(new Lock("a3", ResourceAccessMode.READ)); + } + } + + static class SecondClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return Set.of(new Lock("b2", ResourceAccessMode.READ)); + } + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + return Set.of(new Lock("c2")); + } + } + + static class NestedClassLevelProvider implements ResourceLocksProvider { + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + return Set.of(new Lock("c3")); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLocksProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLocksProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLocksProviderTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLocksProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,315 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api.parallel; + +import static java.util.Collections.emptySet; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully; +import static org.junit.platform.testkit.engine.EventConditions.test; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.platform.testkit.engine.Event; + +/** + * Integration tests for {@link ResourceLocksProvider}. + * + * @since 5.12 + */ +class ResourceLocksProviderTests extends AbstractJupiterTestEngineTests { + + @Test + void classLevelProvider() { + var events = execute(ClassLevelProviderTestCase.class); + assertThat(events.filter(event(test(), finishedSuccessfully())::matches)).hasSize(2); + } + + @Test + void nestedClassLevelProvider() { + var events = execute(NestedClassLevelProviderTestCase.class); + assertThat(events.filter(event(test(), finishedSuccessfully())::matches)).hasSize(2); + } + + @Test + void methodLevelProvider() { + var events = execute(MethodLevelProviderTestCase.class); + assertThat(events.filter(event(test(), finishedSuccessfully())::matches)).hasSize(2); + } + + @Test + void methodLevelProviderInNestedClass() { + var events = execute(MethodLevelProviderInNestedClassTestCase.class); + assertThat(events.filter(event(test(), finishedSuccessfully())::matches)).hasSize(2); + } + + @Test + void providesAccessToRuntimeEnclosingInstances() { + var events = execute(SubClassLevelProviderTestCase.class); + assertThat(events.filter(event(test(), finishedSuccessfully())::matches)).hasSize(2); + } + + private Stream execute(Class testCase) { + return executeTestsForClass(testCase).allEvents().stream(); + } + + // ------------------------------------------------------------------------- + + @SuppressWarnings("JUnitMalformedDeclaration") + @ResourceLock(providers = ClassLevelProviderTestCase.Provider.class) + static class ClassLevelProviderTestCase { + + @Test + void test() { + assertTrue(Provider.isProvideForClassCalled, "'provideForClass' was not called"); + assertTrue(Provider.isProvideForTestMethodCalled, "'provideForMethod(test)' was not called"); + } + + @Nested + class NestedClass { + + @Test + void nestedTest() { + assertTrue(Provider.isProvideForNestedClassCalled, "'provideForNestedClass' was not called"); + // @formatter:off + assertTrue( + Provider.isProvideForNestedTestMethodCalled, + "'provideForMethod(nestedTest)' was not called" + ); + // @formatter:on + } + } + + @AfterAll + static void afterAll() { + Provider.isProvideForClassCalled = false; + Provider.isProvideForTestMethodCalled = false; + + Provider.isProvideForNestedClassCalled = false; + Provider.isProvideForNestedTestMethodCalled = false; + } + + static class Provider implements ResourceLocksProvider { + + private static boolean isProvideForClassCalled = false; + private static boolean isProvideForTestMethodCalled = false; + + private static boolean isProvideForNestedClassCalled = false; + private static boolean isProvideForNestedTestMethodCalled = false; + + private Class testClass; + + @Override + public Set provideForClass(Class testClass) { + this.testClass = testClass; + isProvideForClassCalled = true; + assertThat(testClass).isAssignableTo(ClassLevelProviderTestCase.class); + return emptySet(); + } + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + isProvideForNestedClassCalled = true; + assertEquals(List.of(this.testClass), enclosingInstanceTypes); + assertEquals(ClassLevelProviderTestCase.NestedClass.class, testClass); + return emptySet(); + } + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + if (ClassLevelProviderTestCase.class.isAssignableFrom(testClass)) { + assertEquals(List.of(), enclosingInstanceTypes); + assertEquals("test", testMethod.getName()); + isProvideForTestMethodCalled = true; + return emptySet(); + } + if (testClass == ClassLevelProviderTestCase.NestedClass.class) { + assertEquals(List.of(this.testClass), enclosingInstanceTypes); + assertEquals("nestedTest", testMethod.getName()); + isProvideForNestedTestMethodCalled = true; + return emptySet(); + } + fail("Unexpected test class: " + testClass); + return emptySet(); + } + } + } + + static class SubClassLevelProviderTestCase extends ClassLevelProviderTestCase { + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class NestedClassLevelProviderTestCase { + + @Test + void test() { + } + + @Nested + @ResourceLock(providers = NestedClassLevelProviderTestCase.Provider.class) + class NestedClass { + + @Test + void nestedTest() { + assertTrue(Provider.isProvideForNestedClassCalled, "'provideForNestedClass' was not called"); + assertTrue(Provider.isProvideForMethodCalled, "'provideForMethod' was not called"); + } + } + + @AfterAll + static void afterAll() { + Provider.isProvideForNestedClassCalled = false; + Provider.isProvideForMethodCalled = false; + } + + static class Provider implements ResourceLocksProvider { + + private static boolean isProvideForNestedClassCalled = false; + + private static boolean isProvideForMethodCalled = false; + + @Override + public Set provideForClass(Class testClass) { + fail("'provideForClass' should not be called"); + return emptySet(); + } + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + isProvideForNestedClassCalled = true; + assertEquals(List.of(NestedClassLevelProviderTestCase.class), enclosingInstanceTypes); + assertEquals(NestedClass.class, testClass); + return emptySet(); + } + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + isProvideForMethodCalled = true; + assertEquals(List.of(NestedClassLevelProviderTestCase.class), enclosingInstanceTypes); + assertEquals(NestedClassLevelProviderTestCase.NestedClass.class, testClass); + assertEquals("nestedTest", testMethod.getName()); + return emptySet(); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class MethodLevelProviderTestCase { + + @Test + @ResourceLock(providers = MethodLevelProviderTestCase.Provider.class) + void test() { + assertTrue(Provider.isProvideForMethodCalled, "'provideForMethod' was not called"); + } + + @Nested + class NestedClass { + + @Test + void nestedTest() { + } + } + + @AfterAll + static void afterAll() { + Provider.isProvideForMethodCalled = false; + } + + static class Provider implements ResourceLocksProvider { + + private static boolean isProvideForMethodCalled = false; + + @Override + public Set provideForClass(Class testClass) { + fail("'provideForClass' should not be called"); + return emptySet(); + } + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + fail("'provideForNestedClass' should not be called"); + return emptySet(); + } + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + isProvideForMethodCalled = true; + assertEquals(List.of(), enclosingInstanceTypes); + assertEquals(MethodLevelProviderTestCase.class, testClass); + assertEquals("test", testMethod.getName()); + return emptySet(); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class MethodLevelProviderInNestedClassTestCase { + + @Test + void test() { + } + + @Nested + class NestedClass { + + @Test + @ResourceLock(providers = MethodLevelProviderInNestedClassTestCase.Provider.class) + void nestedTest() { + assertTrue(Provider.isProvideForMethodCalled, "'provideForMethod' was not called"); + } + } + + @AfterAll + static void afterAll() { + Provider.isProvideForMethodCalled = false; + } + + static class Provider implements ResourceLocksProvider { + + private static boolean isProvideForMethodCalled = false; + + @Override + public Set provideForClass(Class testClass) { + fail("'provideForClass' should not be called"); + return emptySet(); + } + + @Override + public Set provideForNestedClass(List> enclosingInstanceTypes, Class testClass) { + fail("'provideForNestedClass' should not be called"); + return emptySet(); + } + + @Override + public Set provideForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + isProvideForMethodCalled = true; + assertEquals(List.of(MethodLevelProviderInNestedClassTestCase.class), enclosingInstanceTypes); + assertEquals(MethodLevelProviderInNestedClassTestCase.NestedClass.class, testClass); + assertEquals("nestedTest", testMethod.getName()); + return emptySet(); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssertionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssertionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssertionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssertionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssumptionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssumptionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssumptionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/api/subpackage/SubclassedAssumptionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AbstractJupiterTestEngineTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AbstractJupiterTestEngineTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AbstractJupiterTestEngineTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AbstractJupiterTestEngineTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,18 +10,24 @@ package org.junit.jupiter.engine; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.launcher.LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME; +import static org.junit.platform.launcher.LauncherConstants.STACKTRACE_PRUNING_ENABLED_PROPERTY_NAME; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; -import java.util.Set; +import java.util.function.Consumer; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; +import org.junit.platform.testkit.engine.EngineDiscoveryResults; import org.junit.platform.testkit.engine.EngineExecutionResults; import org.junit.platform.testkit.engine.EngineTestKit; @@ -39,7 +45,13 @@ } protected EngineExecutionResults executeTests(DiscoverySelector... selectors) { - return executeTests(request().selectors(selectors)); + return executeTests(request -> request.selectors(selectors)); + } + + protected EngineExecutionResults executeTests(Consumer configurer) { + var builder = defaultRequest(); + configurer.accept(builder); + return executeTests(builder); } protected EngineExecutionResults executeTests(LauncherDiscoveryRequestBuilder builder) { @@ -50,19 +62,48 @@ return EngineTestKit.execute(this.engine, request); } - protected TestDescriptor discoverTests(DiscoverySelector... selectors) { - return discoverTests(request().selectors(selectors).build()); + protected TestDescriptor discoverTestsWithoutIssues(LauncherDiscoveryRequest request) { + var results = discoverTests(request); + assertThat(results.getDiscoveryIssues()).isEmpty(); + return results.getEngineDescriptor(); + } + + protected EngineDiscoveryResults discoverTestsForClass(Class testClass) { + return discoverTests(selectClass(testClass)); + } + + protected EngineDiscoveryResults discoverTests(Consumer configurer) { + var builder = defaultRequest(); + configurer.accept(builder); + return discoverTests(builder); + } + + protected EngineDiscoveryResults discoverTests(DiscoverySelector... selectors) { + return discoverTests(request -> request.selectors(selectors)); + } + + protected EngineDiscoveryResults discoverTests(LauncherDiscoveryRequestBuilder builder) { + return discoverTests(builder.build()); + } + + protected EngineDiscoveryResults discoverTests(LauncherDiscoveryRequest request) { + return EngineTestKit.discover(this.engine, request); } - protected TestDescriptor discoverTests(LauncherDiscoveryRequest request) { - return engine.discover(request, UniqueId.forEngine(engine.getId())); + protected static LauncherDiscoveryRequestBuilder defaultRequest() { + return request() // + .outputDirectoryCreator(dummyOutputDirectoryCreator()) // + .configurationParameter(STACKTRACE_PRUNING_ENABLED_PROPERTY_NAME, String.valueOf(false)) // + .configurationParameter(CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, Severity.INFO.name()) // + .enableImplicitConfigurationParameters(false); } protected UniqueId discoverUniqueId(Class clazz, String methodName) { - TestDescriptor engineDescriptor = discoverTests(selectMethod(clazz, methodName)); - Set descendants = engineDescriptor.getDescendants(); + var results = discoverTests(selectMethod(clazz, methodName)); + var engineDescriptor = results.getEngineDescriptor(); + var descendants = engineDescriptor.getDescendants(); // @formatter:off - TestDescriptor testDescriptor = descendants.stream() + var testDescriptor = descendants.stream() .skip(descendants.size() - 1) .findFirst() .orElseGet(() -> fail("no descendants")); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AtypicalJvmMethodNameTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AtypicalJvmMethodNameTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AtypicalJvmMethodNameTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/AtypicalJvmMethodNameTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeAllAndAfterAllComposedAnnotationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeAllAndAfterAllComposedAnnotationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeAllAndAfterAllComposedAnnotationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeAllAndAfterAllComposedAnnotationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -39,6 +39,7 @@ assertThat(methodsInvoked).containsExactly("beforeAll", "test", "afterAll"); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase { @CustomBeforeAll diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeEachAndAfterEachComposedAnnotationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeEachAndAfterEachComposedAnnotationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeEachAndAfterEachComposedAnnotationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/BeforeEachAndAfterEachComposedAnnotationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -39,6 +39,7 @@ assertThat(methodsInvoked).containsExactly("beforeEach", "test", "afterEach"); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase { @CustomBeforeEach diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ClassTemplateInvocationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ClassTemplateInvocationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ClassTemplateInvocationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ClassTemplateInvocationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,1600 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.commons.util.ExceptionUtils.throwAsUncheckedException; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectIteration; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectNestedClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectNestedMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; +import static org.junit.platform.launcher.TagFilter.excludeTags; +import static org.junit.platform.launcher.TagFilter.includeTags; +import static org.junit.platform.testkit.engine.EventConditions.container; +import static org.junit.platform.testkit.engine.EventConditions.displayName; +import static org.junit.platform.testkit.engine.EventConditions.dynamicTestRegistered; +import static org.junit.platform.testkit.engine.EventConditions.engine; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.EventConditions.legacyReportingName; +import static org.junit.platform.testkit.engine.EventConditions.started; +import static org.junit.platform.testkit.engine.EventConditions.test; +import static org.junit.platform.testkit.engine.EventConditions.uniqueId; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.suppressed; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.ClassTemplate; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContextProvider; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.engine.descriptor.ClassTemplateInvocationTestDescriptor; +import org.junit.jupiter.engine.descriptor.ClassTemplateTestDescriptor; +import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; +import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; +import org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor; +import org.junit.jupiter.engine.descriptor.TestFactoryTestDescriptor; +import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; +import org.junit.jupiter.engine.descriptor.TestTemplateInvocationTestDescriptor; +import org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.engine.TestTag; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.engine.support.hierarchical.ExclusiveResource; +import org.junit.platform.testkit.engine.EngineExecutionResults; +import org.opentest4j.AssertionFailedError; +import org.opentest4j.TestAbortedException; + +/** + * @since 5.13 + */ +public class ClassTemplateInvocationTests extends AbstractJupiterTestEngineTests { + + @ParameterizedTest + @ValueSource(strings = { // + "class:%s", // + "uid:[engine:junit-jupiter]/[class-template:%s]" // + }) + void executesClassTemplateClassTwice(String selectorIdentifierTemplate) { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoInvocationsTestCase.class.getName()); + var invocationId1 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var invocation1MethodAId = invocationId1.append(TestMethodTestDescriptor.SEGMENT_TYPE, "a()"); + var invocation1NestedClassId = invocationId1.append(NestedClassTestDescriptor.SEGMENT_TYPE, "NestedTestCase"); + var invocation1NestedMethodBId = invocation1NestedClassId.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var invocation2MethodAId = invocationId2.append(TestMethodTestDescriptor.SEGMENT_TYPE, "a()"); + var invocation2NestedClassId = invocationId2.append(NestedClassTestDescriptor.SEGMENT_TYPE, "NestedTestCase"); + var invocation2NestedMethodBId = invocation2NestedClassId.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + + var results = executeTests(DiscoverySelectors.parse( + selectorIdentifierTemplate.formatted(TwoInvocationsTestCase.class.getName())).orElseThrow()); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId1)), displayName("[1] A of TwoInvocationsTestCase"), + legacyReportingName("%s[1]".formatted(TwoInvocationsTestCase.class.getName()))), // + event(container(uniqueId(invocationId1)), started()), // + event(dynamicTestRegistered(uniqueId(invocation1MethodAId))), // + event(dynamicTestRegistered(uniqueId(invocation1NestedClassId))), // + event(dynamicTestRegistered(uniqueId(invocation1NestedMethodBId))), // + event(test(uniqueId(invocation1MethodAId)), started()), // + event(test(uniqueId(invocation1MethodAId)), finishedSuccessfully()), // + event(container(uniqueId(invocation1NestedClassId)), started()), // + event(test(uniqueId(invocation1NestedMethodBId)), started()), // + event(test(uniqueId(invocation1NestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(invocation1NestedClassId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId1)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), displayName("[2] B of TwoInvocationsTestCase"), + legacyReportingName("%s[2]".formatted(TwoInvocationsTestCase.class.getName()))), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(invocation2MethodAId))), // + event(dynamicTestRegistered(uniqueId(invocation2NestedClassId))), // + event(dynamicTestRegistered(uniqueId(invocation2NestedMethodBId))), // + event(test(uniqueId(invocation2MethodAId)), started()), // + event(test(uniqueId(invocation2MethodAId)), finishedSuccessfully()), // + event(container(uniqueId(invocation2NestedClassId)), started()), // + event(test(uniqueId(invocation2NestedMethodBId)), started()), // + event(test(uniqueId(invocation2NestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(invocation2NestedClassId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void classTemplateAnnotationIsInherited() { + var results = executeTestsForClass(InheritedTwoInvocationsTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(12).succeeded(12)); + } + + @Test + void executesOnlySelectedMethodsDeclaredInClassTemplate() { + var results = executeTests(selectMethod(TwoInvocationsTestCase.class, "a")); + + results.testEvents() // + .assertStatistics(stats -> stats.started(2).succeeded(2)) // + .assertEventsMatchLoosely(event(test(displayName("a()")), finishedSuccessfully())); + } + + @Test + void executesOnlySelectedMethodsDeclaredInNestedClassOfClassTemplate() { + var results = executeTests(selectNestedMethod(List.of(TwoInvocationsTestCase.class), + TwoInvocationsTestCase.NestedTestCase.class, "b")); + + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)) // + .assertEventsMatchLoosely(event(test(displayName("b()")), finishedSuccessfully())); + } + + @Test + void executesOnlyTestsPassingPostDiscoveryFilter() { + var results = executeTests(request -> request // + .selectors(selectClass(TwoInvocationsTestCase.class)) // + .filters(includeTags("nested"))); + + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)) // + .assertEventsMatchLoosely(event(test(displayName("b()")), finishedSuccessfully())); + } + + @Test + void prunesEmptyNestedTestClasses() { + var results = executeTests(request -> request // + .selectors(selectClass(TwoInvocationsTestCase.class)) // + .filters(excludeTags("nested"))); + + results.containerEvents().assertThatEvents() // + .noneMatch(container(TwoInvocationsTestCase.NestedTestCase.class.getSimpleName())::matches); + + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)) // + .assertEventsMatchLoosely(event(test(displayName("a()")), finishedSuccessfully())); + } + + @Test + void executesNestedClassTemplateClassTwiceWithClassSelectorForEnclosingClass() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classId = engineId.append(ClassTestDescriptor.SEGMENT_TYPE, + NestedClassTemplateWithTwoInvocationsTestCase.class.getName()); + var methodAId = classId.append(TestMethodTestDescriptor.SEGMENT_TYPE, "a()"); + var nestedClassTemplateId = classId.append(ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, + "NestedTestCase"); + var invocationId1 = nestedClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var invocation1NestedMethodBId = invocationId1.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + var invocationId2 = nestedClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var invocation2NestedMethodBId = invocationId2.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + + var results = executeTestsForClass(NestedClassTemplateWithTwoInvocationsTestCase.class); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classId)), started()), // + + event(test(uniqueId(methodAId)), started()), // + event(test(uniqueId(methodAId)), finishedSuccessfully()), // + + event(container(uniqueId(nestedClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId1)), displayName("[1] A of NestedTestCase"), + legacyReportingName( + "%s[1]".formatted(NestedClassTemplateWithTwoInvocationsTestCase.NestedTestCase.class.getName()))), // + event(container(uniqueId(invocationId1)), started()), // + event(dynamicTestRegistered(uniqueId(invocation1NestedMethodBId))), // + event(test(uniqueId(invocation1NestedMethodBId)), started()), // + event(test(uniqueId(invocation1NestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId1)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), displayName("[2] B of NestedTestCase"), + legacyReportingName( + "%s[2]".formatted(NestedClassTemplateWithTwoInvocationsTestCase.NestedTestCase.class.getName()))), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(invocation2NestedMethodBId))), // + event(test(uniqueId(invocation2NestedMethodBId)), started()), // + event(test(uniqueId(invocation2NestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(nestedClassTemplateId)), finishedSuccessfully()), // + + event(container(uniqueId(classId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void executesNestedClassTemplateClassTwiceWithNestedClassSelector() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classId = engineId.append(ClassTestDescriptor.SEGMENT_TYPE, + NestedClassTemplateWithTwoInvocationsTestCase.class.getName()); + var nestedClassTemplateId = classId.append(ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, + "NestedTestCase"); + var invocationId1 = nestedClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var invocation1NestedMethodBId = invocationId1.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + var invocationId2 = nestedClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var invocation2NestedMethodBId = invocationId2.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + + var results = executeTestsForClass(NestedClassTemplateWithTwoInvocationsTestCase.NestedTestCase.class); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classId)), started()), // + + event(container(uniqueId(nestedClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId1)), displayName("[1] A of NestedTestCase")), // + event(container(uniqueId(invocationId1)), started()), // + event(dynamicTestRegistered(uniqueId(invocation1NestedMethodBId))), // + event(test(uniqueId(invocation1NestedMethodBId)), started()), // + event(test(uniqueId(invocation1NestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId1)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), displayName("[2] B of NestedTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(invocation2NestedMethodBId))), // + event(test(uniqueId(invocation2NestedMethodBId)), started()), // + event(test(uniqueId(invocation2NestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(nestedClassTemplateId)), finishedSuccessfully()), // + + event(container(uniqueId(classId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void executesNestedClassTemplatesTwiceEach() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var outerClassTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoTimesTwoInvocationsTestCase.class.getName()); + + var outerInvocation1Id = outerClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var outerInvocation1NestedClassTemplateId = outerInvocation1Id.append( + ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, "NestedTestCase"); + var outerInvocation1InnerInvocation1Id = outerInvocation1NestedClassTemplateId.append( + ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var outerInvocation1InnerInvocation1NestedMethodId = outerInvocation1InnerInvocation1Id.append( + TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); + var outerInvocation1InnerInvocation2Id = outerInvocation1NestedClassTemplateId.append( + ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation1InnerInvocation2NestedMethodId = outerInvocation1InnerInvocation2Id.append( + TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); + + var outerInvocation2Id = outerClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation2NestedClassTemplateId = outerInvocation2Id.append( + ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, "NestedTestCase"); + var outerInvocation2InnerInvocation1Id = outerInvocation2NestedClassTemplateId.append( + ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var outerInvocation2InnerInvocation1NestedMethodId = outerInvocation2InnerInvocation1Id.append( + TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); + var outerInvocation2InnerInvocation2Id = outerInvocation2NestedClassTemplateId.append( + ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation2InnerInvocation2NestedMethodId = outerInvocation2InnerInvocation2Id.append( + TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); + + var results = executeTestsForClass(TwoTimesTwoInvocationsTestCase.class); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(outerClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation1Id)), + displayName("[1] A of TwoTimesTwoInvocationsTestCase")), // + event(container(uniqueId(outerInvocation1Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation1NestedClassTemplateId))), // + event(container(uniqueId(outerInvocation1NestedClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation1InnerInvocation1Id)), + displayName("[1] A of NestedTestCase")), // + event(container(uniqueId(outerInvocation1InnerInvocation1Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation1InnerInvocation1NestedMethodId))), // + event(test(uniqueId(outerInvocation1InnerInvocation1NestedMethodId)), started()), // + event(test(uniqueId(outerInvocation1InnerInvocation1NestedMethodId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation1InnerInvocation1Id)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation1InnerInvocation2Id)), + displayName("[2] B of NestedTestCase")), // + event(container(uniqueId(outerInvocation1InnerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation1InnerInvocation2NestedMethodId))), // + event(test(uniqueId(outerInvocation1InnerInvocation2NestedMethodId)), started()), // + event(test(uniqueId(outerInvocation1InnerInvocation2NestedMethodId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation1InnerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerInvocation1NestedClassTemplateId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation1Id)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation2Id)), + displayName("[2] B of TwoTimesTwoInvocationsTestCase")), // + event(container(uniqueId(outerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation2NestedClassTemplateId))), // + event(container(uniqueId(outerInvocation2NestedClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation1Id)), + displayName("[1] A of NestedTestCase")), // + event(container(uniqueId(outerInvocation2InnerInvocation1Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation1NestedMethodId))), // + event(test(uniqueId(outerInvocation2InnerInvocation1NestedMethodId)), started()), // + event(test(uniqueId(outerInvocation2InnerInvocation1NestedMethodId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation2InnerInvocation1Id)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation2Id)), + displayName("[2] B of NestedTestCase")), // + event(container(uniqueId(outerInvocation2InnerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation2NestedMethodId))), // + event(test(uniqueId(outerInvocation2InnerInvocation2NestedMethodId)), started()), // + event(test(uniqueId(outerInvocation2InnerInvocation2NestedMethodId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation2InnerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerInvocation2NestedClassTemplateId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerClassTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void invocationContextProviderCanRegisterAdditionalExtensions() { + var results = executeTestsForClass(AdditionalExtensionRegistrationTestCase.class); + + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)); + } + + @Test + void eachInvocationHasSeparateExtensionContext() { + var results = executeTestsForClass(SeparateExtensionContextTestCase.class); + + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)); + } + + @Test + void supportsTestTemplateMethodsInsideClassTemplateClasses() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + CombinationWithTestTemplateTestCase.class.getName()); + var invocationId1 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var testTemplateId1 = invocationId1.append(TestTemplateTestDescriptor.SEGMENT_TYPE, "test(int)"); + var testTemplate1InvocationId1 = testTemplateId1.append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, + "#1"); + var testTemplate1InvocationId2 = testTemplateId1.append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, + "#2"); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var testTemplateId2 = invocationId2.append(TestTemplateTestDescriptor.SEGMENT_TYPE, "test(int)"); + var testTemplate2InvocationId1 = testTemplateId2.append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, + "#1"); + var testTemplate2InvocationId2 = testTemplateId2.append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, + "#2"); + + var results = executeTestsForClass(CombinationWithTestTemplateTestCase.class); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId1)), + displayName("[1] A of CombinationWithTestTemplateTestCase")), // + event(container(uniqueId(invocationId1)), started()), // + event(dynamicTestRegistered(uniqueId(testTemplateId1))), // + event(container(uniqueId(testTemplateId1)), started()), // + event(dynamicTestRegistered(uniqueId(testTemplate1InvocationId1))), // + event(test(uniqueId(testTemplate1InvocationId1)), started()), // + event(test(uniqueId(testTemplate1InvocationId1)), finishedSuccessfully()), // + event(dynamicTestRegistered(uniqueId(testTemplate1InvocationId2))), // + event(test(uniqueId(testTemplate1InvocationId2)), started()), // + event(test(uniqueId(testTemplate1InvocationId2)), finishedSuccessfully()), // + event(container(uniqueId(testTemplateId1)), finishedSuccessfully()), // + event(container(uniqueId(invocationId1)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), + displayName("[2] B of CombinationWithTestTemplateTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(testTemplateId2))), // + event(container(uniqueId(testTemplateId2)), started()), // + event(dynamicTestRegistered(uniqueId(testTemplate2InvocationId1))), // + event(test(uniqueId(testTemplate2InvocationId1)), started()), // + event(test(uniqueId(testTemplate2InvocationId1)), finishedSuccessfully()), // + event(dynamicTestRegistered(uniqueId(testTemplate2InvocationId2))), // + event(test(uniqueId(testTemplate2InvocationId2)), started()), // + event(test(uniqueId(testTemplate2InvocationId2)), finishedSuccessfully()), // + event(container(uniqueId(testTemplateId2)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void testTemplateInvocationInsideClassTemplateClassCanBeSelectedByUniqueId() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + CombinationWithTestTemplateTestCase.class.getName()); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var testTemplateId2 = invocationId2.append(TestTemplateTestDescriptor.SEGMENT_TYPE, "test(int)"); + var testTemplate2InvocationId2 = testTemplateId2.append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, + "#2"); + + var results = executeTests(selectUniqueId(testTemplate2InvocationId2)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), + displayName("[2] B of CombinationWithTestTemplateTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(testTemplateId2))), // + event(container(uniqueId(testTemplateId2)), started()), // + event(dynamicTestRegistered(uniqueId(testTemplate2InvocationId2))), // + event(test(uniqueId(testTemplate2InvocationId2)), started()), // + event(test(uniqueId(testTemplate2InvocationId2)), finishedSuccessfully()), // + event(container(uniqueId(testTemplateId2)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void supportsTestFactoryMethodsInsideClassTemplateClasses() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + CombinationWithTestFactoryTestCase.class.getName()); + var invocationId1 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var testFactoryId1 = invocationId1.append(TestFactoryTestDescriptor.SEGMENT_TYPE, "test()"); + var testFactory1DynamicTestId1 = testFactoryId1.append(TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE, + "#1"); + var testFactory1DynamicTestId2 = testFactoryId1.append(TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE, + "#2"); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var testFactoryId2 = invocationId2.append(TestFactoryTestDescriptor.SEGMENT_TYPE, "test()"); + var testFactory2DynamicTestId1 = testFactoryId2.append(TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE, + "#1"); + var testFactory2DynamicTestId2 = testFactoryId2.append(TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE, + "#2"); + + var results = executeTestsForClass(CombinationWithTestFactoryTestCase.class); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId1)), + displayName("[1] A of CombinationWithTestFactoryTestCase")), // + event(container(uniqueId(invocationId1)), started()), // + event(dynamicTestRegistered(uniqueId(testFactoryId1))), // + event(container(uniqueId(testFactoryId1)), started()), // + event(dynamicTestRegistered(uniqueId(testFactory1DynamicTestId1))), // + event(test(uniqueId(testFactory1DynamicTestId1)), started()), // + event(test(uniqueId(testFactory1DynamicTestId1)), finishedSuccessfully()), // + event(dynamicTestRegistered(uniqueId(testFactory1DynamicTestId2))), // + event(test(uniqueId(testFactory1DynamicTestId2)), started()), // + event(test(uniqueId(testFactory1DynamicTestId2)), finishedSuccessfully()), // + event(container(uniqueId(testFactoryId1)), finishedSuccessfully()), // + event(container(uniqueId(invocationId1)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), + displayName("[2] B of CombinationWithTestFactoryTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(testFactoryId2))), // + event(container(uniqueId(testFactoryId2)), started()), // + event(dynamicTestRegistered(uniqueId(testFactory2DynamicTestId1))), // + event(test(uniqueId(testFactory2DynamicTestId1)), started()), // + event(test(uniqueId(testFactory2DynamicTestId1)), finishedSuccessfully()), // + event(dynamicTestRegistered(uniqueId(testFactory2DynamicTestId2))), // + event(test(uniqueId(testFactory2DynamicTestId2)), started()), // + event(test(uniqueId(testFactory2DynamicTestId2)), finishedSuccessfully()), // + event(container(uniqueId(testFactoryId2)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void specificDynamicTestInsideClassTemplateClassCanBeSelectedByUniqueId() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + CombinationWithTestFactoryTestCase.class.getName()); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var testFactoryId2 = invocationId2.append(TestFactoryTestDescriptor.SEGMENT_TYPE, "test()"); + var testFactory2DynamicTestId2 = testFactoryId2.append(TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE, + "#2"); + + var results = executeTests(selectUniqueId(testFactory2DynamicTestId2)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), + displayName("[2] B of CombinationWithTestFactoryTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(testFactoryId2))), // + event(container(uniqueId(testFactoryId2)), started()), // + event(dynamicTestRegistered(uniqueId(testFactory2DynamicTestId2))), // + event(test(uniqueId(testFactory2DynamicTestId2)), started()), // + event(test(uniqueId(testFactory2DynamicTestId2)), finishedSuccessfully()), // + event(container(uniqueId(testFactoryId2)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void failsIfProviderReturnsZeroInvocationContextWithoutOptIn() { + var results = executeTestsForClass(InvalidZeroInvocationTestCase.class); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(InvalidZeroInvocationTestCase.class), started()), // + event(container(InvalidZeroInvocationTestCase.class), + finishedWithFailure( + message("Provider [Ext] did not provide any invocation contexts, but was expected to do so. " + + "You may override mayReturnZeroClassTemplateInvocationContexts() to allow this."))), // + event(engine(), finishedSuccessfully())); + } + + @Test + void succeedsIfProviderReturnsZeroInvocationContextWithOptIn() { + var results = executeTestsForClass(ValidZeroInvocationTestCase.class); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(ValidZeroInvocationTestCase.class), started()), // + event(container(ValidZeroInvocationTestCase.class), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @ParameterizedTest + @ValueSource(classes = { NoProviderRegisteredTestCase.class, NoSupportingProviderRegisteredTestCase.class }) + void failsIfNoSupportingProviderIsRegistered(Class testClass) { + var results = executeTestsForClass(testClass); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(testClass), started()), // + event(container(testClass), + finishedWithFailure( + message("You must register at least one ClassTemplateInvocationContextProvider that supports " + + "@ClassTemplate class [" + testClass.getName() + "]"))), // + event(engine(), finishedSuccessfully())); + } + + @Test + void classTemplateInvocationCanBeSelectedByUniqueId() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoInvocationsTestCase.class.getName()); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var methodAId = invocationId2.append(TestMethodTestDescriptor.SEGMENT_TYPE, "a()"); + var nestedClassId = invocationId2.append(NestedClassTestDescriptor.SEGMENT_TYPE, "NestedTestCase"); + var nestedMethodBId = nestedClassId.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + + var results = executeTests(selectUniqueId(invocationId2)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), displayName("[2] B of TwoInvocationsTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(methodAId))), // + event(dynamicTestRegistered(uniqueId(nestedClassId))), // + event(dynamicTestRegistered(uniqueId(nestedMethodBId))), // + event(test(uniqueId(methodAId)), started()), // + event(test(uniqueId(methodAId)), finishedSuccessfully()), // + event(container(uniqueId(nestedClassId)), started()), // + event(test(uniqueId(nestedMethodBId)), started()), // + event(test(uniqueId(nestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(nestedClassId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void classTemplateInvocationCanBeSelectedByIteration() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoInvocationsTestCase.class.getName()); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var methodAId = invocationId2.append(TestMethodTestDescriptor.SEGMENT_TYPE, "a()"); + var nestedClassId = invocationId2.append(NestedClassTestDescriptor.SEGMENT_TYPE, "NestedTestCase"); + var nestedMethodBId = nestedClassId.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + + var results = executeTests(selectIteration(selectClass(TwoInvocationsTestCase.class), 1)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), displayName("[2] B of TwoInvocationsTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(methodAId))), // + event(dynamicTestRegistered(uniqueId(nestedClassId))), // + event(dynamicTestRegistered(uniqueId(nestedMethodBId))), // + event(test(uniqueId(methodAId)), started()), // + event(test(uniqueId(methodAId)), finishedSuccessfully()), // + event(container(uniqueId(nestedClassId)), started()), // + event(test(uniqueId(nestedMethodBId)), started()), // + event(test(uniqueId(nestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(nestedClassId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @ParameterizedTest + @ValueSource(strings = { // + "class:org.junit.jupiter.engine.ClassTemplateInvocationTests$TwoInvocationsTestCase", // + "uid:[engine:junit-jupiter]/[class-template:org.junit.jupiter.engine.ClassTemplateInvocationTests$TwoInvocationsTestCase]" // + }) + void executesAllInvocationsForRedundantSelectors(String classTemplateSelectorIdentifier) { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoInvocationsTestCase.class.getName()); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + + var results = executeTests(selectUniqueId(invocationId2), + DiscoverySelectors.parse(classTemplateSelectorIdentifier).orElseThrow()); + + results.testEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + @Test + void methodInClassTemplateInvocationCanBeSelectedByUniqueId() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoInvocationsTestCase.class.getName()); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var methodAId = invocationId2.append(TestMethodTestDescriptor.SEGMENT_TYPE, "a()"); + + var results = executeTests(selectUniqueId(methodAId)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), displayName("[2] B of TwoInvocationsTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(methodAId))), // + event(test(uniqueId(methodAId)), started()), // + event(test(uniqueId(methodAId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void nestedMethodInClassTemplateInvocationCanBeSelectedByUniqueId() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var classTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoInvocationsTestCase.class.getName()); + var invocationId2 = classTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var nestedClassId = invocationId2.append(NestedClassTestDescriptor.SEGMENT_TYPE, "NestedTestCase"); + var nestedMethodBId = nestedClassId.append(TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + + var results = executeTests(selectUniqueId(nestedMethodBId)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(classTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(invocationId2)), displayName("[2] B of TwoInvocationsTestCase")), // + event(container(uniqueId(invocationId2)), started()), // + event(dynamicTestRegistered(uniqueId(nestedClassId))), // + event(dynamicTestRegistered(uniqueId(nestedMethodBId))), // + event(container(uniqueId(nestedClassId)), started()), // + event(test(uniqueId(nestedMethodBId)), started()), // + event(test(uniqueId(nestedMethodBId)), finishedSuccessfully()), // + event(container(uniqueId(nestedClassId)), finishedSuccessfully()), // + event(container(uniqueId(invocationId2)), finishedSuccessfully()), // + + event(container(uniqueId(classTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void nestedClassTemplateInvocationCanBeSelectedByUniqueId() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var outerClassTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoTimesTwoInvocationsWithMultipleMethodsTestCase.class.getName()); + var outerInvocation2Id = outerClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation2NestedClassTemplateId = outerInvocation2Id.append( + ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, "NestedTestCase"); + var outerInvocation2InnerInvocation2Id = outerInvocation2NestedClassTemplateId.append( + ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation2InnerInvocation2NestedMethodId = outerInvocation2InnerInvocation2Id.append( + TestMethodTestDescriptor.SEGMENT_TYPE, "b()"); + + var results = executeTests(selectUniqueId(outerInvocation2InnerInvocation2NestedMethodId)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(outerClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation2Id)), + displayName("[2] B of TwoTimesTwoInvocationsWithMultipleMethodsTestCase")), // + event(container(uniqueId(outerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation2NestedClassTemplateId))), // + event(container(uniqueId(outerInvocation2NestedClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation2Id)), + displayName("[2] B of NestedTestCase")), // + event(container(uniqueId(outerInvocation2InnerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation2NestedMethodId))), // + event(test(uniqueId(outerInvocation2InnerInvocation2NestedMethodId)), started()), // + event(test(uniqueId(outerInvocation2InnerInvocation2NestedMethodId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation2InnerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerInvocation2NestedClassTemplateId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerClassTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void nestedClassTemplateInvocationCanBeSelectedByIteration() { + var engineId = UniqueId.forEngine(JupiterEngineDescriptor.ENGINE_ID); + var outerClassTemplateId = engineId.append(ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE, + TwoTimesTwoInvocationsTestCase.class.getName()); + var outerInvocation1Id = outerClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#1"); + var outerInvocation1NestedClassTemplateId = outerInvocation1Id.append( + ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, "NestedTestCase"); + var outerInvocation1InnerInvocation2Id = outerInvocation1NestedClassTemplateId.append( + ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation1InnerInvocation2NestedMethodId = outerInvocation1InnerInvocation2Id.append( + TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); + var outerInvocation2Id = outerClassTemplateId.append(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation2NestedClassTemplateId = outerInvocation2Id.append( + ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE, "NestedTestCase"); + var outerInvocation2InnerInvocation2Id = outerInvocation2NestedClassTemplateId.append( + ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#2"); + var outerInvocation2InnerInvocation2NestedMethodId = outerInvocation2InnerInvocation2Id.append( + TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); + + var results = executeTests(selectIteration(selectNestedClass(List.of(TwoTimesTwoInvocationsTestCase.class), + TwoTimesTwoInvocationsTestCase.NestedTestCase.class), 1)); + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(uniqueId(outerClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation1Id)), + displayName("[1] A of TwoTimesTwoInvocationsTestCase")), // + event(container(uniqueId(outerInvocation1Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation1NestedClassTemplateId))), // + event(container(uniqueId(outerInvocation1NestedClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation1InnerInvocation2Id)), + displayName("[2] B of NestedTestCase")), // + event(container(uniqueId(outerInvocation1InnerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation1InnerInvocation2NestedMethodId))), // + event(test(uniqueId(outerInvocation1InnerInvocation2NestedMethodId)), started()), // + event(test(uniqueId(outerInvocation1InnerInvocation2NestedMethodId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation1InnerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerInvocation1NestedClassTemplateId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation1Id)), finishedSuccessfully()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation2Id)), + displayName("[2] B of TwoTimesTwoInvocationsTestCase")), // + event(container(uniqueId(outerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation2NestedClassTemplateId))), // + event(container(uniqueId(outerInvocation2NestedClassTemplateId)), started()), // + + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation2Id)), + displayName("[2] B of NestedTestCase")), // + event(container(uniqueId(outerInvocation2InnerInvocation2Id)), started()), // + event(dynamicTestRegistered(uniqueId(outerInvocation2InnerInvocation2NestedMethodId))), // + event(test(uniqueId(outerInvocation2InnerInvocation2NestedMethodId)), started()), // + event(test(uniqueId(outerInvocation2InnerInvocation2NestedMethodId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation2InnerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerInvocation2NestedClassTemplateId)), finishedSuccessfully()), // + event(container(uniqueId(outerInvocation2Id)), finishedSuccessfully()), // + + event(container(uniqueId(outerClassTemplateId)), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @Test + void executesLifecycleCallbacksInNestedClassTemplates() { + var results = executeTestsForClass(TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase.class); + + results.containerEvents().assertStatistics(stats -> stats.started(10).succeeded(10)); + results.testEvents().assertStatistics(stats -> stats.started(8).succeeded(8)); + + // @formatter:off + assertThat(allReportEntryValues(results)).containsExactly( + "beforeAll: TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase", + "beforeClassTemplateInvocation: TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase", + "beforeAll: NestedTestCase", + "beforeClassTemplateInvocation: NestedTestCase", + "beforeEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test1 [NestedTestCase]", + "test1", + "afterEach: test1 [NestedTestCase]", + "afterEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [NestedTestCase]", + "test2", + "afterEach: test2 [NestedTestCase]", + "afterEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "afterClassTemplateInvocation: NestedTestCase", + "beforeClassTemplateInvocation: NestedTestCase", + "beforeEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test1 [NestedTestCase]", + "test1", + "afterEach: test1 [NestedTestCase]", + "afterEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [NestedTestCase]", + "test2", + "afterEach: test2 [NestedTestCase]", + "afterEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "afterClassTemplateInvocation: NestedTestCase", + "afterAll: NestedTestCase", + "afterClassTemplateInvocation: TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase", + "beforeClassTemplateInvocation: TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase", + "beforeAll: NestedTestCase", + "beforeClassTemplateInvocation: NestedTestCase", + "beforeEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test1 [NestedTestCase]", + "test1", + "afterEach: test1 [NestedTestCase]", + "afterEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [NestedTestCase]", + "test2", + "afterEach: test2 [NestedTestCase]", + "afterEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "afterClassTemplateInvocation: NestedTestCase", + "beforeClassTemplateInvocation: NestedTestCase", + "beforeEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test1 [NestedTestCase]", + "test1", + "afterEach: test1 [NestedTestCase]", + "afterEach: test1 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "beforeEach: test2 [NestedTestCase]", + "test2", + "afterEach: test2 [NestedTestCase]", + "afterEach: test2 [TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase]", + "afterClassTemplateInvocation: NestedTestCase", + "afterAll: NestedTestCase", + "afterClassTemplateInvocation: TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase", + "afterAll: TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase" + ); + // @formatter:on + } + + @Test + void guaranteesWrappingBehaviorForCallbacks() { + var results = executeTestsForClass(CallbackWrappingBehaviorTestCase.class); + + results.containerEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)); + + // @formatter:off + assertThat(allReportEntryValues(results)).containsExactly( + "1st -> beforeClassTemplateInvocation: CallbackWrappingBehaviorTestCase", + "2nd -> beforeClassTemplateInvocation: CallbackWrappingBehaviorTestCase", + "test", + "2nd -> afterClassTemplateInvocation: CallbackWrappingBehaviorTestCase", + "1st -> afterClassTemplateInvocation: CallbackWrappingBehaviorTestCase", + "1st -> beforeClassTemplateInvocation: CallbackWrappingBehaviorTestCase", + "2nd -> beforeClassTemplateInvocation: CallbackWrappingBehaviorTestCase", + "test", + "2nd -> afterClassTemplateInvocation: CallbackWrappingBehaviorTestCase", + "1st -> afterClassTemplateInvocation: CallbackWrappingBehaviorTestCase" + ); + // @formatter:on + } + + @Test + void propagatesExceptionsFromCallbacks() { + + var results = executeTestsForClass(CallbackExceptionBehaviorTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(4).failed(2).succeeded(2)); + + results.containerEvents().assertThatEvents() // + .haveExactly(2, finishedWithFailure( // + message("2nd -> afterClassTemplateInvocation: CallbackExceptionBehaviorTestCase"), // + suppressed(0, message("1st -> beforeClassTemplateInvocation: CallbackExceptionBehaviorTestCase")), // + suppressed(1, message("1st -> afterClassTemplateInvocation: CallbackExceptionBehaviorTestCase")))); + + assertThat(allReportEntryValues(results).distinct()) // + .containsExactly("1st -> beforeClassTemplateInvocation: CallbackExceptionBehaviorTestCase", // + "2nd -> afterClassTemplateInvocation: CallbackExceptionBehaviorTestCase", // + "1st -> afterClassTemplateInvocation: CallbackExceptionBehaviorTestCase"); + } + + @Test + void templateWithPreparations() { + var results = executeTestsForClass(ClassTemplateWithPreparationsTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + assertTrue(CustomCloseableResource.closed, "resource in store was closed"); + } + + @Test + void propagatesTagsFromEnclosingClassesToNestedClassTemplates() { + var request = defaultRequest() // + .selectors(selectClass(NestedClassTemplateWithTagOnEnclosingClassTestCase.class)) // + .build(); + var engineDescriptor = discoverTestsWithoutIssues(request); + var classDescriptor = getOnlyElement(engineDescriptor.getChildren()); + var nestedClassTemplateDescriptor = getOnlyElement(classDescriptor.getChildren()); + + assertThat(classDescriptor.getTags()).extracting(TestTag::getName) // + .containsExactly("top-level"); + assertThat(nestedClassTemplateDescriptor.getTags()).extracting(TestTag::getName) // + .containsExactlyInAnyOrder("top-level", "nested"); + } + + @Test + void ignoresComposedAnnotations() { + var request = defaultRequest() // + .selectors(selectClass(ParameterizedClass.class)) // + .build(); + + var engineDescriptor = discoverTestsWithoutIssues(request); + + assertThat(engineDescriptor.getDescendants()).isEmpty(); + } + + @Test + void classTemplateWithResourceLockCollectsExclusiveResources() { + var results = discoverTestsForClass(ClassTemplateWithResourceLockTestCase.class); + var classTemplateDescriptor = (ClassTemplateTestDescriptor) getOnlyElement( + results.getEngineDescriptor().getChildren()); + + assertThat(classTemplateDescriptor.getExclusiveResources()).extracting( + ExclusiveResource::getKey).containsExactly("test-resource"); + } + + @Test + void classTemplateWithResourceLockExecutesSuccessfully() { + var results = executeTestsForClass(ClassTemplateWithResourceLockTestCase.class); + + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)); + results.containerEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + // ------------------------------------------------------------------- + + private static Stream allReportEntryValues(EngineExecutionResults results) { + return results.allEvents().reportingEntryPublished() // + .map(event -> event.getRequiredPayload(ReportEntry.class)) // + .map(ReportEntry::getKeyValuePairs) // + .map(Map::values) // + .flatMap(Collection::stream); + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + static class TwoInvocationsTestCase { + @Test + void a() { + } + + @Nested + class NestedTestCase { + @Test + @Tag("nested") + void b() { + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class NestedClassTemplateWithTwoInvocationsTestCase { + @Test + void a() { + } + + @Nested + @ClassTemplate + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + class NestedTestCase { + @Test + void b() { + } + } + } + + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + @ClassTemplate + static class TwoTimesTwoInvocationsTestCase { + @Nested + @ClassTemplate + class NestedTestCase { + @Test + void test() { + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + static class TwoInvocationsWithExtensionTestCase { + @Test + void a() { + } + + @Nested + class NestedTestCase { + @Test + @Tag("nested") + void b() { + } + } + } + + static class TwoInvocationsClassTemplateInvocationContextProvider + implements ClassTemplateInvocationContextProvider { + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts(ExtensionContext context) { + var suffix = " of %s".formatted(context.getRequiredTestClass().getSimpleName()); + return Stream.of(new Ctx("A" + suffix), new Ctx("B" + suffix)); + } + + record Ctx(String displayName) implements ClassTemplateInvocationContext { + @Override + public String getDisplayName(int invocationIndex) { + var defaultDisplayName = ClassTemplateInvocationContext.super.getDisplayName(invocationIndex); + return "%s %s".formatted(defaultDisplayName, displayName); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(AdditionalExtensionRegistrationTestCase.Ext.class) + static class AdditionalExtensionRegistrationTestCase { + + @Test + void test(Data data) { + assertNotNull(data); + assertNotNull(data.value()); + } + + static class Ext implements ClassTemplateInvocationContextProvider { + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts(ExtensionContext context) { + return Stream.of(new Data("A"), new Data("B")).map(Ctx::new); + } + } + + record Ctx(Data data) implements ClassTemplateInvocationContext { + @Override + public String getDisplayName(int invocationIndex) { + return this.data.value(); + } + + @Override + public List getAdditionalExtensions() { + return List.of(new ParameterResolver() { + @Override + public boolean supportsParameter(ParameterContext parameterContext, + ExtensionContext extensionContext) throws ParameterResolutionException { + return Data.class.equals(parameterContext.getParameter().getType()); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return Ctx.this.data; + } + }); + } + } + + record Data(String value) { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + @ExtendWith(SeparateExtensionContextTestCase.SomeResourceExtension.class) + static class SeparateExtensionContextTestCase { + + @Test + void test(SomeResource someResource) { + assertFalse(someResource.closed); + } + + static class SomeResourceExtension implements BeforeAllCallback, ParameterResolver { + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + context.getStore(Namespace.GLOBAL).put("someResource", new SomeResource()); + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + var parentContext = extensionContext.getParent().orElseThrow(); + assertAll( // + () -> assertEquals(SeparateExtensionContextTestCase.class, parentContext.getRequiredTestClass()), // + () -> assertEquals(SeparateExtensionContextTestCase.class, + parentContext.getElement().orElseThrow()), // + () -> assertEquals(TestInstance.Lifecycle.PER_METHOD, + parentContext.getTestInstanceLifecycle().orElseThrow()) // + ); + return SomeResource.class.equals(parameterContext.getParameter().getType()); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return extensionContext.getStore(Namespace.GLOBAL).get("someResource"); + } + } + + static class SomeResource implements AutoCloseable { + private boolean closed; + + @Override + public void close() { + this.closed = true; + } + } + } + + @ClassTemplate + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + static class CombinationWithTestTemplateTestCase { + + @ParameterizedTest + @ValueSource(ints = { 1, 2 }) + void test(int i) { + assertNotEquals(0, i); + } + } + + @ClassTemplate + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + static class CombinationWithTestFactoryTestCase { + + @TestFactory + Stream test() { + return IntStream.of(1, 2) // + .mapToObj(i -> dynamicTest("test" + i, () -> assertNotEquals(0, i))); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(InvalidZeroInvocationTestCase.Ext.class) + static class InvalidZeroInvocationTestCase { + + @Test + void test() { + fail("should not be called"); + } + + static class Ext implements ClassTemplateInvocationContextProvider { + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts( + ExtensionContext context) { + return Stream.empty(); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(ValidZeroInvocationTestCase.Ext.class) + static class ValidZeroInvocationTestCase { + + @Test + void test() { + fail("should not be called"); + } + + static class Ext implements ClassTemplateInvocationContextProvider { + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts( + ExtensionContext context) { + return Stream.empty(); + } + + @Override + public boolean mayReturnZeroClassTemplateInvocationContexts(ExtensionContext context) { + return true; + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + static class NoProviderRegisteredTestCase { + + @Test + void test() { + fail("should not be called"); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(NoSupportingProviderRegisteredTestCase.Ext.class) + static class NoSupportingProviderRegisteredTestCase { + + @Test + void test() { + fail("should not be called"); + } + + static class Ext implements ClassTemplateInvocationContextProvider { + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return false; + } + + @Override + public Stream provideClassTemplateInvocationContexts( + ExtensionContext context) { + throw new RuntimeException("should not be called"); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + @ClassTemplate + static class TwoTimesTwoInvocationsWithMultipleMethodsTestCase { + + @Test + void test() { + } + + @Nested + @ClassTemplate + class NestedTestCase { + @Test + void a() { + } + + @Test + void b() { + } + } + + @Nested + @ClassTemplate + class AnotherNestedTestCase { + @Test + void test() { + } + } + } + + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + @ExtendWith(ClassTemplateInvocationCallbacks.class) + @ClassTemplate + static class TwoTimesTwoInvocationsWithLifecycleCallbacksTestCase extends LifecycleCallbacks { + + @Nested + @ClassTemplate + class NestedTestCase extends LifecycleCallbacks { + + @Test + @DisplayName("test1") + void test1(TestReporter testReporter) { + testReporter.publishEntry("test1"); + } + + @Test + @DisplayName("test2") + void test2(TestReporter testReporter) { + testReporter.publishEntry("test2"); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class LifecycleCallbacks { + @BeforeAll + static void beforeAll(TestReporter testReporter, TestInfo testInfo) { + testReporter.publishEntry("beforeAll: " + testInfo.getTestClass().orElseThrow().getSimpleName()); + } + + @BeforeEach + void beforeEach(TestReporter testReporter, TestInfo testInfo) { + testReporter.publishEntry( + "beforeEach: " + testInfo.getDisplayName() + " [" + getClass().getSimpleName() + "]"); + } + + @AfterEach + void afterEach(TestReporter testReporter, TestInfo testInfo) { + testReporter.publishEntry( + "afterEach: " + testInfo.getDisplayName() + " [" + getClass().getSimpleName() + "]"); + } + + @AfterAll + static void afterAll(TestReporter testReporter, TestInfo testInfo) { + testReporter.publishEntry("afterAll: " + testInfo.getTestClass().orElseThrow().getSimpleName()); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith({ PreparingClassTemplateInvocationContextProvider.class, CompanionExtension.class }) + static class ClassTemplateWithPreparationsTestCase { + + @Test + void test(CustomCloseableResource resource) { + assertNotNull(resource); + assertFalse(CustomCloseableResource.closed, "should not be closed yet"); + } + + } + + private static class PreparingClassTemplateInvocationContextProvider + implements ClassTemplateInvocationContextProvider { + + static final Namespace NAMESPACE = Namespace.create(PreparingClassTemplateInvocationContextProvider.class); + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts( + ExtensionContext context) { + var invocationContext = new PreparingClassTemplateInvocationContext(); + return Stream.of(invocationContext, invocationContext); + } + + } + + private static class PreparingClassTemplateInvocationContext implements ClassTemplateInvocationContext { + + @Override + public void prepareInvocation(ExtensionContext context) { + CustomCloseableResource.closed = false; + context.getStore(PreparingClassTemplateInvocationContextProvider.NAMESPACE) // + .put("resource", new CustomCloseableResource()); + } + + } + + private static class CompanionExtension implements ParameterResolver { + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return CustomCloseableResource.class.equals(parameterContext.getParameter().getType()); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return extensionContext.getStore(PreparingClassTemplateInvocationContextProvider.NAMESPACE).get("resource"); + } + + } + + @SuppressWarnings("deprecation") + private static class CustomCloseableResource implements ExtensionContext.Store.CloseableResource { + + static boolean closed; + + @Override + public void close() { + closed = true; + } + + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + @ClassTemplate + static class CallbackWrappingBehaviorTestCase { + + @RegisterExtension + @Order(1) + static Extension first = new ClassTemplateInvocationCallbacks("1st -> "); + + @RegisterExtension + @Order(2) + static Extension second = new ClassTemplateInvocationCallbacks("2nd -> "); + + @Test + void test(TestReporter testReporter) { + testReporter.publishEntry("test"); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + @ClassTemplate + static class CallbackExceptionBehaviorTestCase { + + @RegisterExtension + @Order(1) + static Extension first = new ClassTemplateInvocationCallbacks("1st -> ", TestAbortedException::new); + + @RegisterExtension + @Order(2) + static Extension second = new ClassTemplateInvocationCallbacks("2nd -> ", AssertionFailedError::new); + + @Test + void test() { + fail("should not be called"); + } + } + + static class ClassTemplateInvocationCallbacks + implements BeforeClassTemplateInvocationCallback, AfterClassTemplateInvocationCallback { + + private final String prefix; + private final Function exceptionFactory; + + @SuppressWarnings("unused") + ClassTemplateInvocationCallbacks() { + this(""); + } + + ClassTemplateInvocationCallbacks(String prefix) { + this(prefix, __ -> null); + } + + ClassTemplateInvocationCallbacks(String prefix, Function exceptionFactory) { + this.prefix = prefix; + this.exceptionFactory = exceptionFactory; + } + + @Override + public void beforeClassTemplateInvocation(ExtensionContext context) { + handle("beforeClassTemplateInvocation", context); + } + + @Override + public void afterClassTemplateInvocation(ExtensionContext context) { + handle("afterClassTemplateInvocation", context); + } + + private void handle(String methodName, ExtensionContext context) { + var message = format(methodName, context); + context.publishReportEntry(message); + var throwable = exceptionFactory.apply(message); + if (throwable != null) { + throw throwAsUncheckedException(throwable); + } + } + + private String format(String methodName, ExtensionContext context) { + return "%s%s: %s".formatted(prefix, methodName, context.getRequiredTestClass().getSimpleName()); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class InheritedTwoInvocationsTestCase extends TwoInvocationsTestCase { + @Test + void c() { + } + } + + @Tag("top-level") + static class NestedClassTemplateWithTagOnEnclosingClassTestCase { + @Nested + @ClassTemplate + @Tag("nested") + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + class NestedTestCase { + @Test + void test() { + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(TwoInvocationsClassTemplateInvocationContextProvider.class) + @ResourceLock("test-resource") + static class ClassTemplateWithResourceLockTestCase { + @Test + void test() { + // This test verifies that @ResourceLock works with @ClassTemplate (issue #5155) + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultExecutionModeTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultExecutionModeTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultExecutionModeTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultExecutionModeTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -109,7 +109,7 @@ if (executionMode != null) { request.configurationParameter(Constants.DEFAULT_PARALLEL_EXECUTION_MODE, executionMode.name()); } - return (JupiterEngineDescriptor) discoverTests(request.build()); + return (JupiterEngineDescriptor) discoverTests(request.build()).getEngineDescriptor(); } private static void assertExecutionMode(TestDescriptor testDescriptor, ExecutionMode expectedExecutionMode) { @@ -126,6 +126,7 @@ .orElseGet(() -> fail("No child of type " + testDescriptorClass + " found")); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase { @Test @@ -155,6 +156,7 @@ static class SameThreadTestCase extends TestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") static class OuterTestCase { @Nested class LevelOne { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DefaultMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -200,6 +200,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class GenericTestCaseWithDefaultMethod implements GenericTestInterface { @Test @@ -210,6 +211,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class GenericTestCaseWithOverriddenDefaultMethod implements GenericTestInterface { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DisabledTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DisabledTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DisabledTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DisabledTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -50,6 +50,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @Disabled static class DisabledTestClassTestCase { @@ -59,6 +60,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class DisabledTestMethodsTestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DynamicNodeGenerationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DynamicNodeGenerationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DynamicNodeGenerationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/DynamicNodeGenerationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -67,7 +67,7 @@ @Test void testFactoryMethodsAreCorrectlyDiscoveredForClassSelector() { LauncherDiscoveryRequest request = request().selectors(selectClass(MyDynamicTestCase.class)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor(); assertThat(engineDescriptor.getDescendants()).as("# resolved test descriptors").hasSize(13); } @@ -75,7 +75,7 @@ void testFactoryMethodIsCorrectlyDiscoveredForMethodSelector() { LauncherDiscoveryRequest request = request().selectors( selectMethod(MyDynamicTestCase.class, "dynamicStream")).build(); - TestDescriptor engineDescriptor = discoverTests(request); + TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor(); assertThat(engineDescriptor.getDescendants()).as("# resolved test descriptors").hasSize(2); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ExceptionHandlingTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ExceptionHandlingTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ExceptionHandlingTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ExceptionHandlingTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -248,6 +248,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class FailureTestCase { static Optional exceptionToThrowInBeforeAll = Optional.empty(); @@ -309,6 +310,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @TestInstance(PER_METHOD) @ExtendWith(ThrowingAfterAllCallback.class) static class TestCaseWithInvalidConstructorAndThrowingAfterAllCallbackAndPerMethodLifecycle { @@ -322,6 +324,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @TestInstance(PER_CLASS) @ExtendWith(ThrowingAfterAllCallback.class) static class TestCaseWithInvalidConstructorAndThrowingAfterAllCallbackAndPerClassLifecycle { @@ -334,6 +337,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ThrowingBeforeAllCallback.class) @ExtendWith(ThrowingAfterAllCallback.class) static class TestCaseWithThrowingBeforeAllAndAfterAllCallbacks { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/FailedAssumptionsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/FailedAssumptionsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/FailedAssumptionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/FailedAssumptionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -42,6 +42,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class TestAbortedExceptionInBeforeAllTestCase { @BeforeAll @@ -54,6 +55,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class AssumptionViolatedExceptionInBeforeAllTestCase { @BeforeAll diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,79 +10,64 @@ package org.junit.jupiter.engine; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static java.util.function.Predicate.isEqual; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.commons.util.FunctionUtils.where; + +import java.lang.annotation.Annotation; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.platform.testkit.engine.EngineExecutionResults; -import org.junit.platform.testkit.engine.Events; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; /** * Integration tests that verify proper handling of invalid configuration for * lifecycle methods in conjunction with the {@link JupiterTestEngine}. * - *

    In general, configuration errors should not be thrown until the - * execution phase, thereby giving all containers a chance to execute. - * * @since 5.0 */ class InvalidLifecycleMethodConfigurationTests extends AbstractJupiterTestEngineTests { @Test void executeValidTestCaseAlongsideTestCaseWithInvalidNonStaticBeforeAllDeclaration() { - assertContainerFailed(TestCaseWithInvalidNonStaticBeforeAllMethod.class); + assertReportsError(TestCaseWithInvalidNonStaticBeforeAllMethod.class, BeforeAll.class); } @Test void executeValidTestCaseAlongsideTestCaseWithInvalidNonStaticAfterAllDeclaration() { - assertContainerFailed(TestCaseWithInvalidNonStaticAfterAllMethod.class); + assertReportsError(TestCaseWithInvalidNonStaticAfterAllMethod.class, AfterAll.class); } @Test void executeValidTestCaseAlongsideTestCaseWithInvalidStaticBeforeEachDeclaration() { - assertContainerFailed(TestCaseWithInvalidStaticBeforeEachMethod.class); + assertReportsError(TestCaseWithInvalidStaticBeforeEachMethod.class, BeforeEach.class); } @Test void executeValidTestCaseAlongsideTestCaseWithInvalidStaticAfterEachDeclaration() { - assertContainerFailed(TestCaseWithInvalidStaticAfterEachMethod.class); + assertReportsError(TestCaseWithInvalidStaticAfterEachMethod.class, AfterEach.class); } - private void assertContainerFailed(Class invalidTestClass) { - EngineExecutionResults executionResults = executeTests(selectClass(TestCase.class), - selectClass(invalidTestClass)); - Events containers = executionResults.containerEvents(); - Events tests = executionResults.testEvents(); - - // @formatter:off - assertAll( - () -> assertEquals(3, containers.started().count(), "# containers started"), - () -> assertEquals(1, tests.started().count(), "# tests started"), - () -> assertEquals(1, tests.succeeded().count(), "# tests succeeded"), - () -> assertEquals(0, tests.failed().count(), "# tests failed"), - () -> assertEquals(3, containers.finished().count(), "# containers finished"), - () -> assertEquals(1, containers.failed().count(), "# containers failed") - ); - // @formatter:on + private void assertReportsError(Class invalidTestClass, Class annotationType) { + var results = discoverTestsForClass(invalidTestClass); + + assertThat(results.getDiscoveryIssues()) // + .filteredOn(where(DiscoveryIssue::severity, isEqual(Severity.ERROR))) // + .extracting(DiscoveryIssue::message) // + .asString().contains("@%s method".formatted(annotationType.getSimpleName())); } // ------------------------------------------------------------------------- - static class TestCase { - - @Test - void test() { - } - } - + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithInvalidNonStaticBeforeAllMethod { // must be static + @SuppressWarnings("unused") @BeforeAll void beforeAll() { } @@ -92,9 +77,11 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithInvalidNonStaticAfterAllMethod { // must be static + @SuppressWarnings("unused") @AfterAll void afterAll() { } @@ -104,9 +91,11 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithInvalidStaticBeforeEachMethod { // must NOT be static + @SuppressWarnings("unused") @BeforeEach static void beforeEach() { } @@ -116,9 +105,11 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithInvalidStaticAfterEachMethod { // must NOT be static + @SuppressWarnings("unused") @AfterEach static void afterEach() { } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineBasicTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineBasicTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineBasicTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineBasicTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -/** - * Basic assertions regarding {@link org.junit.platform.engine.TestEngine} - * functionality in JUnit Jupiter. - * - * @since 5.0 - */ -class JupiterTestEngineBasicTests { - - private final JupiterTestEngine jupiter = new JupiterTestEngine(); - - @Test - void id() { - assertEquals("junit-jupiter", jupiter.getId()); - } - - @Test - void groupId() { - assertEquals("org.junit.jupiter", jupiter.getGroupId().orElseThrow()); - } - - @Test - void artifactId() { - assertEquals("junit-jupiter-engine", jupiter.getArtifactId().orElseThrow()); - } - - @Test - void version() { - assertThat(jupiter.getVersion().orElseThrow()).isIn( // - System.getProperty("developmentVersion"), // with Test Distribution - "DEVELOPMENT" // without Test Distribution - ); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/JupiterTestEngineTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; +import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.EngineExecutionListener; +import org.junit.platform.engine.ExecutionRequest; +import org.junit.platform.launcher.core.NamespacedHierarchicalStoreProviders; + +/** + * @since 5.13 + */ +public class JupiterTestEngineTests { + + private final JupiterEngineDescriptor jupiterEngineDescriptor = mock(); + + private final ConfigurationParameters configurationParameters = mock(); + + private final EngineExecutionListener engineExecutionListener = mock(); + + private final ExecutionRequest executionRequest = mock(); + + private final JupiterTestEngine engine = new JupiterTestEngine(); + + private final JupiterTestEngine jupiter = new JupiterTestEngine(); + + @BeforeEach + void setUp() { + when(executionRequest.getEngineExecutionListener()).thenReturn(engineExecutionListener); + when(executionRequest.getConfigurationParameters()).thenReturn(configurationParameters); + when(executionRequest.getRootTestDescriptor()).thenReturn(jupiterEngineDescriptor); + } + + @Test + void createExecutionContextWithValidRequest() { + when(executionRequest.getStore()).thenReturn( + NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStore()); + + JupiterEngineExecutionContext context = engine.createExecutionContext(executionRequest); + assertThat(context).isNotNull(); + } + + @Test + void createExecutionContextWithNoParentsRequestLevelStore() { + when(executionRequest.getStore()).thenReturn( + NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStoreWithNoParent()); + + assertThatThrownBy(() -> engine // + .createExecutionContext(executionRequest)) // + .isInstanceOf(JUnitException.class) // + .hasMessageContaining("Request-level store must have a parent"); + } + + @Test + void id() { + assertEquals("junit-jupiter", jupiter.getId()); + } + + @Test + void groupId() { + assertEquals("org.junit.jupiter", jupiter.getGroupId().orElseThrow()); + } + + @Test + void artifactId() { + assertEquals("junit-jupiter-engine", jupiter.getArtifactId().orElseThrow()); + } + + @Test + void version() { + assertThat(jupiter.getVersion().orElseThrow()).isIn( // + System.getProperty("developmentVersion"), // with Test Distribution + "DEVELOPMENT" // without Test Distribution + ); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/LifecycleMethodOverridingTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/LifecycleMethodOverridingTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/LifecycleMethodOverridingTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/LifecycleMethodOverridingTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,18 +10,15 @@ package org.junit.jupiter.engine; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; -import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; - -import java.util.logging.Level; -import java.util.logging.LogRecord; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.RepetitionInfo; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.fixtures.TrackLogRecords; -import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.MethodSource; /** * Integration tests that verify the correct behavior for methods annotated @@ -32,21 +29,27 @@ class MultipleTestableAnnotationsTests extends AbstractJupiterTestEngineTests { @Test - void testAndRepeatedTest(@TrackLogRecords LogRecordListener listener) { - discoverTests(request().selectors(selectClass(TestCase.class)).build()); + void testAndRepeatedTest() throws Exception { + var results = discoverTestsForClass(TestCase.class); + + var discoveryIssue = getOnlyElement(results.getDiscoveryIssues()); - // @formatter:off - assertTrue(listener.stream(Level.WARNING) - .map(LogRecord::getMessage) - .anyMatch(m -> m.matches("Possible configuration error: method .+ resulted in multiple TestDescriptors .+"))); - // @formatter:on + assertThat(discoveryIssue.severity()) // + .isEqualTo(Severity.WARNING); + assertThat(discoveryIssue.message()) // + .matches("Possible configuration error: method .+ resulted in multiple TestDescriptors .+"); + assertThat(discoveryIssue.source()) // + .contains( + MethodSource.from(TestCase.class.getDeclaredMethod("testAndRepeatedTest", RepetitionInfo.class))); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase { @Test @RepeatedTest(1) void testAndRepeatedTest(RepetitionInfo repetitionInfo) { + assertNotNull(repetitionInfo); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedTestClassesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedTestClassesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedTestClassesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedTestClassesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,26 +11,42 @@ package org.junit.jupiter.engine; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.util.Throwables.getRootCause; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; -import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; +import static org.junit.platform.launcher.LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +import java.util.function.Consumer; +import java.util.regex.Pattern; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.engine.NestedTestClassesTests.OuterClass.NestedClass; import org.junit.jupiter.engine.NestedTestClassesTests.OuterClass.NestedClass.RecursiveNestedClass; import org.junit.jupiter.engine.NestedTestClassesTests.OuterClass.NestedClass.RecursiveNestedSiblingClass; -import org.junit.platform.commons.JUnitException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.descriptor.ClassSource; import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import org.junit.platform.testkit.engine.EngineExecutionResults; import org.junit.platform.testkit.engine.Events; @@ -44,29 +60,46 @@ @Test void nestedTestsAreCorrectlyDiscovered() { - LauncherDiscoveryRequest request = request().selectors(selectClass(TestCaseWithNesting.class)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(TestCaseWithNesting.class)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(5, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } - @Test - void nestedTestsAreExecuted() { - EngineExecutionResults executionResults = executeTestsForClass(TestCaseWithNesting.class); - Events containers = executionResults.containerEvents(); - Events tests = executionResults.testEvents(); + @ParameterizedTest(name = "{0}") + @MethodSource + void nestedTestsAreExecutedInTheRightOrder(Consumer configurer) { + EngineExecutionResults executionResults = executeTests(configurer); + Events tests = executionResults.testEvents(); assertEquals(3, tests.started().count(), "# tests started"); assertEquals(2, tests.succeeded().count(), "# tests succeeded"); assertEquals(1, tests.failed().count(), "# tests failed"); + assertThat(tests.started().map(it -> it.getTestDescriptor().getDisplayName())) // + .containsExactlyInAnyOrder("someTest()", "successful()", "failing()") // + .containsSubsequence("someTest()", "successful()") // + .containsSubsequence("someTest()", "failing()"); + + Events containers = executionResults.containerEvents(); assertEquals(3, containers.started().count(), "# containers started"); assertEquals(3, containers.finished().count(), "# containers finished"); } + static List>> nestedTestsAreExecutedInTheRightOrder() { + return List.of( // + Named.of("class selector", request -> request // + .selectors(selectClass(TestCaseWithNesting.class))), + Named.of("package selector", request -> request // + .selectors(selectPackage(TestCaseWithNesting.class.getPackageName())) // + .filters(includeClassNamePatterns(Pattern.quote(TestCaseWithNesting.class.getName()) + ".*"))) // + ); + } + @Test void doublyNestedTestsAreCorrectlyDiscovered() { - LauncherDiscoveryRequest request = request().selectors(selectClass(TestCaseWithDoubleNesting.class)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + LauncherDiscoveryRequest request = defaultRequest().selectors( + selectClass(TestCaseWithDoubleNesting.class)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(8, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @@ -97,7 +130,14 @@ @Test void inheritedNestedTestsAreExecuted() { - EngineExecutionResults executionResults = executeTestsForClass(TestCaseWithInheritedNested.class); + var discoveryIssues = discoverTestsForClass(TestCaseWithInheritedNested.class).getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().source()) // + .contains(ClassSource.from(InterfaceWithNestedClass.NestedInInterface.class)); + + var executionResults = executeTests(request -> request // + .selectors(selectClass(TestCaseWithInheritedNested.class)) // + .configurationParameter(CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, Severity.ERROR.name())); Events containers = executionResults.containerEvents(); Events tests = executionResults.testEvents(); @@ -111,8 +151,14 @@ @Test void extendedNestedTestsAreExecuted() { - EngineExecutionResults executionResults = executeTestsForClass(TestCaseWithExtendedNested.class); - executionResults.allEvents().debug(); + var discoveryIssues = discoverTestsForClass(TestCaseWithExtendedNested.class).getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().source()) // + .contains(ClassSource.from(InterfaceWithNestedClass.NestedInInterface.class)); + + var executionResults = executeTests(request -> request // + .selectors(selectClass(TestCaseWithExtendedNested.class)) // + .configurationParameter(CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, Severity.ERROR.name())); Events containers = executionResults.containerEvents(); Events tests = executionResults.testEvents(); @@ -126,11 +172,21 @@ @Test void deeplyNestedInheritedMethodsAreExecutedWhenSelectedViaUniqueId() { - EngineExecutionResults executionResults = executeTests(selectUniqueId( - "[engine:junit-jupiter]/[class:org.junit.jupiter.engine.NestedTestClassesTests$TestCaseWithExtendedNested]/[nested-class:ConcreteInner1]/[nested-class:NestedInAbstractClass]/[nested-class:SecondLevelInherited]/[method:test()]"), + var selectors = List.of( // + selectUniqueId( + "[engine:junit-jupiter]/[class:org.junit.jupiter.engine.NestedTestClassesTests$TestCaseWithExtendedNested]/[nested-class:ConcreteInner1]/[nested-class:NestedInAbstractClass]/[nested-class:SecondLevelInherited]/[method:test()]"), selectUniqueId( "[engine:junit-jupiter]/[class:org.junit.jupiter.engine.NestedTestClassesTests$TestCaseWithExtendedNested]/[nested-class:ConcreteInner2]/[nested-class:NestedInAbstractClass]/[nested-class:SecondLevelInherited]/[method:test()]")); - executionResults.allEvents().debug(); + + var discoveryIssues = discoverTests(request -> request.selectors(selectors)).getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().source()) // + .contains(ClassSource.from(InterfaceWithNestedClass.NestedInInterface.class)); + + var executionResults = executeTests(request -> request // + .selectors(selectors) // + .configurationParameter(CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, Severity.ERROR.name())); + Events containers = executionResults.containerEvents(); Events tests = executionResults.testEvents(); @@ -179,17 +235,83 @@ executionResults.testEvents().assertStatistics(stats -> stats.started(1).succeeded(1)); } + @Test + void doesNotReportDiscoveryIssueForClassWithAbstractInnerClass() { + var discoveryIssues = discoverTestsForClass(ConcreteWithExtendedInnerClassTestCase.class).getDiscoveryIssues(); + + assertThat(discoveryIssues).isEmpty(); + } + + @Test + void doesNotReportDiscoveryIssueForAbstractInnerClass() { + var discoveryIssues = discoverTestsForClass( + AbstractBaseWithInnerClassTestCase.AbstractInnerClass.class).getDiscoveryIssues(); + + assertThat(discoveryIssues).isEmpty(); + } + + @Test + void nestedTestsWithCustomAnnotationAreCorrectlyDiscovered() { + LauncherDiscoveryRequest request = defaultRequest().selectors( + selectClass(CustomAnnotationTestCase.class)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); + assertEquals(3, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + } + + @ParameterizedTest + @ValueSource(classes = { TopLevelComposedNested.class, CustomAnnotationTestCase.MyNested.class }) + void ignoresComposedAnnotations(Class annotationType) { + LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(annotationType)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); + assertEquals(0, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + } + private void assertNestedCycle(Class start, Class from, Class to) { - assertThatExceptionOfType(JUnitException.class)// - .isThrownBy(() -> executeTestsForClass(start))// - .withCauseExactlyInstanceOf(JUnitException.class)// - .satisfies(ex -> assertThat(getRootCause(ex)).hasMessageMatching( - String.format("Detected cycle in inner class hierarchy between .+%s and .+%s", from.getSimpleName(), - to.getSimpleName()))); + var results = executeTestsForClass(start); + var expectedMessage = String.format( + "Cause: org.junit.platform.commons.JUnitException: Detected cycle in inner class hierarchy between %s and %s", + from.getName(), to.getName()); + results.containerEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message(it -> it.contains(expectedMessage)))); + } + + @Test + void discoversButWarnsAboutTopLevelNestedTestClasses() { + var results = discoverTestsForClass(TopLevelNestedTestCase.class); + + var engineDescriptor = results.getEngineDescriptor(); + assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + + var discoveryIssues = results.getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo( + "Top-level class '%s' must not be annotated with @Nested. " + + "It will be executed anyway for backward compatibility. " + + "You should remove the @Nested annotation to resolve this warning.", + TopLevelNestedTestCase.class.getName()); + } + + @Test + void discoversButWarnsAboutStaticNestedTestClasses() { + var results = discoverTestsForClass(StaticNestedTestCase.TestCase.class); + + var engineDescriptor = results.getEngineDescriptor(); + assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + + var discoveryIssues = results.getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo( + "@Nested class '%s' must not be static. " + + "It will only be executed if discovered as a standalone test class. " + + "You should remove the annotation or make it non-static to resolve this warning.", + StaticNestedTestCase.TestCase.class.getName()); } // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithNesting { @Test @@ -210,6 +332,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithDoubleNesting { static int beforeTopCount = 0; @@ -283,6 +406,7 @@ interface InterfaceWithNestedClass { + @SuppressWarnings({ "JUnitMalformedDeclaration", "NewClassNamingConvention" }) @Nested class NestedInInterface { @@ -334,6 +458,7 @@ static class AbstractOuterClass { } + @SuppressWarnings({ "JUnitMalformedDeclaration", "NewClassNamingConvention" }) static class OuterClass extends AbstractOuterClass { @Test @@ -365,5 +490,39 @@ } } } + + static class AbstractBaseWithInnerClassTestCase { + @SuppressWarnings("InnerClassMayBeStatic") + abstract class AbstractInnerClass { + @Test + void test() { + } + } + } + + static class ConcreteWithExtendedInnerClassTestCase extends AbstractBaseWithInnerClassTestCase { + @Nested + class NestedTests extends AbstractInnerClass { + } + } + + static class CustomAnnotationTestCase { + + @Nested + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @interface MyNested { + } + + @SuppressWarnings({ "JUnitMalformedDeclaration", "InnerClassMayBeStatic" }) + @MyNested + class Inner { + + @Test + void test() { + + } + } + } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithInheritanceTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithInheritanceTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithInheritanceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithInheritanceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithSeparateInheritanceTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithSeparateInheritanceTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithSeparateInheritanceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NestedWithSeparateInheritanceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NonVoidTestableMethodIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NonVoidTestableMethodIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NonVoidTestableMethodIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/NonVoidTestableMethodIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine; - -import static org.junit.jupiter.api.Assertions.fail; - -import org.junit.jupiter.api.RepeatedTest; -import org.junit.jupiter.api.Test; - -class NonVoidTestableMethodIntegrationTests { - - @Test - void valid() { - } - - @Test - int invalidMethodReturningPrimitive() { - fail("This method should never have been called."); - return 1; - } - - @Test - String invalidMethodReturningObject() { - fail("This method should never have been called."); - return ""; - } - - @RepeatedTest(3) - int invalidMethodVerifyingTestTemplateMethod() { - fail("This method should never have been called."); - return 1; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/OverloadedTestMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/OverloadedTestMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/OverloadedTestMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/OverloadedTestMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -53,7 +53,7 @@ } @Test - void executeTestCaseWithOverloadedMethodsWithSingleMethodThatAcceptsArgumentsSelectedByFullyQualifedMethodName() { + void executeTestCaseWithOverloadedMethodsWithSingleMethodThatAcceptsArgumentsSelectedByFullyQualifiedMethodName() { String fqmn = TestCase.class.getName() + "#test(" + TestInfo.class.getName() + ")"; Events tests = executeTests(selectMethod(fqmn)).testEvents(); @@ -64,6 +64,7 @@ assertTrue(first.isPresent()); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/RecordTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/RecordTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/RecordTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/RecordTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -23,6 +23,7 @@ .assertStatistics(stats -> stats.finished(2).succeeded(1).failed(1)); } + @SuppressWarnings("JUnitMalformedDeclaration") record TestCase() { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ReportingTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ReportingTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ReportingTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/ReportingTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,49 +10,109 @@ package org.junit.jupiter.engine; -import static java.util.Collections.emptyMap; import static org.junit.jupiter.api.Assertions.assertThrows; - +import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.hierarchicalOutputDirectoryCreator; +import static org.junit.platform.testkit.engine.EventConditions.fileEntry; +import static org.junit.platform.testkit.engine.EventConditions.reportEntry; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MediaType; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.engine.reporting.FileEntry; /** * @since 5.0 */ class ReportingTests extends AbstractJupiterTestEngineTests { - @Test - void reportEntriesArePublished() { - executeTestsForClass(MyReportingTestCase.class).testEvents().assertStatistics(stats -> stats // - .started(2) // - .succeeded(2) // - .failed(0) // - .reportingEntryPublished(7)); + @ParameterizedTest + @CsvSource(textBlock = """ + PER_CLASS, 1, 7, 5 + PER_METHOD, 0, 9, 7 + """) + void reportAndFileEntriesArePublished(Lifecycle lifecycle, int containerEntries, int testReportEntries, + int testFileEntries, @TempDir Path tempDir) { + var request = request() // + .selectors(selectClass(MyReportingTestCase.class)) // + .configurationParameter(DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME, lifecycle.name()) // + .outputDirectoryCreator(hierarchicalOutputDirectoryCreator(tempDir)); + + var results = executeTests(request); + + results // + .containerEvents() // + .assertStatistics(stats -> stats // + .started(2) // + .succeeded(2) // + .reportingEntryPublished(containerEntries) // + .fileEntryPublished(containerEntries)); + + results // + .testEvents() // + .assertStatistics(stats -> stats // + .started(2) // + .succeeded(2) // + .reportingEntryPublished(testReportEntries) // + .fileEntryPublished(testFileEntries)) // + .assertThatEvents() // + .haveExactly(2, reportEntry(Map.of("value", "@BeforeEach"))) // + .haveExactly(2, fileEntry(nameAndContent("beforeEach", MediaType.TEXT_PLAIN_UTF_8))) // + .haveExactly(1, reportEntry(Map.of())) // + .haveExactly(1, reportEntry(Map.of("user name", "dk38"))) // + .haveExactly(1, reportEntry(Map.of("value", "message"))) // + .haveExactly(1, fileEntry(nameAndContent("succeedingTest", MediaType.APPLICATION_OCTET_STREAM))) // + .haveExactly(2, reportEntry(Map.of("value", "@AfterEach"))) // + .haveExactly(2, fileEntry(nameAndContent("afterEach", MediaType.TEXT_PLAIN_UTF_8))); } + @SuppressWarnings("JUnitMalformedDeclaration") static class MyReportingTestCase { + public MyReportingTestCase(TestReporter reporter) { + // Reported on class-level for PER_CLASS lifecycle and on method-level for PER_METHOD lifecycle + reporter.publishEntry("Constructor"); + reporter.publishFile("constructor", MediaType.TEXT_PLAIN_UTF_8, + file -> Files.writeString(file, "constructor")); + } + @BeforeEach void beforeEach(TestReporter reporter) { reporter.publishEntry("@BeforeEach"); + reporter.publishFile("beforeEach", MediaType.TEXT_PLAIN_UTF_8, + file -> Files.writeString(file, "beforeEach")); } @AfterEach void afterEach(TestReporter reporter) { reporter.publishEntry("@AfterEach"); + reporter.publishFile("afterEach", MediaType.TEXT_PLAIN_UTF_8, file -> Files.writeString(file, "afterEach")); } @Test void succeedingTest(TestReporter reporter) { - reporter.publishEntry(emptyMap()); + reporter.publishEntry(Map.of()); reporter.publishEntry("user name", "dk38"); reporter.publishEntry("message"); + reporter.publishFile("succeedingTest", MediaType.APPLICATION_OCTET_STREAM, + file -> Files.writeString(file, "succeedingTest")); } @Test @@ -80,4 +140,17 @@ } + private static Predicate nameAndContent(String expectedName, MediaType mediaType) { + Predicate filePredicate = file -> { + try { + return Path.of(expectedName).equals(file.getFileName()) && expectedName.equals(Files.readString(file)); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + return fileEntry -> filePredicate.test(fileEntry.getPath()) // + && mediaType.toString().equals(fileEntry.getMediaType().orElse(null)); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/SealedClassTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/SealedClassTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/SealedClassTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/SealedClassTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StandardTestClassTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StandardTestClassTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StandardTestClassTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StandardTestClassTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -37,7 +37,7 @@ @Test void standardTestClassIsCorrectlyDiscovered() { LauncherDiscoveryRequest request = request().selectors(selectClass(MyStandardTestCase.class)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor(); assertEquals(1 /*class*/ + 6 /*methods*/, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @@ -45,7 +45,7 @@ @Test void moreThanOneTestClassIsCorrectlyDiscovered() { LauncherDiscoveryRequest request = request().selectors(selectClass(SecondOfTwoTestCases.class)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor(); assertEquals(1 /*class*/ + 3 /*methods*/, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @@ -118,6 +118,7 @@ assertTrue(TestCaseWithFailingAfter.testExecuted, "test executed?"); } + @SuppressWarnings("JUnitMalformedDeclaration") static class MyStandardTestCase { static int countBefore1 = 0; @@ -175,6 +176,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FirstOfTwoTestCases { @Test @@ -194,6 +196,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class SecondOfTwoTestCases { @Test @@ -213,6 +216,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithFailingBefore { static int countBefore = 0; @@ -233,6 +237,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithFailingAfter { static boolean testExecuted = false; diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedBeforeAllAndAfterAllMethodsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedBeforeAllAndAfterAllMethodsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedBeforeAllAndAfterAllMethodsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedBeforeAllAndAfterAllMethodsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -49,6 +49,7 @@ ); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase { @BeforeAll diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/StaticNestedTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class StaticNestedTestCase { + + @SuppressWarnings("JUnitMalformedDeclaration") + @Nested + static class TestCase { + @Test + void test() { + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestClassInheritanceTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestClassInheritanceTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestClassInheritanceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestClassInheritanceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -157,6 +157,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class LocalTestCase extends AbstractTestCase { boolean throwExceptionInAfterMethod = false; @@ -252,6 +253,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase3 extends TestCase2 { @BeforeAll diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleConfigurationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleConfigurationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleConfigurationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleConfigurationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,7 @@ import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.launcher.LauncherConstants.DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import java.util.ArrayList; @@ -73,7 +74,7 @@ Class testClass = AssumedInstancePerClassTestCase.class; // Should fail by default... - performAssertions(testClass, 2, 1, 0); + performAssertions(testClass, 1, 1, 0); // Should pass with the system property set System.setProperty(KEY, PER_CLASS.name()); @@ -85,7 +86,7 @@ Class testClass = AssumedInstancePerClassTestCase.class; // Should fail by default... - performAssertions(testClass, 2, 1, 0); + performAssertions(testClass, 1, 1, 0); // Should pass with the config param performAssertions(testClass, singletonMap(KEY, PER_CLASS.name()), 2, 0, 1, "beforeAll", "test", "afterAll"); @@ -97,7 +98,7 @@ // Should fail with system property System.setProperty(KEY, PER_METHOD.name()); - performAssertions(testClass, 2, 1, 0); + performAssertions(testClass, 1, 1, 0); // Should pass with the config param performAssertions(testClass, singletonMap(KEY, PER_CLASS.name()), 2, 0, 1, "beforeAll", "test", "afterAll"); @@ -129,6 +130,7 @@ request() .selectors(selectClass(testClass)) .configurationParameters(configParams) + .configurationParameter(DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME, "execution") .build() ); // @formatter:on @@ -143,6 +145,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @TestInstance(PER_METHOD) static class ExplicitInstancePerTestMethodTestCase { @@ -168,6 +171,7 @@ * {@code @AfterAll} methods are static, even though there is no explicit * {@code @TestInstance} declaration. */ + @SuppressWarnings("JUnitMalformedDeclaration") static class AssumedInstancePerTestMethodTestCase { @BeforeAll @@ -187,6 +191,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @TestInstance(PER_CLASS) static class ExplicitInstancePerClassTestCase { @@ -212,8 +217,10 @@ * {@code @AfterAll} methods are non-static, even though there is no * explicit {@code @TestInstance} declaration. */ + @SuppressWarnings("JUnitMalformedDeclaration") static class AssumedInstancePerClassTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @BeforeAll void beforeAll(TestInfo testInfo) { methodsInvoked.add("beforeAll"); @@ -224,6 +231,7 @@ methodsInvoked.add("test"); } + @SuppressWarnings("JUnitMalformedDeclaration") @AfterAll void afterAll(TestInfo testInfo) { methodsInvoked.add("afterAll"); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleKotlinTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleKotlinTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleKotlinTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleKotlinTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestInstanceLifecycleTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,7 +19,8 @@ import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -30,12 +31,14 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Stream; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.ClassTemplate; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; @@ -46,6 +49,8 @@ import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContextProvider; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExecutionCondition; import org.junit.jupiter.api.extension.ExtendWith; @@ -56,6 +61,8 @@ import org.junit.jupiter.api.extension.TestTemplateInvocationContext; import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; import org.junit.jupiter.engine.execution.DefaultTestInstances; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.junit.platform.testkit.engine.EngineExecutionResults; /** @@ -106,7 +113,7 @@ String beforeAllCallbackKey = beforeAllCallbackKey(testClass); String afterAllCallbackKey = afterAllCallbackKey(testClass); String testTemplateKey = testTemplateKey(testClass, "singletonTest"); - String testExecutionConditionKey1 = executionConditionKey(testClass, testsInvoked.get(0)); + String testExecutionConditionKey1 = executionConditionKey(testClass, testsInvoked.getFirst()); String beforeEachCallbackKey1 = beforeEachCallbackKey(testClass, testsInvoked.get(0)); String afterEachCallbackKey1 = afterEachCallbackKey(testClass, testsInvoked.get(0)); String testExecutionConditionKey2 = executionConditionKey(testClass, testsInvoked.get(1)); @@ -188,7 +195,7 @@ String preDestroyCallbackTestInstanceKey = preDestroyCallbackTestInstanceKey(testClass); String beforeAllCallbackKey = beforeAllCallbackKey(testClass); String afterAllCallbackKey = afterAllCallbackKey(testClass); - String testExecutionConditionKey1 = executionConditionKey(testClass, testsInvoked.get(0)); + String testExecutionConditionKey1 = executionConditionKey(testClass, testsInvoked.getFirst()); String beforeEachCallbackKey1 = beforeEachCallbackKey(testClass, testsInvoked.get(0)); String afterEachCallbackKey1 = afterEachCallbackKey(testClass, testsInvoked.get(0)); String testExecutionConditionKey2 = executionConditionKey(testClass, testsInvoked.get(1)); @@ -267,7 +274,7 @@ String afterEachCallbackKey = afterEachCallbackKey(testClass, "outerTest"); String nestedBeforeAllCallbackKey = beforeAllCallbackKey(nestedTestClass); String nestedAfterAllCallbackKey = afterAllCallbackKey(nestedTestClass); - String nestedExecutionConditionKey1 = executionConditionKey(nestedTestClass, testsInvoked.get(0)); + String nestedExecutionConditionKey1 = executionConditionKey(nestedTestClass, testsInvoked.getFirst()); String nestedBeforeEachCallbackKey1 = beforeEachCallbackKey(nestedTestClass, testsInvoked.get(0)); String nestedAfterEachCallbackKey1 = afterEachCallbackKey(nestedTestClass, testsInvoked.get(0)); String nestedExecutionConditionKey2 = executionConditionKey(nestedTestClass, testsInvoked.get(1)); @@ -389,7 +396,7 @@ String afterEachCallbackKey = afterEachCallbackKey(testClass, "outerTest"); String nestedBeforeAllCallbackKey = beforeAllCallbackKey(nestedTestClass); String nestedAfterAllCallbackKey = afterAllCallbackKey(nestedTestClass); - String nestedExecutionConditionKey1 = executionConditionKey(nestedTestClass, testsInvoked.get(0)); + String nestedExecutionConditionKey1 = executionConditionKey(nestedTestClass, testsInvoked.getFirst()); String nestedBeforeEachCallbackKey1 = beforeEachCallbackKey(nestedTestClass, testsInvoked.get(0)); String nestedAfterEachCallbackKey1 = afterEachCallbackKey(nestedTestClass, testsInvoked.get(0)); String nestedExecutionConditionKey2 = executionConditionKey(nestedTestClass, testsInvoked.get(1)); @@ -509,7 +516,7 @@ String afterEachCallbackKey = afterEachCallbackKey(testClass, "outerTest"); String nestedBeforeAllCallbackKey = beforeAllCallbackKey(nestedTestClass); String nestedAfterAllCallbackKey = afterAllCallbackKey(nestedTestClass); - String nestedExecutionConditionKey1 = executionConditionKey(nestedTestClass, testsInvoked.get(0)); + String nestedExecutionConditionKey1 = executionConditionKey(nestedTestClass, testsInvoked.getFirst()); String nestedBeforeEachCallbackKey1 = beforeEachCallbackKey(nestedTestClass, testsInvoked.get(0)); String nestedAfterEachCallbackKey1 = afterEachCallbackKey(nestedTestClass, testsInvoked.get(0)); String nestedExecutionConditionKey2 = executionConditionKey(nestedTestClass, testsInvoked.get(1)); @@ -601,6 +608,44 @@ assertThat(lifecyclesMap.get(nestedTestClass).stream()).allMatch(Lifecycle.PER_CLASS::equals); } + @ParameterizedTest + @EnumSource(Lifecycle.class) + void classTemplate(Lifecycle lifecycle) { + var classTemplate = ClassTemplateWithDefaultLifecycleTestCase.class; + + var results = executeTests(r -> r // + .selectors(selectClass(classTemplate)) // + .configurationParameter(Constants.DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME, lifecycle.name())); + + results.allEvents().assertStatistics(stats -> stats.failed(0)); + results.testEvents().assertStatistics(stats -> stats.succeeded(4)); + + assertThat(instanceCount).containsExactly(entry(classTemplate, lifecycle == Lifecycle.PER_CLASS ? 1 : 4)); + assertThat(lifecyclesMap.keySet()).containsExactly(classTemplate); + assertThat(lifecyclesMap.get(classTemplate)).filteredOn(Objects::nonNull).containsOnly(lifecycle); + } + + @ParameterizedTest + @EnumSource(Lifecycle.class) + void classTemplateWithNestedClass(Lifecycle lifecycle) { + var classTemplate = ClassTemplateWithDefaultLifecycleAndNestedClassTestCase.class; + var nestedClass = ClassTemplateWithDefaultLifecycleAndNestedClassTestCase.InnerTestCase.class; + + var results = executeTests(r -> r // + .selectors(selectClass(classTemplate)) // + .configurationParameter(Constants.DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME, lifecycle.name())); + + results.allEvents().assertStatistics(stats -> stats.failed(0)); + results.testEvents().assertStatistics(stats -> stats.succeeded(4)); + + assertThat(instanceCount).containsExactly( // + entry(classTemplate, lifecycle == Lifecycle.PER_CLASS ? 1 : 4), // + entry(nestedClass, lifecycle == Lifecycle.PER_CLASS ? 2 : 4)); + assertThat(lifecyclesMap.keySet()).containsExactlyInAnyOrder(classTemplate, nestedClass); + assertThat(lifecyclesMap.get(classTemplate)).filteredOn(Objects::nonNull).containsOnly(lifecycle); + assertThat(lifecyclesMap.get(nestedClass)).filteredOn(Objects::nonNull).containsOnly(lifecycle); + } + private void performAssertions(Class testClass, int numContainers, int numTests, Map.Entry, Integer>[] instanceCountEntries, int allMethods, int eachMethods) { @@ -623,7 +668,7 @@ @SafeVarargs @SuppressWarnings("varargs") - private final Map.Entry, Integer>[] instanceCounts(Map.Entry, Integer>... entries) { + private Map.Entry, Integer>[] instanceCounts(Map.Entry, Integer>... entries) { return entries; } @@ -677,6 +722,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(InstanceTrackingExtension.class) // The following is commented out b/c it's the default. // @TestInstance(Lifecycle.PER_METHOD) @@ -752,6 +798,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(InstanceTrackingExtension.class) // The following is commented out b/c it's the default. // @TestInstance(Lifecycle.PER_METHOD) @@ -817,6 +864,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(InstanceTrackingExtension.class) @TestInstance(Lifecycle.PER_CLASS) static class InstancePerClassOuterTestCase { @@ -892,6 +940,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(InstanceTrackingExtension.class) // The following is commented out b/c it's the default. // @TestInstance(Lifecycle.PER_METHOD) @@ -979,7 +1028,9 @@ String testMethod = context.getTestMethod().map(Method::getName).orElse(null); if (testMethod == null) { assertThat(context.getTestInstance()).isNotPresent(); - assertThat(instanceCount.getOrDefault(context.getRequiredTestClass(), 0)).isEqualTo(0); + if (!isAnnotated(context.getRequiredTestClass().getEnclosingClass(), ClassTemplate.class)) { + assertThat(instanceCount.getOrDefault(context.getRequiredTestClass(), 0)).isEqualTo(0); + } } instanceMap.put(executionConditionKey(context.getRequiredTestClass(), testMethod), context.getTestInstances().orElse(null)); @@ -992,8 +1043,7 @@ trackLifecycle(context); assertThat(context.getTestInstance()).isNotPresent(); assertNotNull(testInstance); - instanceMap.put(postProcessTestInstanceKey(context.getRequiredTestClass()), - DefaultTestInstances.of(testInstance)); + instanceMap.put(postProcessTestInstanceKey(testInstance.getClass()), DefaultTestInstances.of(testInstance)); } @Override @@ -1064,4 +1114,65 @@ @interface SingletonTest { } + @SuppressWarnings("JUnitMalformedDeclaration") + @ClassTemplate + @ExtendWith(Twice.class) + @ExtendWith(InstanceTrackingExtension.class) + static class ClassTemplateWithDefaultLifecycleTestCase { + + ClassTemplateWithDefaultLifecycleTestCase() { + incrementInstanceCount(ClassTemplateWithDefaultLifecycleTestCase.class); + } + + @Test + void test1() { + } + + @Test + void test2() { + } + } + + @ClassTemplate + @ExtendWith(Twice.class) + @ExtendWith(InstanceTrackingExtension.class) + static class ClassTemplateWithDefaultLifecycleAndNestedClassTestCase { + + ClassTemplateWithDefaultLifecycleAndNestedClassTestCase() { + incrementInstanceCount(ClassTemplateWithDefaultLifecycleAndNestedClassTestCase.class); + } + + @Nested + class InnerTestCase { + + public InnerTestCase() { + incrementInstanceCount(InnerTestCase.class); + } + + @Test + void test1() { + } + + @Test + void test2() { + } + } + } + + private static class Twice implements ClassTemplateInvocationContextProvider { + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts(ExtensionContext context) { + return Stream.of(new Ctx(), new Ctx()); + } + + private record Ctx() implements ClassTemplateInvocationContext { + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestMethodOverridingTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestMethodOverridingTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestMethodOverridingTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestMethodOverridingTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.engine.subpackage.SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.testkit.engine.EngineExecutionResults; + +/** + * @since 5.14.1 + */ +class TestMethodOverridingTests extends AbstractJupiterTestEngineTests { + + @Test + void bothPackagePrivateTestMethodsAreDiscovered() throws Exception { + var results = discoverTestsForClass(DuplicateTestMethodDueToPackagePrivateVisibilityTestCase.class); + var classDescriptor = getOnlyElement(results.getEngineDescriptor().getChildren()); + + var parentUniqueId = classDescriptor.getUniqueId(); + var inheritedMethodUniqueId = parentUniqueId.append("method", + "org.junit.jupiter.engine.subpackage.SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase#" + + "test(org.junit.jupiter.api.TestInfo, org.junit.jupiter.api.TestReporter)"); + var declaredMethodUniqueId = parentUniqueId.append("method", + "test(org.junit.jupiter.api.TestInfo, org.junit.jupiter.api.TestReporter)"); + + var inheritedMethod = SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase.class.getDeclaredMethod( + "test", TestInfo.class, TestReporter.class); + var declaredMethod = DuplicateTestMethodDueToPackagePrivateVisibilityTestCase.class.getDeclaredMethod("test", + TestInfo.class, TestReporter.class); + + assertThat(classDescriptor.getChildren()) // + .hasSize(2) // + .extracting(TestDescriptor::getUniqueId, TestMethodOverridingTests::getSourceMethod) // + .containsExactly(tuple(inheritedMethodUniqueId, inheritedMethod), + tuple(declaredMethodUniqueId, declaredMethod)); + + results = discoverTests(selectUniqueId(inheritedMethodUniqueId)); + classDescriptor = getOnlyElement(results.getEngineDescriptor().getChildren()); + assertThat(classDescriptor.getChildren()) // + .extracting(TestDescriptor::getUniqueId, TestMethodOverridingTests::getSourceMethod) // + .containsExactly(tuple(inheritedMethodUniqueId, inheritedMethod)); + + results = discoverTests(selectUniqueId(declaredMethodUniqueId)); + classDescriptor = getOnlyElement(results.getEngineDescriptor().getChildren()); + assertThat(classDescriptor.getChildren()) // + .extracting(TestDescriptor::getUniqueId, TestMethodOverridingTests::getSourceMethod) // + .containsExactly(tuple(declaredMethodUniqueId, declaredMethod)); + } + + @Test + void bothPackagePrivateTestMethodsAreExecuted() throws Exception { + var results = executeTestsForClass(DuplicateTestMethodDueToPackagePrivateVisibilityTestCase.class); + + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)); + assertThat(allReportEntries(results)) // + .containsExactly( + Map.of("invokedSuper", + SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase.class.getDeclaredMethod( + "test", TestInfo.class, TestReporter.class).toGenericString()), + Map.of("invokedChild", + DuplicateTestMethodDueToPackagePrivateVisibilityTestCase.class.getDeclaredMethod("test", + TestInfo.class, TestReporter.class).toGenericString())); + } + + private static Method getSourceMethod(TestDescriptor it) { + return ((MethodSource) it.getSource().orElseThrow()).getJavaMethod(); + } + + private static Stream> allReportEntries(EngineExecutionResults results) { + return results.allEvents().reportingEntryPublished() // + .map(event -> event.getRequiredPayload(ReportEntry.class)) // + .map(ReportEntry::getKeyValuePairs); + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class DuplicateTestMethodDueToPackagePrivateVisibilityTestCase + extends SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase { + + // @Override + @Test + void test(TestInfo testInfo, TestReporter reporter) { + reporter.publishEntry("invokedChild", testInfo.getTestMethod().orElseThrow().toGenericString()); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestTemplateInvocationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestTemplateInvocationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestTemplateInvocationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TestTemplateInvocationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,9 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; @@ -57,6 +60,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.Extension; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.ParameterResolver; @@ -353,9 +357,40 @@ wrappedInContainerEvents(MyTestTemplateTestCase.class, // event(container("templateWithSupportingProviderButNoInvocations"), started()), // event(container("templateWithSupportingProviderButNoInvocations"), - finishedWithFailure(message("None of the supporting TestTemplateInvocationContextProviders [" - + InvocationContextProviderThatSupportsEverythingButProvidesNothing.class.getSimpleName() - + "] provided a non-empty stream"))))); + finishedWithFailure(message( + "Provider [%s] did not provide any invocation contexts, but was expected to do so. ".formatted( + InvocationContextProviderThatSupportsEverythingButProvidesNothing.class.getSimpleName()) + + "You may override mayReturnZeroTestTemplateInvocationContexts() to allow this."))))); + } + + @Test + void templateWithSupportingProviderAllowingNoInvocationsDoesNotFail() { + LauncherDiscoveryRequest request = request().selectors( + selectMethod(MyTestTemplateTestCase.class, "templateWithSupportingProviderAllowingNoInvocations")).build(); + + EngineExecutionResults executionResults = executeTests(request); + + executionResults.allEvents().assertEventsMatchExactly( // + wrappedInContainerEvents(MyTestTemplateTestCase.class, + event(container("templateWithSupportingProviderAllowingNoInvocations"), started()), + event(container("templateWithSupportingProviderAllowingNoInvocations"), finishedSuccessfully()))); + } + + @Test + void templateWithMixedProvidersNoInvocationReportsFailure() { + LauncherDiscoveryRequest request = request().selectors(selectMethod(MyTestTemplateTestCase.class, + "templateWithMultipleProvidersAllowingAndRestrictingToProvideNothing")).build(); + + EngineExecutionResults executionResults = executeTests(request); + + executionResults.allEvents().assertEventsMatchExactly( // + wrappedInContainerEvents(MyTestTemplateTestCase.class, // + event(container("templateWithMultipleProvidersAllowingAndRestrictingToProvideNothing"), started()), // + event(container("templateWithMultipleProvidersAllowingAndRestrictingToProvideNothing"), + finishedWithFailure(message( + "Provider [%s] did not provide any invocation contexts, but was expected to do so. ".formatted( + InvocationContextProviderThatSupportsEverythingButProvidesNothing.class.getSimpleName()) + + "You may override mayReturnZeroTestTemplateInvocationContexts() to allow this."))))); } @Test @@ -377,6 +412,14 @@ event(container("templateWithCloseableStream"), finishedSuccessfully()))); } + @Test + void templateWithPreparations() { + var results = executeTestsForClass(TestTemplateWithPreparationsTestCase.class); + + assertTrue(CustomCloseableResource.closed, "resource in store was closed"); + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + private TestDescriptor findTestDescriptor(EngineExecutionResults executionResults, Condition condition) { // @formatter:off return executionResults.allEvents() @@ -470,6 +513,19 @@ fail("never called"); } + @ExtendWith(InvocationContextProviderThatSupportsEverythingAllowsProvideNothing.class) + @TestTemplate + void templateWithSupportingProviderAllowingNoInvocations() { + fail("never called"); + } + + @ExtendWith(InvocationContextProviderThatSupportsEverythingButProvidesNothing.class) + @ExtendWith(InvocationContextProviderThatSupportsEverythingAllowsProvideNothing.class) + @TestTemplate + void templateWithMultipleProvidersAllowingAndRestrictingToProvideNothing() { + fail("never called"); + } + @ExtendWith(InvocationContextProviderWithCloseableStream.class) @TestTemplate void templateWithCloseableStream() { @@ -769,6 +825,25 @@ } } + private static class InvocationContextProviderThatSupportsEverythingAllowsProvideNothing + implements TestTemplateInvocationContextProvider { + + @Override + public boolean supportsTestTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideTestTemplateInvocationContexts(ExtensionContext context) { + return Stream.empty(); + } + + @Override + public boolean mayReturnZeroTestTemplateInvocationContexts(ExtensionContext extensionContext) { + return true; + } + } + private static class InvocationContextProviderWithCloseableStream implements TestTemplateInvocationContextProvider { private static AtomicBoolean streamClosed = new AtomicBoolean(false); @@ -789,4 +864,74 @@ }; } + static class TestTemplateWithPreparationsTestCase { + + @TestTemplate + @ExtendWith({ PreparingTestTemplateInvocationContextProvider.class, CompanionExtension.class }) + void test(CustomCloseableResource resource) { + assertNotNull(resource); + assertFalse(CustomCloseableResource.closed, "should not be closed yet"); + } + + } + + private static class PreparingTestTemplateInvocationContextProvider + implements TestTemplateInvocationContextProvider { + + static final Namespace NAMESPACE = Namespace.create(PreparingTestTemplateInvocationContextProvider.class); + + @Override + public boolean supportsTestTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideTestTemplateInvocationContexts(ExtensionContext context) { + return Stream.of(new PreparingTestTemplateInvocationContext()); + } + + } + + private static class PreparingTestTemplateInvocationContext implements TestTemplateInvocationContext { + + @Override + public void prepareInvocation(ExtensionContext context) { + context.getStore(PreparingTestTemplateInvocationContextProvider.NAMESPACE) // + .put("resource", new CustomCloseableResource()); + } + + } + + private static class CompanionExtension implements ParameterResolver { + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return CustomCloseableResource.class.equals(parameterContext.getParameter().getType()); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return extensionContext.getStore(PreparingTestTemplateInvocationContextProvider.NAMESPACE).get("resource"); + } + + } + + private static class CustomCloseableResource implements AutoCloseable { + + static boolean closed; + + @Override + public void close() { + closed = true; + } + + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelComposedNested.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelComposedNested.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelComposedNested.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelComposedNested.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.Nested; + +@Nested +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface TopLevelComposedNested { +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelNestedTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelNestedTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelNestedTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/TopLevelNestedTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +@Nested +public class TopLevelNestedTestCase { + + @Test + void test() { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNonGenericTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNonGenericTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNonGenericTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNonGenericTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNumberTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNumberTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNumberTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/AbstractNumberTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/BridgeMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/BridgeMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/BridgeMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/BridgeMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithBridgeMethods.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithBridgeMethods.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithBridgeMethods.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithBridgeMethods.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithoutBridgeMethods.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithoutBridgeMethods.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithoutBridgeMethods.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/ChildWithoutBridgeMethods.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberTestGroup.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberTestGroup.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberTestGroup.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/NumberTestGroup.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/PackagePrivateParent.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/PackagePrivateParent.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/PackagePrivateParent.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/bridge/PackagePrivateParent.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,6 +17,7 @@ import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD; import static org.junit.jupiter.api.io.CleanupMode.ALWAYS; import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,20 +45,20 @@ @Test void getDefaultTestInstanceLifecyclePreconditions() { PreconditionViolationException exception = assertThrows(PreconditionViolationException.class, - () -> new DefaultJupiterConfiguration(null)); + () -> new DefaultJupiterConfiguration(null, dummyOutputDirectoryCreator())); assertThat(exception).hasMessage("ConfigurationParameters must not be null"); } @Test void getDefaultTestInstanceLifecycleWithNoConfigParamSet() { - JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock()); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock(), dummyOutputDirectoryCreator()); Lifecycle lifecycle = configuration.getDefaultTestInstanceLifecycle(); assertThat(lifecycle).isEqualTo(PER_METHOD); } @Test void getDefaultTempDirCleanupModeWithNoConfigParamSet() { - JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock()); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock(), dummyOutputDirectoryCreator()); CleanupMode cleanupMode = configuration.getDefaultTempDirCleanupMode(); assertThat(cleanupMode).isEqualTo(ALWAYS); } @@ -82,7 +83,7 @@ ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.of(CustomDisplayNameGenerator.class.getName())); - JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters, dummyOutputDirectoryCreator()); DisplayNameGenerator defaultDisplayNameGenerator = configuration.getDefaultDisplayNameGenerator(); @@ -94,7 +95,7 @@ ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.empty()); - JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters, dummyOutputDirectoryCreator()); DisplayNameGenerator defaultDisplayNameGenerator = configuration.getDefaultDisplayNameGenerator(); @@ -106,7 +107,7 @@ ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.empty()); - JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters, dummyOutputDirectoryCreator()); final Optional defaultTestMethodOrder = configuration.getDefaultTestMethodOrderer(); @@ -118,7 +119,7 @@ ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_TEMP_DIR_FACTORY_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.of(CustomFactory.class.getName())); - JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters, dummyOutputDirectoryCreator()); Supplier supplier = configuration.getDefaultTempDirFactorySupplier(); @@ -138,7 +139,7 @@ ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_TEMP_DIR_FACTORY_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.empty()); - JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters, dummyOutputDirectoryCreator()); Supplier supplier = configuration.getDefaultTempDirFactorySupplier(); @@ -148,7 +149,8 @@ private void assertDefaultConfigParam(String configValue, Lifecycle expected) { ConfigurationParameters configParams = mock(); when(configParams.get(KEY)).thenReturn(Optional.ofNullable(configValue)); - Lifecycle lifecycle = new DefaultJupiterConfiguration(configParams).getDefaultTestInstanceLifecycle(); + Lifecycle lifecycle = new DefaultJupiterConfiguration(configParams, + dummyOutputDirectoryCreator()).getDefaultTestInstanceLifecycle(); assertThat(lifecycle).isEqualTo(expected); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.jupiter.engine.descriptor; import java.lang.reflect.Method; +import java.util.List; import org.junit.jupiter.api.DisplayNameGenerator; @@ -22,12 +23,13 @@ } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return "nested-class-display-name"; } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return "method-display-name"; } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,6 +15,7 @@ import static org.mockito.Mockito.when; import java.lang.reflect.Method; +import java.util.List; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -24,7 +25,6 @@ import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.platform.commons.logging.LogRecordListener; @@ -47,15 +47,12 @@ } @Test - void shouldGetDisplayNameFromSupplierIfNoDisplayNameAnnotationWithBlankStringPresent( - @TrackLogRecords LogRecordListener listener) { + void shouldGetDisplayNameFromSupplierIfDisplayNameAnnotationProvidesBlankString() { String displayName = DisplayNameUtils.determineDisplayName(BlankDisplayNameTestCase.class, () -> "default-name"); assertThat(displayName).isEqualTo("default-name"); - assertThat(firstWarningLogRecord(listener).getMessage()).isEqualTo( - "Configuration error: @DisplayName on [class org.junit.jupiter.engine.descriptor.DisplayNameUtilsTests$BlankDisplayNameTestCase] must be declared with a non-empty value."); } @Test @@ -70,7 +67,7 @@ @Nested class ClassDisplayNameSupplierTests { - private JupiterConfiguration configuration = mock(); + private final JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() { @@ -115,12 +112,12 @@ @Nested class NestedClassDisplayNameTests { - private JupiterConfiguration configuration = mock(); + private final JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass( + Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass(List::of, StandardDisplayNameTestCase.class, configuration); assertThat(displayName.get()).isEqualTo(StandardDisplayNameTestCase.class.getSimpleName()); @@ -129,7 +126,7 @@ @Test void shouldGetDisplayNameFromDefaultDisplayNameGenerator() { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass( + Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass(List::of, NestedTestCase.class, configuration); assertThat(displayName.get()).isEqualTo("nested-class-display-name"); @@ -138,7 +135,7 @@ @Test void shouldFallbackOnDefaultDisplayNameGeneratorWhenNullIsGenerated() { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass( + Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass(List::of, NullDisplayNameTestCase.NestedTestCase.class, configuration); assertThat(displayName.get()).isEqualTo("nested-class-display-name"); @@ -148,14 +145,14 @@ @Nested class MethodDisplayNameTests { - private JupiterConfiguration configuration = mock(); + private final JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() throws Exception { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); Method method = MyTestCase.class.getDeclaredMethod("test1"); - String displayName = DisplayNameUtils.determineDisplayNameForMethod(StandardDisplayNameTestCase.class, - method, configuration); + String displayName = DisplayNameUtils.determineDisplayNameForMethod(List::of, + StandardDisplayNameTestCase.class, method, configuration); assertThat(displayName).isEqualTo("test1()"); } @@ -165,8 +162,8 @@ Method method = MyTestCase.class.getDeclaredMethod("test1"); when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - String displayName = DisplayNameUtils.determineDisplayNameForMethod(NotDisplayNameTestCase.class, method, - configuration); + String displayName = DisplayNameUtils.determineDisplayNameForMethod(List::of, NotDisplayNameTestCase.class, + method, configuration); assertThat(displayName).isEqualTo("method-display-name"); } @@ -176,8 +173,8 @@ Method method = NullDisplayNameTestCase.class.getDeclaredMethod("test"); when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - String displayName = DisplayNameUtils.determineDisplayNameForMethod(NullDisplayNameTestCase.class, method, - configuration); + String displayName = DisplayNameUtils.determineDisplayNameForMethod(List::of, NullDisplayNameTestCase.class, + method, configuration); assertThat(displayName).isEqualTo("method-display-name"); } @@ -188,7 +185,7 @@ () -> new AssertionError("Failed to find warning log record")); } - @DisplayName("my-test-case") + @DisplayName("my-test-case\t") @DisplayNameGeneration(value = CustomDisplayNameGenerator.class) static class MyTestCase { @@ -216,6 +213,7 @@ class NestedTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayNameGeneration(value = NullDisplayNameGenerator.class) static class NullDisplayNameTestCase { @@ -237,12 +235,13 @@ } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return null; } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return null; } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,19 +10,32 @@ package org.junit.jupiter.engine.descriptor; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.MediaType.TEXT_PLAIN; +import static org.junit.jupiter.api.MediaType.TEXT_PLAIN_UTF_8; import static org.junit.jupiter.api.Named.named; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullOrBlankFor; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.hierarchicalOutputDirectoryCreator; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.lang.reflect.Method; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -30,27 +43,35 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Named; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.Extension; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.PreInterruptCallback; +import org.junit.jupiter.api.function.ThrowingConsumer; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.parallel.ExecutionMode; import org.junit.jupiter.engine.config.DefaultJupiterConfiguration; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.execution.DefaultTestInstances; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import org.junit.platform.commons.PreconditionViolationException; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.hierarchical.OpenTest4JAwareThrowableCollector; +import org.junit.platform.launcher.core.NamespacedHierarchicalStoreProviders; import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; /** * Unit tests for concrete implementations of {@link ExtensionContext}: @@ -61,119 +82,173 @@ */ public class ExtensionContextTests { + private static final ThrowingConsumer failingAction = __ -> fail("should not be called"); + private final JupiterConfiguration configuration = mock(); + private final ExtensionRegistry extensionRegistry = mock(); + private final LauncherStoreFacade launcherStoreFacade = new LauncherStoreFacade( + NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStore()); @BeforeEach void setUp() { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); when(configuration.getDefaultExecutionMode()).thenReturn(ExecutionMode.SAME_THREAD); when(configuration.getDefaultClassesExecutionMode()).thenReturn(ExecutionMode.SAME_THREAD); + when(configuration.getOutputDirectoryCreator()).thenReturn(dummyOutputDirectoryCreator()); } @Test void fromJupiterEngineDescriptor() { - JupiterEngineDescriptor engineTestDescriptor = new JupiterEngineDescriptor( - UniqueId.root("engine", "junit-jupiter"), configuration); + var engineTestDescriptor = new JupiterEngineDescriptor(UniqueId.root("engine", "junit-jupiter"), configuration); try (var engineContext = new JupiterEngineExtensionContext(null, engineTestDescriptor, configuration, - __ -> null)) { + extensionRegistry, launcherStoreFacade)) { // @formatter:off assertAll("engineContext", () -> assertThat(engineContext.getElement()).isEmpty(), () -> assertThat(engineContext.getTestClass()).isEmpty(), () -> assertThat(engineContext.getTestInstance()).isEmpty(), () -> assertThat(engineContext.getTestMethod()).isEmpty(), - () -> assertThrows(PreconditionViolationException.class, engineContext::getRequiredTestClass), - () -> assertThrows(PreconditionViolationException.class, engineContext::getRequiredTestInstance), - () -> assertThrows(PreconditionViolationException.class, engineContext::getRequiredTestMethod), + () -> assertPreconditionViolationFor(engineContext::getRequiredTestClass), + () -> assertPreconditionViolationFor(engineContext::getRequiredTestInstance), + () -> assertPreconditionViolationFor(engineContext::getRequiredTestMethod), () -> assertThat(engineContext.getDisplayName()).isEqualTo(engineTestDescriptor.getDisplayName()), () -> assertThat(engineContext.getParent()).isEmpty(), () -> assertThat(engineContext.getRoot()).isSameAs(engineContext), - () -> assertThat(engineContext.getExecutionMode()).isEqualTo(ExecutionMode.SAME_THREAD) + () -> assertThat(engineContext.getExecutionMode()).isEqualTo(ExecutionMode.SAME_THREAD), + () -> assertThat(engineContext.getExtensions(PreInterruptCallback.class)).isEmpty() ); // @formatter:on } } @Test + @SuppressWarnings("resource") void fromClassTestDescriptor() { - NestedClassTestDescriptor nestedClassDescriptor = nestedClassDescriptor(); - ClassTestDescriptor outerClassDescriptor = outerClassDescriptor(nestedClassDescriptor); + var nestedClassDescriptor = nestedClassDescriptor(); + var outerClassDescriptor = outerClassDescriptor(nestedClassDescriptor); + var doublyNestedClassDescriptor = doublyNestedClassDescriptor(); + var methodTestDescriptor = nestedMethodDescriptor(); + nestedClassDescriptor.addChild(doublyNestedClassDescriptor); + nestedClassDescriptor.addChild(methodTestDescriptor); - ClassExtensionContext outerExtensionContext = new ClassExtensionContext(null, null, outerClassDescriptor, - configuration, null, __ -> null); + var outerExtensionContext = new ClassExtensionContext(null, null, outerClassDescriptor, PER_METHOD, + configuration, extensionRegistry, launcherStoreFacade, null); // @formatter:off assertAll("outerContext", - () -> assertThat(outerExtensionContext.getElement()).contains(OuterClass.class), - () -> assertThat(outerExtensionContext.getTestClass()).contains(OuterClass.class), + () -> assertThat(outerExtensionContext.getElement()).contains(OuterClassTestCase.class), + () -> assertThat(outerExtensionContext.getTestClass()).contains(OuterClassTestCase.class), () -> assertThat(outerExtensionContext.getTestInstance()).isEmpty(), () -> assertThat(outerExtensionContext.getTestMethod()).isEmpty(), - () -> assertThat(outerExtensionContext.getRequiredTestClass()).isEqualTo(OuterClass.class), - () -> assertThrows(PreconditionViolationException.class, outerExtensionContext::getRequiredTestInstance), - () -> assertThrows(PreconditionViolationException.class, outerExtensionContext::getRequiredTestMethod), + () -> assertThat(outerExtensionContext.getRequiredTestClass()).isEqualTo(OuterClassTestCase.class), + () -> assertPreconditionViolationFor(outerExtensionContext::getRequiredTestInstance), + () -> assertPreconditionViolationFor(outerExtensionContext::getRequiredTestMethod), () -> assertThat(outerExtensionContext.getDisplayName()).isEqualTo(outerClassDescriptor.getDisplayName()), () -> assertThat(outerExtensionContext.getParent()).isEmpty(), - () -> assertThat(outerExtensionContext.getExecutionMode()).isEqualTo(ExecutionMode.SAME_THREAD) + () -> assertThat(outerExtensionContext.getExecutionMode()).isEqualTo(ExecutionMode.SAME_THREAD), + () -> assertThat(outerExtensionContext.getExtensions(PreInterruptCallback.class)).isEmpty(), + () -> assertThat(outerExtensionContext.getEnclosingTestClasses()).isEmpty() + ); + // @formatter:on + + var nestedExtensionContext = new ClassExtensionContext(outerExtensionContext, null, nestedClassDescriptor, + PER_METHOD, configuration, extensionRegistry, launcherStoreFacade, null); + // @formatter:off + assertAll("nestedContext", + () -> assertThat(nestedExtensionContext.getParent()).containsSame(outerExtensionContext), + () -> assertThat(nestedExtensionContext.getTestClass()).contains(OuterClassTestCase.NestedClass.class), + () -> assertThat(nestedExtensionContext.getEnclosingTestClasses()).containsExactly(OuterClassTestCase.class) ); // @formatter:on - ClassExtensionContext nestedExtensionContext = new ClassExtensionContext(outerExtensionContext, null, - nestedClassDescriptor, configuration, null, __ -> null); - assertThat(nestedExtensionContext.getParent()).containsSame(outerExtensionContext); + var doublyNestedExtensionContext = new ClassExtensionContext(nestedExtensionContext, null, + doublyNestedClassDescriptor, PER_METHOD, configuration, extensionRegistry, launcherStoreFacade, null); + // @formatter:off + assertAll("doublyNestedContext", + () -> assertThat(doublyNestedExtensionContext.getParent()).containsSame(nestedExtensionContext), + () -> assertThat(doublyNestedExtensionContext.getTestClass()).contains(OuterClassTestCase.NestedClass.DoublyNestedClass.class), + () -> assertThat(doublyNestedExtensionContext.getEnclosingTestClasses()).containsExactly(OuterClassTestCase.class, OuterClassTestCase.NestedClass.class) + ); + // @formatter:on + + var methodExtensionContext = new MethodExtensionContext(nestedExtensionContext, null, methodTestDescriptor, + configuration, extensionRegistry, launcherStoreFacade, new OpenTest4JAwareThrowableCollector()); + // @formatter:off + assertAll("methodContext", + () -> assertThat(methodExtensionContext.getParent()).containsSame(nestedExtensionContext), + () -> assertThat(methodExtensionContext.getTestClass()).contains(OuterClassTestCase.NestedClass.class), + () -> assertThat(methodExtensionContext.getEnclosingTestClasses()).containsExactly(OuterClassTestCase.class) + ); + // @formatter:on + } + + @Test + void ExtensionContext_With_ExtensionRegistry_getExtensions() { + var classTestDescriptor = nestedClassDescriptor(); + try (var ctx = new ClassExtensionContext(null, null, classTestDescriptor, PER_METHOD, configuration, + extensionRegistry, launcherStoreFacade, null)) { + + Extension ext = mock(); + when(extensionRegistry.getExtensions(Extension.class)).thenReturn(List.of(ext)); + + assertThat(ctx.getExtensions(Extension.class)).isEqualTo(List.of(ext)); + } } @Test + @SuppressWarnings("resource") void tagsCanBeRetrievedInExtensionContext() { - NestedClassTestDescriptor nestedClassDescriptor = nestedClassDescriptor(); - ClassTestDescriptor outerClassDescriptor = outerClassDescriptor(nestedClassDescriptor); - TestMethodTestDescriptor methodTestDescriptor = methodDescriptor(); + var nestedClassDescriptor = nestedClassDescriptor(); + var outerClassDescriptor = outerClassDescriptor(nestedClassDescriptor); + var methodTestDescriptor = methodDescriptor(); outerClassDescriptor.addChild(methodTestDescriptor); - ClassExtensionContext outerExtensionContext = new ClassExtensionContext(null, null, outerClassDescriptor, - configuration, null, __ -> null); + var outerExtensionContext = new ClassExtensionContext(null, null, outerClassDescriptor, PER_METHOD, + configuration, extensionRegistry, launcherStoreFacade, null); assertThat(outerExtensionContext.getTags()).containsExactly("outer-tag"); assertThat(outerExtensionContext.getRoot()).isSameAs(outerExtensionContext); - ClassExtensionContext nestedExtensionContext = new ClassExtensionContext(outerExtensionContext, null, - nestedClassDescriptor, configuration, null, __ -> null); + var nestedExtensionContext = new ClassExtensionContext(outerExtensionContext, null, nestedClassDescriptor, + PER_METHOD, configuration, extensionRegistry, launcherStoreFacade, null); assertThat(nestedExtensionContext.getTags()).containsExactlyInAnyOrder("outer-tag", "nested-tag"); assertThat(nestedExtensionContext.getRoot()).isSameAs(outerExtensionContext); - MethodExtensionContext methodExtensionContext = new MethodExtensionContext(outerExtensionContext, null, - methodTestDescriptor, configuration, new OpenTest4JAwareThrowableCollector(), __ -> null); - methodExtensionContext.setTestInstances(DefaultTestInstances.of(new OuterClass())); + var methodExtensionContext = new MethodExtensionContext(outerExtensionContext, null, methodTestDescriptor, + configuration, extensionRegistry, launcherStoreFacade, new OpenTest4JAwareThrowableCollector()); + methodExtensionContext.setTestInstances(DefaultTestInstances.of(new OuterClassTestCase())); assertThat(methodExtensionContext.getTags()).containsExactlyInAnyOrder("outer-tag", "method-tag"); assertThat(methodExtensionContext.getRoot()).isSameAs(outerExtensionContext); } @Test + @SuppressWarnings("resource") void fromMethodTestDescriptor() { - TestMethodTestDescriptor methodTestDescriptor = methodDescriptor(); - ClassTestDescriptor classTestDescriptor = outerClassDescriptor(methodTestDescriptor); - JupiterEngineDescriptor engineDescriptor = new JupiterEngineDescriptor(UniqueId.forEngine("junit-jupiter"), - configuration); + var methodTestDescriptor = methodDescriptor(); + var classTestDescriptor = outerClassDescriptor(methodTestDescriptor); + var engineDescriptor = new JupiterEngineDescriptor(UniqueId.forEngine("junit-jupiter"), configuration); engineDescriptor.addChild(classTestDescriptor); - Object testInstance = new OuterClass(); - Method testMethod = methodTestDescriptor.getTestMethod(); + Object testInstance = new OuterClassTestCase(); + var testMethod = methodTestDescriptor.getTestMethod(); - JupiterEngineExtensionContext engineExtensionContext = new JupiterEngineExtensionContext(null, engineDescriptor, - configuration, __ -> null); - ClassExtensionContext classExtensionContext = new ClassExtensionContext(engineExtensionContext, null, - classTestDescriptor, configuration, null, __ -> null); - MethodExtensionContext methodExtensionContext = new MethodExtensionContext(classExtensionContext, null, - methodTestDescriptor, configuration, new OpenTest4JAwareThrowableCollector(), __ -> null); + var engineExtensionContext = new JupiterEngineExtensionContext(null, engineDescriptor, configuration, + extensionRegistry, launcherStoreFacade); + var classExtensionContext = new ClassExtensionContext(engineExtensionContext, null, classTestDescriptor, + PER_METHOD, configuration, extensionRegistry, launcherStoreFacade, null); + var methodExtensionContext = new MethodExtensionContext(classExtensionContext, null, methodTestDescriptor, + configuration, extensionRegistry, launcherStoreFacade, new OpenTest4JAwareThrowableCollector()); methodExtensionContext.setTestInstances(DefaultTestInstances.of(testInstance)); // @formatter:off assertAll("methodContext", () -> assertThat(methodExtensionContext.getElement()).contains(testMethod), - () -> assertThat(methodExtensionContext.getTestClass()).contains(OuterClass.class), + () -> assertThat(methodExtensionContext.getTestClass()).contains(OuterClassTestCase.class), + () -> assertThat(methodExtensionContext.getEnclosingTestClasses()).isEmpty(), () -> assertThat(methodExtensionContext.getTestInstance()).contains(testInstance), () -> assertThat(methodExtensionContext.getTestMethod()).contains(testMethod), - () -> assertThat(methodExtensionContext.getRequiredTestClass()).isEqualTo(OuterClass.class), + () -> assertThat(methodExtensionContext.getRequiredTestClass()).isEqualTo(OuterClassTestCase.class), () -> assertThat(methodExtensionContext.getRequiredTestInstance()).isEqualTo(testInstance), () -> assertThat(methodExtensionContext.getRequiredTestMethod()).isEqualTo(testMethod), () -> assertThat(methodExtensionContext.getDisplayName()).isEqualTo(methodTestDescriptor.getDisplayName()), @@ -186,28 +261,28 @@ @Test @SuppressWarnings("resource") - void reportEntriesArePublishedToExecutionContext() { - ClassTestDescriptor classTestDescriptor = outerClassDescriptor(null); - EngineExecutionListener engineExecutionListener = Mockito.spy(EngineExecutionListener.class); + void reportEntriesArePublishedToExecutionListener() { + var classTestDescriptor = outerClassDescriptor(null); + var engineExecutionListener = spy(EngineExecutionListener.class); ExtensionContext extensionContext = new ClassExtensionContext(null, engineExecutionListener, - classTestDescriptor, configuration, null, __ -> null); + classTestDescriptor, PER_METHOD, configuration, extensionRegistry, launcherStoreFacade, null); - Map map1 = Collections.singletonMap("key", "value"); - Map map2 = Collections.singletonMap("other key", "other value"); + var map1 = Collections.singletonMap("key", "value"); + var map2 = Collections.singletonMap("other key", "other value"); extensionContext.publishReportEntry(map1); extensionContext.publishReportEntry(map2); extensionContext.publishReportEntry("3rd key", "third value"); extensionContext.publishReportEntry("status message"); - ArgumentCaptor entryCaptor = ArgumentCaptor.forClass(ReportEntry.class); - Mockito.verify(engineExecutionListener, Mockito.times(4)).reportingEntryPublished( - ArgumentMatchers.eq(classTestDescriptor), entryCaptor.capture()); - - ReportEntry reportEntry1 = entryCaptor.getAllValues().get(0); - ReportEntry reportEntry2 = entryCaptor.getAllValues().get(1); - ReportEntry reportEntry3 = entryCaptor.getAllValues().get(2); - ReportEntry reportEntry4 = entryCaptor.getAllValues().get(3); + var entryCaptor = ArgumentCaptor.forClass(ReportEntry.class); + verify(engineExecutionListener, times(4)) // + .reportingEntryPublished(eq(classTestDescriptor), entryCaptor.capture()); + + var reportEntry1 = entryCaptor.getAllValues().get(0); + var reportEntry2 = entryCaptor.getAllValues().get(1); + var reportEntry3 = entryCaptor.getAllValues().get(2); + var reportEntry4 = entryCaptor.getAllValues().get(3); assertEquals(map1, reportEntry1.getKeyValuePairs()); assertEquals(map2, reportEntry2.getKeyValuePairs()); @@ -216,21 +291,148 @@ } @Test + void fileEntriesArePublishedToExecutionListener(@TempDir Path tempDir) { + var engineExecutionListener = mock(EngineExecutionListener.class); + var classTestDescriptor = outerClassDescriptor(null); + var extensionContext = createExtensionContextForFilePublishing(tempDir, engineExecutionListener, + classTestDescriptor); + + extensionContext.publishFile("test1.txt", TEXT_PLAIN_UTF_8, file -> Files.writeString(file, "Test 1")); + extensionContext.publishDirectory("test2", dir -> { + Files.writeString(dir.resolve("nested1.txt"), "Nested content 1"); + Files.writeString(dir.resolve("nested2.txt"), "Nested content 2"); + }); + + var entryCaptor = ArgumentCaptor.forClass(FileEntry.class); + verify(engineExecutionListener, times(2)) // + .fileEntryPublished(eq(classTestDescriptor), entryCaptor.capture()); + var fileEntries = entryCaptor.getAllValues(); + + var fileEntry1 = fileEntries.getFirst(); + assertThat(fileEntry1.getPath()).isEqualTo(tempDir.resolve("OuterClass/test1.txt")); + assertThat(fileEntry1.getMediaType()).contains(TEXT_PLAIN_UTF_8.toString()); + + var fileEntry2 = fileEntries.get(1); + assertThat(fileEntry2.getPath()).isEqualTo(tempDir.resolve("OuterClass/test2")); + assertThat(fileEntry2.getMediaType()).isEmpty(); + assertThat(fileEntry2.getPath().resolve("nested1.txt")).usingCharset(UTF_8).hasContent("Nested content 1"); + assertThat(fileEntry2.getPath().resolve("nested2.txt")).usingCharset(UTF_8).hasContent("Nested content 2"); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void failsWhenAttemptingToPublishFileWithNullOrBlankName(String name, @TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + + assertPreconditionViolationNotNullOrBlankFor("name", + () -> extensionContext.publishFile(name, TEXT_PLAIN, failingAction)); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { " ", " \t " }) + void failsWhenAttemptingToPublishDirectoryWithNullOrBlankName(String name, @TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + + assertPreconditionViolationNotNullOrBlankFor("name", + () -> extensionContext.publishDirectory(name, failingAction)); + } + + @Test + void failsWhenAttemptingToPublishFileWithPathSeparators(@TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + var name = "test" + File.separator + "subDir"; + + assertPreconditionViolationFor(() -> extensionContext.publishFile(name, TEXT_PLAIN, failingAction))// + .withMessage("name must not contain path separators: " + name); + } + + @Test + void failsWhenAttemptingToPublishDirectoryWithPathSeparators(@TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + var name = "test" + File.separator + "subDir"; + + assertPreconditionViolationFor(() -> extensionContext.publishDirectory(name, failingAction))// + .withMessage("name must not contain path separators: " + name); + } + + @Test + void failsWhenAttemptingToPublishMissingFiles(@TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + + assertPreconditionViolationFor(() -> extensionContext.publishFile("test", TEXT_PLAIN, Files::deleteIfExists)) // + .withMessage("Published path must exist: " + tempDir.resolve("OuterClass").resolve("test")); + } + + @Test + void failsWhenAttemptingToPublishMissingDirectory(@TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + + assertPreconditionViolationFor(() -> extensionContext.publishDirectory("test", Files::delete)) // + .withMessage("Published path must exist: " + tempDir.resolve("OuterClass").resolve("test")); + } + + @Test + void failsWhenAttemptingToPublishDirectoriesAsRegularFiles(@TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + + assertPreconditionViolationFor(() -> extensionContext.publishFile("test", TEXT_PLAIN, Files::createDirectory))// + .withMessage("Published path must be a regular file: " + tempDir.resolve("OuterClass").resolve("test")); + } + + @Test + void failsWhenAttemptingToPublishRegularFilesAsDirectories(@TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + + assertPreconditionViolationFor(() -> extensionContext.publishDirectory("test", dir -> { + Files.delete(dir); + Files.createFile(dir); + })).withMessage("Published path must be a directory: " + tempDir.resolve("OuterClass").resolve("test")); + } + + @Test + void allowsPublishingToTheSameDirectoryTwice(@TempDir Path tempDir) { + var extensionContext = createExtensionContextForFilePublishing(tempDir); + + extensionContext.publishDirectory("test", + dir -> Files.writeString(dir.resolve("nested1.txt"), "Nested content 1")); + extensionContext.publishDirectory("test", + dir -> Files.writeString(dir.resolve("nested2.txt"), "Nested content 2")); + + assertThat(tempDir.resolve("OuterClass/test/nested1.txt")).hasContent("Nested content 1"); + assertThat(tempDir.resolve("OuterClass/test/nested2.txt")).hasContent("Nested content 2"); + } + + private ExtensionContext createExtensionContextForFilePublishing(Path tempDir) { + return createExtensionContextForFilePublishing(tempDir, mock(EngineExecutionListener.class), + outerClassDescriptor(null)); + } + + private ExtensionContext createExtensionContextForFilePublishing(Path tempDir, + EngineExecutionListener engineExecutionListener, ClassTestDescriptor classTestDescriptor) { + when(configuration.getOutputDirectoryCreator()) // + .thenReturn(hierarchicalOutputDirectoryCreator(tempDir)); + return new ClassExtensionContext(null, engineExecutionListener, classTestDescriptor, PER_METHOD, configuration, + extensionRegistry, launcherStoreFacade, null); + } + + @Test @SuppressWarnings("resource") void usingStore() { - TestMethodTestDescriptor methodTestDescriptor = methodDescriptor(); - ClassTestDescriptor classTestDescriptor = outerClassDescriptor(methodTestDescriptor); - ExtensionContext parentContext = new ClassExtensionContext(null, null, classTestDescriptor, configuration, null, - __ -> null); - MethodExtensionContext childContext = new MethodExtensionContext(parentContext, null, methodTestDescriptor, - configuration, new OpenTest4JAwareThrowableCollector(), __ -> null); - childContext.setTestInstances(DefaultTestInstances.of(new OuterClass())); + var methodTestDescriptor = methodDescriptor(); + var classTestDescriptor = outerClassDescriptor(methodTestDescriptor); + ExtensionContext parentContext = new ClassExtensionContext(null, null, classTestDescriptor, PER_METHOD, + configuration, extensionRegistry, launcherStoreFacade, null); + var childContext = new MethodExtensionContext(parentContext, null, methodTestDescriptor, configuration, + extensionRegistry, launcherStoreFacade, new OpenTest4JAwareThrowableCollector()); + childContext.setTestInstances(DefaultTestInstances.of(new OuterClassTestCase())); - ExtensionContext.Store childStore = childContext.getStore(Namespace.GLOBAL); - ExtensionContext.Store parentStore = parentContext.getStore(Namespace.GLOBAL); + var childStore = childContext.getStore(Namespace.GLOBAL); + var parentStore = parentContext.getStore(Namespace.GLOBAL); final Object key1 = "key 1"; - final String value1 = "a value"; + final var value1 = "a value"; childStore.put(key1, value1); assertEquals(value1, childStore.get(key1)); assertEquals(value1, childStore.remove(key1)); @@ -242,14 +444,14 @@ assertNull(childStore.get(key1)); final Object key2 = "key 2"; - final String value2 = "other value"; + final var value2 = "other value"; assertEquals(value2, childStore.getOrComputeIfAbsent(key2, key -> value2)); assertEquals(value2, childStore.getOrComputeIfAbsent(key2, key -> value2, String.class)); assertEquals(value2, childStore.get(key2)); assertEquals(value2, childStore.get(key2, String.class)); final Object parentKey = "parent key"; - final String parentValue = "parent value"; + final var parentValue = "parent value"; parentStore.put(parentKey, parentValue); assertEquals(parentValue, childStore.getOrComputeIfAbsent(parentKey, k -> "a different value")); assertEquals(parentValue, childStore.get(parentKey)); @@ -258,9 +460,10 @@ @ParameterizedTest @MethodSource("extensionContextFactories") void configurationParameter(Function extensionContextFactory) { - JupiterConfiguration echo = new DefaultJupiterConfiguration(new EchoParameters()); - String key = "123"; - Optional expected = Optional.of(key); + JupiterConfiguration echo = new DefaultJupiterConfiguration(new EchoParameters(), + dummyOutputDirectoryCreator()); + var key = "123"; + var expected = Optional.of(key); var context = extensionContextFactory.apply(echo); @@ -268,37 +471,46 @@ } static List>> extensionContextFactories() { - Class testClass = ExtensionContextTests.class; + ExtensionRegistry extensionRegistry = mock(); + LauncherStoreFacade launcherStoreFacade = mock(); + var testClass = ExtensionContextTests.class; return List.of( // named("engine", (JupiterConfiguration configuration) -> { - UniqueId engineUniqueId = UniqueId.parse("[engine:junit-jupiter]"); - JupiterEngineDescriptor engineDescriptor = new JupiterEngineDescriptor(engineUniqueId, configuration); - return new JupiterEngineExtensionContext(null, engineDescriptor, configuration, __ -> null); + var engineUniqueId = UniqueId.parse("[engine:junit-jupiter]"); + var engineDescriptor = new JupiterEngineDescriptor(engineUniqueId, configuration); + return new JupiterEngineExtensionContext(null, engineDescriptor, configuration, extensionRegistry, + launcherStoreFacade); }), // named("class", (JupiterConfiguration configuration) -> { - UniqueId classUniqueId = UniqueId.parse("[engine:junit-jupiter]/[class:MyClass]"); - ClassTestDescriptor classTestDescriptor = new ClassTestDescriptor(classUniqueId, testClass, - configuration); - return new ClassExtensionContext(null, null, classTestDescriptor, configuration, null, __ -> null); + var classUniqueId = UniqueId.parse("[engine:junit-jupiter]/[class:MyClass]"); + var classTestDescriptor = new ClassTestDescriptor(classUniqueId, testClass, configuration); + return new ClassExtensionContext(null, null, classTestDescriptor, PER_METHOD, configuration, + extensionRegistry, launcherStoreFacade, null); }), // named("method", (JupiterConfiguration configuration) -> { - Method method = ReflectionSupport.findMethod(testClass, "extensionContextFactories").orElseThrow(); - UniqueId methodUniqueId = UniqueId.parse("[engine:junit-jupiter]/[class:MyClass]/[method:myMethod]"); - TestMethodTestDescriptor methodTestDescriptor = new TestMethodTestDescriptor(methodUniqueId, testClass, - method, configuration); - return new MethodExtensionContext(null, null, methodTestDescriptor, configuration, null, __ -> null); + var method = ReflectionSupport.findMethod(testClass, "extensionContextFactories").orElseThrow(); + var methodUniqueId = UniqueId.parse("[engine:junit-jupiter]/[class:MyClass]/[method:myMethod]"); + var methodTestDescriptor = new TestMethodTestDescriptor(methodUniqueId, testClass, method, List::of, + configuration); + return new MethodExtensionContext(null, null, methodTestDescriptor, configuration, extensionRegistry, + launcherStoreFacade, null); }) // ); } private NestedClassTestDescriptor nestedClassDescriptor() { - return new NestedClassTestDescriptor(UniqueId.root("nested-class", "NestedClass"), OuterClass.NestedClass.class, - configuration); + return new NestedClassTestDescriptor(UniqueId.root("nested-class", "NestedClass"), + OuterClassTestCase.NestedClass.class, List::of, configuration); + } + + private NestedClassTestDescriptor doublyNestedClassDescriptor() { + return new NestedClassTestDescriptor(UniqueId.root("nested-class", "DoublyNestedClass"), + OuterClassTestCase.NestedClass.DoublyNestedClass.class, List::of, configuration); } private ClassTestDescriptor outerClassDescriptor(TestDescriptor child) { - ClassTestDescriptor classTestDescriptor = new ClassTestDescriptor(UniqueId.root("class", "OuterClass"), - OuterClass.class, configuration); + var classTestDescriptor = new ClassTestDescriptor(UniqueId.root("class", "OuterClass"), + OuterClassTestCase.class, configuration); if (child != null) { classTestDescriptor.addChild(child); } @@ -307,19 +519,41 @@ private TestMethodTestDescriptor methodDescriptor() { try { - return new TestMethodTestDescriptor(UniqueId.root("method", "aMethod"), OuterClass.class, - OuterClass.class.getDeclaredMethod("aMethod"), configuration); + return new TestMethodTestDescriptor(UniqueId.root("method", "aMethod"), OuterClassTestCase.class, + OuterClassTestCase.class.getDeclaredMethod("aMethod"), List::of, configuration); + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private TestMethodTestDescriptor nestedMethodDescriptor() { + try { + return new TestMethodTestDescriptor(UniqueId.root("method", "nestedMethod"), + OuterClassTestCase.NestedClass.class, BaseNestedTestCase.class.getDeclaredMethod("nestedMethod"), + List::of, configuration); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } + static abstract class BaseNestedTestCase { + @Test + void nestedMethod() { + } + + @Nested + class DoublyNestedClass { + } + } + @Tag("outer-tag") - static class OuterClass { + static class OuterClassTestCase { @Tag("nested-tag") - static class NestedClass { + @Nested + class NestedClass extends BaseNestedTestCase { } @Tag("method-tag") diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionsUtilsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionsUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionsUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionsUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.jupiter.engine.descriptor; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; @@ -114,7 +113,7 @@ void constructFromMethod() throws Exception { Class testClass = TestCase.class; Method testMethod = testClass.getDeclaredMethod("test"); - TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, testClass, testMethod, + TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, testClass, testMethod, List::of, configuration); assertEquals(uniqueId, descriptor.getUniqueId()); @@ -128,14 +127,14 @@ JupiterTestDescriptor classDescriptor = new ClassTestDescriptor(uniqueId, TestCase.class, configuration); Method testMethod = TestCase.class.getDeclaredMethod("foo"); TestMethodTestDescriptor methodDescriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); classDescriptor.addChild(methodDescriptor); assertEquals(testMethod, methodDescriptor.getTestMethod()); assertEquals("custom test name", methodDescriptor.getDisplayName(), "display name:"); assertEquals("foo()", methodDescriptor.getLegacyReportingName(), "legacy name:"); - List tags = methodDescriptor.getTags().stream().map(TestTag::getName).collect(toList()); + List tags = methodDescriptor.getTags().stream().map(TestTag::getName).toList(); assertThat(tags).containsExactlyInAnyOrder("inherited-class-level-tag", "classTag1", "classTag2", "methodTag1", "methodTag2"); } @@ -144,7 +143,7 @@ void constructFromMethodWithCustomTestAnnotation() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("customTestAnnotation"); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("custom name", descriptor.getDisplayName(), "display name:"); @@ -156,7 +155,7 @@ void constructFromMethodWithParameters() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", String.class, BigDecimal.class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(String, BigDecimal)", descriptor.getDisplayName(), "display name"); @@ -167,7 +166,7 @@ void constructFromMethodWithPrimitiveArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", int[].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(int[])", descriptor.getDisplayName(), "display name"); @@ -178,7 +177,7 @@ void constructFromMethodWithObjectArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", String[].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(String[])", descriptor.getDisplayName(), "display name"); @@ -189,7 +188,7 @@ void constructFromMethodWithMultidimensionalPrimitiveArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", int[][][][][].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(int[][][][][])", descriptor.getDisplayName(), "display name"); @@ -200,7 +199,7 @@ void constructFromMethodWithMultidimensionalObjectArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", String[][][][][].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(String[][][][][])", descriptor.getDisplayName(), "display name"); @@ -211,7 +210,7 @@ void constructFromInheritedMethod() throws Exception { Method testMethod = ConcreteTestCase.class.getMethod("theTest"); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, ConcreteTestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); @@ -231,7 +230,7 @@ assertEquals("class-display-name", descriptor.getDisplayName()); assertEquals(getClass().getName(), descriptor.getLegacyReportingName()); - descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, configuration); + descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, List::of, configuration); assertEquals("nested-class-display-name", descriptor.getDisplayName()); assertEquals(NestedTestCase.class.getName(), descriptor.getLegacyReportingName()); @@ -250,7 +249,7 @@ assertEquals(getClass().getSimpleName(), descriptor.getDisplayName()); assertEquals(getClass().getName(), descriptor.getLegacyReportingName()); - descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, configuration); + descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, List::of, configuration); assertEquals(NestedTestCase.class.getSimpleName(), descriptor.getDisplayName()); assertEquals(NestedTestCase.class.getName(), descriptor.getLegacyReportingName()); @@ -270,7 +269,7 @@ ClassBasedTestDescriptor parentDescriptor = new ClassTestDescriptor(uniqueId, StaticTestCase.class, configuration); ClassBasedTestDescriptor nestedDescriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, - configuration); + List::of, configuration); assertThat(parentDescriptor.getEnclosingTestClasses()).isEmpty(); assertThat(nestedDescriptor.getEnclosingTestClasses()).isEmpty(); @@ -296,7 +295,7 @@ @Tag("classTag1") @Tag("classTag2") @DisplayName("custom class name") - @SuppressWarnings("unused") + @SuppressWarnings({ "unused", "JUnitMalformedDeclaration" }) private static class TestCase extends AbstractTestCase { void test() { @@ -331,9 +330,11 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") private static class TestCaseWithInvalidBeforeAllMethod { // must be static + @SuppressWarnings("JUnitMalformedDeclaration") @BeforeAll void beforeAll() { } @@ -344,9 +345,11 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") private static class TestCaseWithInvalidAfterAllMethod { // must be static + @SuppressWarnings("JUnitMalformedDeclaration") @AfterAll void afterAll() { } @@ -357,9 +360,11 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") private static class TestCaseWithInvalidBeforeEachMethod { // must NOT be static + @SuppressWarnings("JUnitMalformedDeclaration") @BeforeEach static void beforeEach() { } @@ -370,9 +375,11 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") private static class TestCaseWithInvalidAfterEachMethod { // must NOT be static + @SuppressWarnings("JUnitMalformedDeclaration") @AfterEach static void afterEach() { } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LauncherStoreFacadeTest.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LauncherStoreFacadeTest.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LauncherStoreFacadeTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LauncherStoreFacadeTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.execution.NamespaceAwareStore; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; + +/** + * Tests for {@link LauncherStoreFacade}. + * + * @since 5.13 + */ +class LauncherStoreFacadeTest { + + private NamespacedHierarchicalStore requestLevelStore; + private NamespacedHierarchicalStore sessionLevelStore; + private ExtensionContext.Namespace extensionNamespace; + + @BeforeEach + void setUp() { + sessionLevelStore = new NamespacedHierarchicalStore<>(null); + requestLevelStore = new NamespacedHierarchicalStore<>(sessionLevelStore); + extensionNamespace = ExtensionContext.Namespace.create("foo", "bar"); + } + + @Test + void createsInstanceSuccessfullyWithValidStore() { + assertDoesNotThrow(() -> new LauncherStoreFacade(requestLevelStore)); + } + + @Test + void throwsExceptionWhenRequestLevelStoreHasNoParent() { + assertThrowsExactly(JUnitException.class, () -> new LauncherStoreFacade(sessionLevelStore), () -> { + throw new JUnitException("Request-level store must have a parent"); + }); + } + + @Test + void returnsRequestLevelStore() { + LauncherStoreFacade facade = new LauncherStoreFacade(requestLevelStore); + assertEquals(requestLevelStore, facade.getRequestLevelStore()); + } + + @Test + void returnsNamespaceAwareStoreWithRequestLevelStore() { + LauncherStoreFacade facade = new LauncherStoreFacade(requestLevelStore); + ExtensionContext.Store store = facade.getRequestLevelStore(extensionNamespace); + + assertNotNull(store); + assertInstanceOf(NamespaceAwareStore.class, store); + } + + @Test + void returnsNamespaceAwareStore() { + LauncherStoreFacade facade = new LauncherStoreFacade(requestLevelStore); + NamespaceAwareStore adapter = facade.getStoreAdapter(requestLevelStore, extensionNamespace); + + assertNotNull(adapter); + } + + @Test + void throwsExceptionWhenNamespaceIsNull() { + LauncherStoreFacade facade = new LauncherStoreFacade(requestLevelStore); + assertThrows(PreconditionViolationException.class, () -> facade.getStoreAdapter(requestLevelStore, null)); + } + + @Test + void returnsNamespaceAwareStoreWithGlobalNamespace() { + requestLevelStore.put(Namespace.GLOBAL, "foo", "bar"); + + LauncherStoreFacade facade = new LauncherStoreFacade(requestLevelStore); + ExtensionContext.Store store = facade.getRequestLevelStore(ExtensionContext.Namespace.GLOBAL); + + assertEquals("bar", store.get("foo")); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtilsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,16 +10,16 @@ package org.junit.jupiter.engine.descriptor; -import static java.util.stream.Collectors.toList; +import static java.util.function.Predicate.isEqual; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findAfterAllMethods; import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findAfterEachMethods; import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findBeforeAllMethods; import static org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.findBeforeEachMethods; +import static org.junit.platform.commons.util.FunctionUtils.where; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.AfterAll; @@ -29,7 +29,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.platform.commons.JUnitException; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Unit tests for {@link LifecycleMethodUtils}. @@ -38,106 +41,162 @@ */ class LifecycleMethodUtilsTests { - @Test - void findNonVoidBeforeAllMethodsWithStandardLifecycle() { - JUnitException exception = assertThrows(JUnitException.class, - () -> findBeforeAllMethods(TestCaseWithNonVoidLifecyleMethods.class, true)); - assertEquals( - "@BeforeAll method 'java.lang.Double org.junit.jupiter.engine.descriptor.TestCaseWithNonVoidLifecyleMethods.cc()' must not return a value.", - exception.getMessage()); - } - - @Test - void findNonVoidAfterAllMethodsWithStandardLifecycle() { - JUnitException exception = assertThrows(JUnitException.class, - () -> findAfterAllMethods(TestCaseWithNonVoidLifecyleMethods.class, true)); - assertEquals( - "@AfterAll method 'java.lang.String org.junit.jupiter.engine.descriptor.TestCaseWithNonVoidLifecyleMethods.dd()' must not return a value.", - exception.getMessage()); - } + List discoveryIssues = new ArrayList<>(); + DiscoveryIssueReporter issueReporter = DiscoveryIssueReporter.collecting(discoveryIssues); @Test - void findNonVoidBeforeEachMethodsWithStandardLifecycle() { - JUnitException exception = assertThrows(JUnitException.class, - () -> findBeforeEachMethods(TestCaseWithNonVoidLifecyleMethods.class)); - assertEquals( - "@BeforeEach method 'java.lang.String org.junit.jupiter.engine.descriptor.TestCaseWithNonVoidLifecyleMethods.aa()' must not return a value.", - exception.getMessage()); - } - - @Test - void findNonVoidAfterEachMethodsWithStandardLifecycle() { - JUnitException exception = assertThrows(JUnitException.class, - () -> findAfterEachMethods(TestCaseWithNonVoidLifecyleMethods.class)); - assertEquals( - "@AfterEach method 'int org.junit.jupiter.engine.descriptor.TestCaseWithNonVoidLifecyleMethods.bb()' must not return a value.", - exception.getMessage()); + void findNonVoidBeforeAllMethodsWithStandardLifecycle() throws Exception { + var methods = findBeforeAllMethods(TestCaseWithInvalidLifecycleMethods.class, true, issueReporter); + assertThat(methods).isEmpty(); + + var methodSource = MethodSource.from(TestCaseWithInvalidLifecycleMethods.class.getDeclaredMethod("cc")); + var notVoidIssue = DiscoveryIssue.builder(Severity.ERROR, + "@BeforeAll method 'private java.lang.Double org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.cc()' must not return a value.") // + .source(methodSource) // + .build(); + var notStaticIssue = DiscoveryIssue.builder(Severity.ERROR, + "@BeforeAll method 'private java.lang.Double org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.cc()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).") // + .source(methodSource) // + .build(); + var privateIssue = DiscoveryIssue.builder(Severity.WARNING, + "@BeforeAll method 'private java.lang.Double org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.cc()' should not be private. This will be disallowed in a future release.") // + .source(methodSource) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notVoidIssue, notStaticIssue, privateIssue); + } + + @Test + void findNonVoidAfterAllMethodsWithStandardLifecycle() throws Exception { + var methods = findAfterAllMethods(TestCaseWithInvalidLifecycleMethods.class, true, issueReporter); + assertThat(methods).isEmpty(); + + var methodSource = MethodSource.from(TestCaseWithInvalidLifecycleMethods.class.getDeclaredMethod("dd")); + var notVoidIssue = DiscoveryIssue.builder(Severity.ERROR, + "@AfterAll method 'private java.lang.String org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.dd()' must not return a value.") // + .source(methodSource) // + .build(); + var notStaticIssue = DiscoveryIssue.builder(Severity.ERROR, + "@AfterAll method 'private java.lang.String org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.dd()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).") // + .source(methodSource) // + .build(); + var privateIssue = DiscoveryIssue.builder(Severity.WARNING, + "@AfterAll method 'private java.lang.String org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.dd()' should not be private. This will be disallowed in a future release.") // + .source(methodSource) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notVoidIssue, notStaticIssue, privateIssue); + } + + @Test + void findNonVoidBeforeEachMethodsWithStandardLifecycle() throws Exception { + var methods = findBeforeEachMethods(TestCaseWithInvalidLifecycleMethods.class, issueReporter); + assertThat(methods).isEmpty(); + + var methodSource = MethodSource.from(TestCaseWithInvalidLifecycleMethods.class.getDeclaredMethod("aa")); + var notVoidIssue = DiscoveryIssue.builder(Severity.ERROR, + "@BeforeEach method 'private java.lang.String org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.aa()' must not return a value.") // + .source(methodSource) // + .build(); + var privateIssue = DiscoveryIssue.builder(Severity.WARNING, + "@BeforeEach method 'private java.lang.String org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.aa()' should not be private. This will be disallowed in a future release.") // + .source(methodSource) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notVoidIssue, privateIssue); + } + + @Test + void findNonVoidAfterEachMethodsWithStandardLifecycle() throws Exception { + var methods = findAfterEachMethods(TestCaseWithInvalidLifecycleMethods.class, issueReporter); + assertThat(methods).isEmpty(); + + var methodSource = MethodSource.from(TestCaseWithInvalidLifecycleMethods.class.getDeclaredMethod("bb")); + var notVoidIssue = DiscoveryIssue.builder(Severity.ERROR, + "@AfterEach method 'private int org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.bb()' must not return a value.") // + .source(methodSource) // + .build(); + var privateIssue = DiscoveryIssue.builder(Severity.WARNING, + "@AfterEach method 'private int org.junit.jupiter.engine.descriptor.TestCaseWithInvalidLifecycleMethods.bb()' should not be private. This will be disallowed in a future release.") // + .source(methodSource) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notVoidIssue, privateIssue); } @Test void findBeforeEachMethodsWithStandardLifecycle() { - List methods = findBeforeEachMethods(TestCaseWithStandardLifecycle.class); + List methods = findBeforeEachMethods(TestCaseWithStandardLifecycle.class, issueReporter); assertThat(namesOf(methods)).containsExactlyInAnyOrder("nine", "ten"); + assertThat(discoveryIssues).isEmpty(); } @Test void findAfterEachMethodsWithStandardLifecycle() { - List methods = findAfterEachMethods(TestCaseWithStandardLifecycle.class); + List methods = findAfterEachMethods(TestCaseWithStandardLifecycle.class, issueReporter); assertThat(namesOf(methods)).containsExactlyInAnyOrder("eleven", "twelve"); } @Test void findBeforeAllMethodsWithStandardLifecycleAndWithoutRequiringStatic() { - List methods = findBeforeAllMethods(TestCaseWithStandardLifecycle.class, false); + List methods = findBeforeAllMethods(TestCaseWithStandardLifecycle.class, false, issueReporter); assertThat(namesOf(methods)).containsExactly("one"); + assertThat(discoveryIssues).isEmpty(); } @Test - void findBeforeAllMethodsWithStandardLifecycleAndRequiringStatic() { - JUnitException exception = assertThrows(JUnitException.class, - () -> findBeforeAllMethods(TestCaseWithStandardLifecycle.class, true)); - assertEquals( - "@BeforeAll method 'void org.junit.jupiter.engine.descriptor.TestCaseWithStandardLifecycle.one()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).", - exception.getMessage()); + void findBeforeAllMethodsWithStandardLifecycleAndRequiringStatic() throws Exception { + var methods = findBeforeAllMethods(TestCaseWithStandardLifecycle.class, true, issueReporter); + assertThat(methods).isEmpty(); + + var expectedIssue = DiscoveryIssue.builder(Severity.ERROR, + "@BeforeAll method 'void org.junit.jupiter.engine.descriptor.TestCaseWithStandardLifecycle.one()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).") // + .source(MethodSource.from(TestCaseWithStandardLifecycle.class.getDeclaredMethod("one"))) // + .build(); + assertThat(discoveryIssues).containsExactly(expectedIssue); } @Test void findBeforeAllMethodsWithLifeCyclePerClassAndRequiringStatic() { - List methods = findBeforeAllMethods(TestCaseWithLifecyclePerClass.class, false); + List methods = findBeforeAllMethods(TestCaseWithLifecyclePerClass.class, false, issueReporter); assertThat(namesOf(methods)).containsExactlyInAnyOrder("three", "four"); + assertThat(discoveryIssues).isEmpty(); } @Test void findAfterAllMethodsWithStandardLifecycleAndWithoutRequiringStatic() { - List methods = findAfterAllMethods(TestCaseWithStandardLifecycle.class, false); + List methods = findAfterAllMethods(TestCaseWithStandardLifecycle.class, false, issueReporter); assertThat(namesOf(methods)).containsExactlyInAnyOrder("five", "six"); + assertThat(discoveryIssues).isEmpty(); } @Test void findAfterAllMethodsWithStandardLifecycleAndRequiringStatic() { - assertThrows(JUnitException.class, () -> findAfterAllMethods(TestCaseWithStandardLifecycle.class, true)); + var methods = findAfterAllMethods(TestCaseWithStandardLifecycle.class, true, issueReporter); + assertThat(methods).isEmpty(); + + assertThat(discoveryIssues) // + .filteredOn(where(DiscoveryIssue::severity, isEqual(Severity.ERROR))) // + .isNotEmpty(); } @Test void findAfterAllMethodsWithLifeCyclePerClassAndRequiringStatic() { - List methods = findAfterAllMethods(TestCaseWithLifecyclePerClass.class, false); + List methods = findAfterAllMethods(TestCaseWithLifecyclePerClass.class, false, issueReporter); assertThat(namesOf(methods)).containsExactlyInAnyOrder("seven", "eight"); } private static List namesOf(List methods) { - return methods.stream().map(Method::getName).collect(toList()); + return methods.stream().map(Method::getName).toList(); } } class TestCaseWithStandardLifecycle { + @SuppressWarnings("JUnitMalformedDeclaration") @BeforeAll void one() { } @@ -158,10 +217,12 @@ void twelve() { } + @SuppressWarnings("JUnitMalformedDeclaration") @AfterAll void five() { } + @SuppressWarnings("JUnitMalformedDeclaration") @AfterAll void six() { } @@ -189,25 +250,26 @@ } -class TestCaseWithNonVoidLifecyleMethods { +@SuppressWarnings("JUnitMalformedDeclaration") +class TestCaseWithInvalidLifecycleMethods { @BeforeEach - String aa() { + private String aa() { return null; } @AfterEach - int bb() { + private int bb() { return 1; } @BeforeAll - Double cc() { + private Double cc() { return null; } @AfterAll - String dd() { + private String dd() { return ""; } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/NamespaceTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/NamespaceTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/NamespaceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/NamespaceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ResourceAutoClosingTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ResourceAutoClosingTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ResourceAutoClosingTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ResourceAutoClosingTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.descriptor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.logging.Level; +import java.util.logging.LogRecord; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.fixtures.TrackLogRecords; +import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.execution.LauncherStoreFacade; +import org.junit.jupiter.engine.extension.ExtensionRegistry; +import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.launcher.core.NamespacedHierarchicalStoreProviders; +import org.junit.platform.testkit.engine.ExecutionRecorder; + +class ResourceAutoClosingTests { + + private final JupiterConfiguration configuration = mock(); + private final ExtensionRegistry extensionRegistry = mock(); + private final JupiterEngineDescriptor testDescriptor = mock(); + private final LauncherStoreFacade launcherStoreFacade = new LauncherStoreFacade( + NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStore()); + + @Test + void shouldCloseAutoCloseableWhenIsClosingStoredAutoCloseablesEnabledIsTrue() throws Exception { + AutoCloseableResource resource = new AutoCloseableResource(); + when(configuration.isClosingStoredAutoCloseablesEnabled()).thenReturn(true); + + ExtensionContext extensionContext = new JupiterEngineExtensionContext(null, testDescriptor, configuration, + extensionRegistry, launcherStoreFacade); + ExtensionContext.Store store = extensionContext.getStore(ExtensionContext.Namespace.GLOBAL); + store.put("resource", resource); + + ((AutoCloseable) extensionContext).close(); + + assertThat(resource.closed).isTrue(); + } + + @Test + void shouldNotCloseAutoCloseableWhenIsClosingStoredAutoCloseablesEnabledIsFalse() throws Exception { + AutoCloseableResource resource = new AutoCloseableResource(); + when(configuration.isClosingStoredAutoCloseablesEnabled()).thenReturn(false); + + ExtensionContext extensionContext = new JupiterEngineExtensionContext(null, testDescriptor, configuration, + extensionRegistry, launcherStoreFacade); + ExtensionContext.Store store = extensionContext.getStore(ExtensionContext.Namespace.GLOBAL); + store.put("resource", resource); + + ((AutoCloseable) extensionContext).close(); + + assertThat(resource.closed).isFalse(); + } + + @Test + void shouldLogWarningWhenResourceImplementsCloseableResourceButNotAutoCloseableAndConfigIsTrue( + @TrackLogRecords LogRecordListener listener) throws Exception { + ExecutionRecorder executionRecorder = new ExecutionRecorder(); + CloseableResource resource1 = new CloseableResource(); + CloseableResource resource2 = new CloseableResource(); + CloseableResource resource3 = new CloseableResource() { + }; + when(configuration.isClosingStoredAutoCloseablesEnabled()).thenReturn(true); + + ExtensionContext extensionContext = new JupiterEngineExtensionContext(executionRecorder, testDescriptor, + configuration, extensionRegistry, launcherStoreFacade); + ExtensionContext.Store store = extensionContext.getStore(ExtensionContext.Namespace.GLOBAL); + store.put("resource1", resource1); + store.put("resource2", resource2); + store.put("resource3", resource3); + + ((AutoCloseable) extensionContext).close(); + + assertThat(listener.stream(Level.WARNING)).map(LogRecord::getMessage) // + .containsExactlyInAnyOrder( + "Type implements CloseableResource but not AutoCloseable: " + resource1.getClass().getName(), + "Type implements CloseableResource but not AutoCloseable: " + resource3.getClass().getName()); + assertThat(resource1.closed).isTrue(); + assertThat(resource2.closed).isTrue(); + assertThat(resource3.closed).isTrue(); + } + + @Test + void shouldNotLogWarningWhenResourceImplementsCloseableResourceAndAutoCloseableAndConfigIsFalse( + @TrackLogRecords LogRecordListener listener) throws Exception { + ExecutionRecorder executionRecorder = new ExecutionRecorder(); + CloseableResource resource = new CloseableResource(); + when(configuration.isClosingStoredAutoCloseablesEnabled()).thenReturn(false); + + ExtensionContext extensionContext = new JupiterEngineExtensionContext(executionRecorder, testDescriptor, + configuration, extensionRegistry, launcherStoreFacade); + ExtensionContext.Store store = extensionContext.getStore(ExtensionContext.Namespace.GLOBAL); + store.put("resource", resource); + + ((AutoCloseable) extensionContext).close(); + + assertThat(listener.stream(Level.WARNING)).isEmpty(); + assertThat(resource.closed).isTrue(); + } + + static class AutoCloseableResource implements AutoCloseable { + private boolean closed = false; + + @Override + public void close() { + closed = true; + } + } + + @SuppressWarnings("deprecation") + static class CloseableResource implements ExtensionContext.Store.CloseableResource { + private boolean closed = false; + + @Override + public void close() { + closed = true; + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,6 +18,7 @@ import java.io.File; import java.lang.reflect.Method; import java.net.URI; +import java.util.List; import java.util.Optional; import java.util.stream.Stream; @@ -47,6 +48,31 @@ */ class TestFactoryTestDescriptorTests { + @Test + void copyIncludesTransformedDynamicDescendantFilter() throws Exception { + var rootUniqueId = UniqueId.forEngine("engine"); + var parentUniqueId = rootUniqueId.append("class", "myClass"); + var originalUniqueId = parentUniqueId.append("old", "testFactory()"); + + var configuration = mock(JupiterConfiguration.class); + when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); + Method testMethod = CustomStreamTestCase.class.getDeclaredMethod("customStream"); + var original = new TestFactoryTestDescriptor(originalUniqueId, CustomStreamTestCase.class, testMethod, List::of, + configuration); + + original.getDynamicDescendantFilter().allowUniqueIdPrefix(originalUniqueId.append("foo", "bar")); + original.getDynamicDescendantFilter().allowIndex(42); + + var newUniqueId = parentUniqueId.append("new", "testFactory()"); + + var copy = original.withUniqueId(new UniqueIdPrefixTransformer(originalUniqueId, newUniqueId)); + + assertThat(copy.getUniqueId()).isEqualTo(newUniqueId); + assertThat(copy.getDynamicDescendantFilter().test(newUniqueId, 0)).isTrue(); + assertThat(copy.getDynamicDescendantFilter().test(newUniqueId, 42)).isTrue(); + assertThat(copy.getDynamicDescendantFilter().test(originalUniqueId, 1)).isFalse(); + } + /** * @since 5.3 */ @@ -128,17 +154,16 @@ private ExtensionContext extensionContext; private TestFactoryTestDescriptor descriptor; private boolean isClosed; - private JupiterConfiguration jupiterConfiguration; @BeforeEach void before() throws Exception { - jupiterConfiguration = mock(); + JupiterConfiguration jupiterConfiguration = mock(); when(jupiterConfiguration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); extensionContext = mock(); isClosed = false; - context = new JupiterEngineExecutionContext(null, null) // + context = new JupiterEngineExecutionContext(null, null, null) // .extend() // .withThrowableCollector(new OpenTest4JAwareThrowableCollector()) // .withExtensionContext(extensionContext) // @@ -147,7 +172,7 @@ Method testMethod = CustomStreamTestCase.class.getDeclaredMethod("customStream"); descriptor = new TestFactoryTestDescriptor(UniqueId.forEngine("engine"), CustomStreamTestCase.class, - testMethod, jupiterConfiguration); + testMethod, List::of, jupiterConfiguration); when(extensionContext.getTestMethod()).thenReturn(Optional.of(testMethod)); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,7 @@ import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD; import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME; import static org.junit.jupiter.engine.descriptor.TestInstanceLifecycleUtils.getTestInstanceLifecycle; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -50,7 +51,8 @@ @Test void getTestInstanceLifecyclePreconditions() { PreconditionViolationException exception = assertThrows(PreconditionViolationException.class, - () -> getTestInstanceLifecycle(null, new DefaultJupiterConfiguration(mock()))); + () -> getTestInstanceLifecycle(null, + new DefaultJupiterConfiguration(mock(), dummyOutputDirectoryCreator()))); assertThat(exception).hasMessage("testClass must not be null"); exception = assertThrows(PreconditionViolationException.class, @@ -60,7 +62,8 @@ @Test void getTestInstanceLifecycleWithNoConfigParamSet() { - Lifecycle lifecycle = getTestInstanceLifecycle(getClass(), new DefaultJupiterConfiguration(mock())); + Lifecycle lifecycle = getTestInstanceLifecycle(getClass(), + new DefaultJupiterConfiguration(mock(), dummyOutputDirectoryCreator())); assertThat(lifecycle).isEqualTo(PER_METHOD); } @@ -68,7 +71,8 @@ void getTestInstanceLifecycleWithConfigParamSet() { ConfigurationParameters configParams = mock(); when(configParams.get(KEY)).thenReturn(Optional.of(PER_CLASS.name().toLowerCase())); - Lifecycle lifecycle = getTestInstanceLifecycle(getClass(), new DefaultJupiterConfiguration(configParams)); + Lifecycle lifecycle = getTestInstanceLifecycle(getClass(), + new DefaultJupiterConfiguration(configParams, dummyOutputDirectoryCreator())); assertThat(lifecycle).isEqualTo(PER_CLASS); } @@ -76,21 +80,24 @@ void getTestInstanceLifecycleWithLocalConfigThatOverridesCustomDefaultSetViaConfigParam() { ConfigurationParameters configParams = mock(); when(configParams.get(KEY)).thenReturn(Optional.of(PER_CLASS.name().toLowerCase())); - Lifecycle lifecycle = getTestInstanceLifecycle(TestCase.class, new DefaultJupiterConfiguration(configParams)); + Lifecycle lifecycle = getTestInstanceLifecycle(TestCase.class, + new DefaultJupiterConfiguration(configParams, dummyOutputDirectoryCreator())); assertThat(lifecycle).isEqualTo(PER_METHOD); } @Test void getTestInstanceLifecycleFromMetaAnnotationWithNoConfigParamSet() { Class testClass = BaseMetaAnnotatedTestCase.class; - Lifecycle lifecycle = getTestInstanceLifecycle(testClass, new DefaultJupiterConfiguration(mock())); + Lifecycle lifecycle = getTestInstanceLifecycle(testClass, + new DefaultJupiterConfiguration(mock(), dummyOutputDirectoryCreator())); assertThat(lifecycle).isEqualTo(PER_CLASS); } @Test void getTestInstanceLifecycleFromSpecializedClassWithNoConfigParamSet() { Class testClass = SpecializedTestCase.class; - Lifecycle lifecycle = getTestInstanceLifecycle(testClass, new DefaultJupiterConfiguration(mock())); + Lifecycle lifecycle = getTestInstanceLifecycle(testClass, + new DefaultJupiterConfiguration(mock(), dummyOutputDirectoryCreator())); assertThat(lifecycle).isEqualTo(PER_CLASS); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,7 @@ import static org.mockito.Mockito.when; import java.lang.reflect.Method; +import java.util.List; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -34,7 +35,7 @@ JupiterConfiguration configuration = mock(); when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); TestTemplateTestDescriptor parent = new TestTemplateTestDescriptor(UniqueId.root("segment", "template"), - testClass, testTemplateMethod, configuration); + testClass, testTemplateMethod, List::of, configuration); TestTemplateInvocationContext invocationContext = mock(); when(invocationContext.getDisplayName(anyInt())).thenReturn("invocation"); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,8 +15,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.List; import java.util.Set; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -32,20 +34,22 @@ * @since 5.0 */ class TestTemplateTestDescriptorTests { + private JupiterConfiguration jupiterConfiguration = mock(); + @BeforeEach + void prepareJupiterConfiguration() { + when(jupiterConfiguration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); + } + @Test void inheritsTagsFromParent() throws Exception { - UniqueId rootUniqueId = UniqueId.root("segment", "template"); - UniqueId parentUniqueId = rootUniqueId.append("class", "myClass"); - AbstractTestDescriptor parent = containerTestDescriptorWithTags(parentUniqueId, - singleton(TestTag.create("foo"))); + var rootUniqueId = UniqueId.root("segment", "template"); + var parentUniqueId = rootUniqueId.append("class", "myClass"); + var parent = containerTestDescriptorWithTags(parentUniqueId, singleton(TestTag.create("foo"))); - when(jupiterConfiguration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); - - TestTemplateTestDescriptor testDescriptor = new TestTemplateTestDescriptor( - parentUniqueId.append("tmp", "testTemplate()"), MyTestCase.class, - MyTestCase.class.getDeclaredMethod("testTemplate"), jupiterConfiguration); + var testDescriptor = new TestTemplateTestDescriptor(parentUniqueId.append("tmp", "testTemplate()"), + MyTestCase.class, MyTestCase.class.getDeclaredMethod("testTemplate"), List::of, jupiterConfiguration); parent.addChild(testDescriptor); assertThat(testDescriptor.getTags()).containsExactlyInAnyOrder(TestTag.create("foo"), TestTag.create("bar"), @@ -54,16 +58,14 @@ @Test void shouldUseCustomDisplayNameGeneratorIfPresentFromConfiguration() throws Exception { - UniqueId rootUniqueId = UniqueId.root("segment", "template"); - UniqueId parentUniqueId = rootUniqueId.append("class", "myClass"); - AbstractTestDescriptor parent = containerTestDescriptorWithTags(parentUniqueId, - singleton(TestTag.create("foo"))); + var rootUniqueId = UniqueId.root("segment", "template"); + var parentUniqueId = rootUniqueId.append("class", "myClass"); + var parent = containerTestDescriptorWithTags(parentUniqueId, singleton(TestTag.create("foo"))); when(jupiterConfiguration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - TestTemplateTestDescriptor testDescriptor = new TestTemplateTestDescriptor( - parentUniqueId.append("tmp", "testTemplate()"), MyTestCase.class, - MyTestCase.class.getDeclaredMethod("testTemplate"), jupiterConfiguration); + var testDescriptor = new TestTemplateTestDescriptor(parentUniqueId.append("tmp", "testTemplate()"), + MyTestCase.class, MyTestCase.class.getDeclaredMethod("testTemplate"), List::of, jupiterConfiguration); parent.addChild(testDescriptor); assertThat(testDescriptor.getDisplayName()).isEqualTo("method-display-name"); @@ -71,21 +73,39 @@ @Test void shouldUseStandardDisplayNameGeneratorIfConfigurationNotPresent() throws Exception { - UniqueId rootUniqueId = UniqueId.root("segment", "template"); - UniqueId parentUniqueId = rootUniqueId.append("class", "myClass"); - AbstractTestDescriptor parent = containerTestDescriptorWithTags(parentUniqueId, - singleton(TestTag.create("foo"))); - - when(jupiterConfiguration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); + var rootUniqueId = UniqueId.root("segment", "template"); + var parentUniqueId = rootUniqueId.append("class", "myClass"); + var parent = containerTestDescriptorWithTags(parentUniqueId, singleton(TestTag.create("foo"))); - TestTemplateTestDescriptor testDescriptor = new TestTemplateTestDescriptor( - parentUniqueId.append("tmp", "testTemplate()"), MyTestCase.class, - MyTestCase.class.getDeclaredMethod("testTemplate"), jupiterConfiguration); + var testDescriptor = new TestTemplateTestDescriptor(parentUniqueId.append("tmp", "testTemplate()"), + MyTestCase.class, MyTestCase.class.getDeclaredMethod("testTemplate"), List::of, jupiterConfiguration); parent.addChild(testDescriptor); assertThat(testDescriptor.getDisplayName()).isEqualTo("testTemplate()"); } + @Test + void copyIncludesTransformedDynamicDescendantFilter() throws Exception { + var rootUniqueId = UniqueId.root("segment", "template"); + var parentUniqueId = rootUniqueId.append("class", "myClass"); + var originalUniqueId = parentUniqueId.append("old", "testTemplate()"); + + var original = new TestTemplateTestDescriptor(originalUniqueId, MyTestCase.class, + MyTestCase.class.getDeclaredMethod("testTemplate"), List::of, jupiterConfiguration); + + original.getDynamicDescendantFilter().allowUniqueIdPrefix(originalUniqueId.append("foo", "bar")); + original.getDynamicDescendantFilter().allowIndex(42); + + var newUniqueId = parentUniqueId.append("new", "testTemplate()"); + + var copy = original.withUniqueId(new UniqueIdPrefixTransformer(originalUniqueId, newUniqueId)); + + assertThat(copy.getUniqueId()).isEqualTo(newUniqueId); + assertThat(copy.getDynamicDescendantFilter().test(newUniqueId, 0)).isTrue(); + assertThat(copy.getDynamicDescendantFilter().test(newUniqueId, 42)).isTrue(); + assertThat(copy.getDynamicDescendantFilter().test(originalUniqueId, 1)).isFalse(); + } + private AbstractTestDescriptor containerTestDescriptorWithTags(UniqueId uniqueId, Set tags) { return new AbstractTestDescriptor(uniqueId, "testDescriptor with tags") { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class1WithTestCases.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class1WithTestCases.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class1WithTestCases.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class1WithTestCases.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class2WithTestCases.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class2WithTestCases.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class2WithTestCases.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/Class2WithTestCases.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithStaticInnerTestCases.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithStaticInnerTestCases.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithStaticInnerTestCases.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithStaticInnerTestCases.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,6 +17,7 @@ */ public class ClassWithStaticInnerTestCases { + @SuppressWarnings("JUnitMalformedDeclaration") public static class ShouldBeDiscovered { @Test @@ -24,7 +25,7 @@ } } - @SuppressWarnings("unused") + @SuppressWarnings({ "unused", "JUnitMalformedDeclaration" }) private static class ShouldNotBeDiscovered { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithoutTestCases.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithoutTestCases.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithoutTestCases.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/subpackage/ClassWithoutTestCases.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,19 +11,21 @@ package org.junit.jupiter.engine.discovery; import static java.util.Collections.singleton; -import static java.util.stream.Collectors.toList; +import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.DisplayNameGenerator.getDisplayNameGenerator; import static org.junit.jupiter.engine.descriptor.TestFactoryTestDescriptor.DYNAMIC_CONTAINER_SEGMENT_TYPE; import static org.junit.jupiter.engine.descriptor.TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE; +import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.appendClassTemplateInvocationSegment; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.engineId; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForClass; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForMethod; +import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForStaticClass; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForTestFactoryMethod; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForTestTemplateMethod; -import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForTopLevelClass; import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import static org.junit.platform.engine.SelectorResolutionResult.Status.FAILED; import static org.junit.platform.engine.SelectorResolutionResult.Status.RESOLVED; @@ -48,12 +50,13 @@ import java.net.URLClassLoader; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.ClassTemplate; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Nested; @@ -61,10 +64,11 @@ import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.jupiter.engine.descriptor.ClassTemplateTestDescriptor; import org.junit.jupiter.engine.descriptor.DynamicDescendantFilter; import org.junit.jupiter.engine.descriptor.Filterable; -import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; import org.junit.jupiter.engine.descriptor.JupiterTestDescriptor; import org.junit.jupiter.engine.descriptor.TestTemplateInvocationTestDescriptor; import org.junit.jupiter.engine.descriptor.subpackage.Class1WithTestCases; @@ -72,8 +76,9 @@ import org.junit.jupiter.engine.descriptor.subpackage.ClassWithStaticInnerTestCases; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.FilterResult; import org.junit.platform.engine.SelectorResolutionResult; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; @@ -83,21 +88,23 @@ import org.junit.platform.engine.discovery.PackageSelector; import org.junit.platform.engine.discovery.UniqueIdSelector; import org.junit.platform.launcher.LauncherDiscoveryListener; +import org.junit.platform.launcher.PostDiscoveryFilter; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import org.mockito.ArgumentCaptor; /** * @since 5.0 */ -class DiscoverySelectorResolverTests { +class DiscoverySelectorResolverTests extends AbstractJupiterTestEngineTests { private final JupiterConfiguration configuration = mock(); private final LauncherDiscoveryListener discoveryListener = mock(); - private final JupiterEngineDescriptor engineDescriptor = new JupiterEngineDescriptor(engineId(), configuration); + private TestDescriptor engineDescriptor; @BeforeEach void setUp() { - when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); + when(configuration.getDefaultDisplayNameGenerator()) // + .thenReturn(getDisplayNameGenerator(DisplayNameGenerator.Standard.class)); when(configuration.getDefaultExecutionMode()).thenReturn(ExecutionMode.SAME_THREAD); } @@ -144,7 +151,7 @@ assertTrue(engineDescriptor.getDescendants().isEmpty()); var result = verifySelectorProcessed(selector); assertThat(result.getStatus()).isEqualTo(FAILED); - assertThat(result.getThrowable().get()).hasMessageContaining("Could not load class with name"); + assertThat(result.getThrowable().orElseThrow()).hasMessageContaining("Could not load class with name"); } @Test @@ -194,6 +201,55 @@ } @Test + void classResolutionOfClassTemplate() { + var selector = selectClass(ClassTemplateTestCase.class); + + AtomicBoolean verified = new AtomicBoolean(); + PostDiscoveryFilter filter = descriptor -> { + if (descriptor instanceof ClassTemplateTestDescriptor) { + assertThat(descriptor.mayRegisterTests()).isFalse(); + assertThat(descriptor.getDescendants()).hasSize(1); + verified.set(true); + } + return FilterResult.included("included"); + }; + + resolve(request().selectors(selector).filters(filter)); + + assertThat(verified.get()).describedAs("filter can see descendants").isTrue(); + + TestDescriptor classTemplateDescriptor = getOnlyElement(engineDescriptor.getChildren()); + assertThat(classTemplateDescriptor.mayRegisterTests()).isTrue(); + assertThat(classTemplateDescriptor.getDescendants()).isEmpty(); + + var classTemplateSegment = classTemplateDescriptor.getUniqueId().getLastSegment(); + assertThat(classTemplateSegment.getType()).isEqualTo("class-template"); + assertThat(classTemplateSegment.getValue()).isEqualTo(ClassTemplateTestCase.class.getName()); + } + + @Test + void uniqueIdResolutionOfClassTemplateInvocation() { + var selector = selectUniqueId( + appendClassTemplateInvocationSegment(uniqueIdForClass(ClassTemplateTestCase.class), 1)); + + resolve(request().selectors(selector)); + + assertThat(engineDescriptor.getChildren()).hasSize(1); + + TestDescriptor classTemplateDescriptor = getOnlyElement(engineDescriptor.getChildren()); + + classTemplateDescriptor.prune(); + assertThat(engineDescriptor.getChildren()).hasSize(1); + assertThat(classTemplateDescriptor.mayRegisterTests()).isTrue(); + assertThat(classTemplateDescriptor.getDescendants()).isEmpty(); + + classTemplateDescriptor.prune(); + assertThat(engineDescriptor.getChildren()).hasSize(1); + assertThat(classTemplateDescriptor.mayRegisterTests()).isTrue(); + assertThat(classTemplateDescriptor.getDescendants()).isEmpty(); + } + + @Test void methodResolution() throws NoSuchMethodException { Method test1 = MyTestClass.class.getDeclaredMethod("test1"); MethodSelector selector = selectMethod(test1.getDeclaringClass(), test1); @@ -239,7 +295,7 @@ assertTrue(engineDescriptor.getDescendants().isEmpty()); var result = verifySelectorProcessed(selector); assertThat(result.getStatus()).isEqualTo(FAILED); - assertThat(result.getThrowable().get())// + assertThat(result.getThrowable().orElseThrow())// .isInstanceOf(PreconditionViolationException.class)// .hasMessageStartingWith("Could not load class with name: " + className); } @@ -253,7 +309,7 @@ assertTrue(engineDescriptor.getDescendants().isEmpty()); var result = verifySelectorProcessed(selector); assertThat(result.getStatus()).isEqualTo(FAILED); - assertThat(result.getThrowable().get()).hasMessageContaining("Could not find method"); + assertThat(result.getThrowable().orElseThrow()).hasMessageContaining("Could not find method"); } @Test @@ -323,7 +379,7 @@ assertTrue(engineDescriptor.getDescendants().isEmpty()); var result = verifySelectorProcessed(selectUniqueId(uniqueId)); assertThat(result.getStatus()).isEqualTo(FAILED); - assertThat(result.getThrowable().get())// + assertThat(result.getThrowable().orElseThrow())// .isInstanceOf(PreconditionViolationException.class)// .hasMessageStartingWith("Method [()] does not match pattern"); } @@ -337,7 +393,7 @@ assertThat(engineDescriptor.getDescendants()).isEmpty(); var result = verifySelectorProcessed(selectUniqueId(uniqueId)); assertThat(result.getStatus()).isEqualTo(FAILED); - assertThat(result.getThrowable().get())// + assertThat(result.getThrowable().orElseThrow())// .isInstanceOf(PreconditionViolationException.class)// .hasMessageStartingWith("Method [methodName] does not match pattern"); } @@ -351,7 +407,7 @@ assertTrue(engineDescriptor.getDescendants().isEmpty()); var result = verifySelectorProcessed(selectUniqueId(uniqueId)); assertThat(result.getStatus()).isEqualTo(FAILED); - assertThat(result.getThrowable().get())// + assertThat(result.getThrowable().orElseThrow())// .isInstanceOf(JUnitException.class)// .hasMessage("Failed to load parameter type [%s] for method [%s] in class [%s].", "junit.foo.Enigma", "methodName", getClass().getName()); @@ -421,9 +477,9 @@ assertThat(uniqueIds).contains(uniqueIdForMethod(MyTestClass.class, "test2()")); TestDescriptor classFromMethod1 = descriptorByUniqueId( - uniqueIdForMethod(MyTestClass.class, "test1()")).getParent().get(); + uniqueIdForMethod(MyTestClass.class, "test1()")).getParent().orElseThrow(); TestDescriptor classFromMethod2 = descriptorByUniqueId( - uniqueIdForMethod(MyTestClass.class, "test2()")).getParent().get(); + uniqueIdForMethod(MyTestClass.class, "test2()")).getParent().orElseThrow(); assertEquals(classFromMethod1, classFromMethod2); assertSame(classFromMethod1, classFromMethod2); @@ -457,7 +513,7 @@ List uniqueIds = uniqueIds(); assertThat(uniqueIds)// .describedAs("Failed to pick up DefaultPackageTestCase via classpath scanning")// - .contains(uniqueIdForClass(ReflectionUtils.tryToLoadClass("DefaultPackageTestCase").get())); + .contains(uniqueIdForClass(ReflectionSupport.tryToLoadClass("DefaultPackageTestCase").get())); assertThat(uniqueIds).contains(uniqueIdForClass(Class1WithTestCases.class)); assertThat(uniqueIds).contains(uniqueIdForMethod(Class1WithTestCases.class, "test1()")); assertThat(uniqueIds).contains(uniqueIdForClass(Class2WithTestCases.class)); @@ -481,7 +537,7 @@ List uniqueIds = uniqueIds(); assertThat(uniqueIds)// .describedAs("Failed to pick up DefaultPackageTestCase via classpath scanning")// - .contains(uniqueIdForClass(ReflectionUtils.tryToLoadClass("DefaultPackageTestCase").get())); + .contains(uniqueIdForClass(ReflectionSupport.tryToLoadClass("DefaultPackageTestCase").get())); assertThat(uniqueIds).contains(uniqueIdForClass(Class1WithTestCases.class)); assertThat(uniqueIds).contains(uniqueIdForMethod(Class1WithTestCases.class, "test1()")); assertThat(uniqueIds).contains(uniqueIdForClass(Class2WithTestCases.class)); @@ -492,7 +548,7 @@ @Test void classpathResolutionForJarFiles() throws Exception { - URL jarUrl = getClass().getResource("/jupiter-testjar.jar"); + URL jarUrl = requireNonNull(getClass().getResource("/jupiter-testjar.jar")); Path path = Paths.get(jarUrl.toURI()); List selectors = selectClasspathRoots(singleton(path)); @@ -503,8 +559,8 @@ resolve(request().selectors(selectors)); assertThat(uniqueIds()) // - .contains(uniqueIdForTopLevelClass("com.example.project.FirstTest")) // - .contains(uniqueIdForTopLevelClass("com.example.project.SecondTest")); + .contains(uniqueIdForStaticClass("com.example.project.FirstTest")) // + .contains(uniqueIdForStaticClass("com.example.project.SecondTest")); } finally { Thread.currentThread().setContextClassLoader(originalClassLoader); @@ -750,20 +806,20 @@ } private void resolve(LauncherDiscoveryRequestBuilder builder) { - new DiscoverySelectorResolver().resolveSelectors(builder.build(), engineDescriptor); + engineDescriptor = discoverTests(builder.build()).getEngineDescriptor(); } private TestDescriptor descriptorByUniqueId(UniqueId uniqueId) { return engineDescriptor.getDescendants().stream().filter( - d -> d.getUniqueId().equals(uniqueId)).findFirst().get(); + d -> d.getUniqueId().equals(uniqueId)).findFirst().orElseThrow(); } private List uniqueIds() { - return engineDescriptor.getDescendants().stream().map(TestDescriptor::getUniqueId).collect(toList()); + return engineDescriptor.getDescendants().stream().map(TestDescriptor::getUniqueId).toList(); } private LauncherDiscoveryRequestBuilder request() { - return LauncherDiscoveryRequestBuilder.request() // + return defaultRequest() // .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging") // .listeners(discoveryListener); } @@ -798,11 +854,13 @@ abstract class AbstractTestClass { + @SuppressWarnings("unused") @Test void test() { } } +@SuppressWarnings("NewClassNamingConvention") class MyTestClass { @Test @@ -818,10 +876,11 @@ @TestFactory Stream dynamicTest() { - return new ArrayList().stream(); + return Stream.empty(); } } +@SuppressWarnings("NewClassNamingConvention") class YourTestClass { @Test @@ -833,15 +892,18 @@ } } +@SuppressWarnings("NewClassNamingConvention") class HerTestClass extends MyTestClass { + @SuppressWarnings("JUnitMalformedDeclaration") @Test - void test7(String param) { + void test7(@SuppressWarnings("unused") String param) { } } class OtherTestClass { + @SuppressWarnings({ "JUnitMalformedDeclaration", "NewClassNamingConvention" }) static class NestedTestClass { @Test @@ -884,6 +946,7 @@ } } +@SuppressWarnings("NewClassNamingConvention") class MatchingClass { @Nested class NestedClass { @@ -893,8 +956,16 @@ } } +@SuppressWarnings("NewClassNamingConvention") class OtherClass { @Test void test() { } +} + +@ClassTemplate +class ClassTemplateTestCase { + @Test + void test() { + } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoveryTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoveryTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoveryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoveryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,31 +10,51 @@ package org.junit.jupiter.engine.discovery; +import static java.util.Comparator.comparing; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.junit.jupiter.api.Named.named; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForTestTemplateMethod; +import static org.junit.jupiter.params.provider.Arguments.argumentSet; +import static org.junit.platform.commons.test.IdeUtils.runningInEclipse; import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectNestedClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectNestedMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; -import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import java.util.List; +import java.util.regex.Pattern; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.DisabledInEclipse; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.jupiter.engine.JupiterTestEngine; import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; import org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor; import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.descriptor.ClassSource; import org.junit.platform.launcher.LauncherDiscoveryRequest; /** @@ -46,39 +66,84 @@ @Test void discoverTestClass() { - LauncherDiscoveryRequest request = request().selectors(selectClass(LocalTestCase.class)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(LocalTestCase.class)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(7, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @Test void doNotDiscoverAbstractTestClass() { - LauncherDiscoveryRequest request = request().selectors(selectClass(AbstractTestCase.class)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(AbstractTestCase.class)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(0, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } + @ParameterizedTest + @ValueSource(strings = { "org.junit.jupiter.engine.discovery.DiscoveryTests$InterfaceTestCase", + "org.junit.jupiter.engine.kotlin.KotlinInterfaceTestCase" }) + void doNotDiscoverTestInterface(String className) { + + assumeFalse(runningInEclipse() && className.contains(".kotlin.")); + + LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(className)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); + assertEquals(0, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + } + + @Test + @DisabledInEclipse + void doNotDiscoverGeneratedKotlinDefaultImplsClass() { + LauncherDiscoveryRequest request = defaultRequest() // + .selectors(selectClass("org.junit.jupiter.engine.kotlin.KotlinInterfaceTestCase$DefaultImpls")) // + .build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); + assertEquals(0, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + } + + @Test + @DisabledInEclipse + void discoverDeclaredKotlinDefaultImplsClass() { + LauncherDiscoveryRequest request = defaultRequest().selectors( + selectClass("org.junit.jupiter.engine.kotlin.KotlinDefaultImplsTestCase$DefaultImpls")).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); + assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + } + + @ParameterizedTest + @ValueSource(strings = { + "org.junit.jupiter.engine.discovery.DiscoveryTests$ConcreteImplementationOfInterfaceTestCase", + "org.junit.jupiter.engine.kotlin.KotlinInterfaceImplementationTestCase" }) + void discoverTestClassInheritingTestsFromInterface(String className) { + + assumeFalse(runningInEclipse() && className.contains(".kotlin.")); + + LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(className)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); + assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); + } + @Test void discoverMethodByUniqueId() { - LauncherDiscoveryRequest request = request().selectors( + LauncherDiscoveryRequest request = defaultRequest().selectors( selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod(LocalTestCase.class, "test1()"))).build(); - TestDescriptor engineDescriptor = discoverTests(request); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @Test void discoverMethodByUniqueIdForOverloadedMethod() { - LauncherDiscoveryRequest request = request().selectors( + LauncherDiscoveryRequest request = defaultRequest().selectors( selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod(LocalTestCase.class, "test4()"))).build(); - TestDescriptor engineDescriptor = discoverTests(request); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @Test void discoverMethodByUniqueIdForOverloadedMethodVariantThatAcceptsArguments() { - LauncherDiscoveryRequest request = request().selectors(selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod( - LocalTestCase.class, "test4(" + TestInfo.class.getName() + ")"))).build(); - TestDescriptor engineDescriptor = discoverTests(request); + LauncherDiscoveryRequest request = defaultRequest().selectors( + selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod(LocalTestCase.class, + "test4(" + TestInfo.class.getName() + ")"))).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @@ -86,17 +151,18 @@ void discoverMethodByMethodReference() throws NoSuchMethodException { Method testMethod = LocalTestCase.class.getDeclaredMethod("test3"); - LauncherDiscoveryRequest request = request().selectors(selectMethod(LocalTestCase.class, testMethod)).build(); - TestDescriptor engineDescriptor = discoverTests(request); + LauncherDiscoveryRequest request = defaultRequest().selectors( + selectMethod(LocalTestCase.class, testMethod)).build(); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @Test void discoverMultipleMethodsOfSameClass() { - LauncherDiscoveryRequest request = request().selectors(selectMethod(LocalTestCase.class, "test1"), + LauncherDiscoveryRequest request = defaultRequest().selectors(selectMethod(LocalTestCase.class, "test1"), selectMethod(LocalTestCase.class, "test2")).build(); - TestDescriptor engineDescriptor = discoverTests(request); + TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request); assertThat(engineDescriptor.getChildren()).hasSize(1); TestDescriptor classDescriptor = getOnlyElement(engineDescriptor.getChildren()); @@ -105,29 +171,29 @@ @Test void discoverCompositeSpec() { - LauncherDiscoveryRequest spec = request().selectors( + LauncherDiscoveryRequest spec = defaultRequest().selectors( selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod(LocalTestCase.class, "test2()")), selectClass(LocalTestCase.class)).build(); - TestDescriptor engineDescriptor = discoverTests(spec); + TestDescriptor engineDescriptor = discoverTests(spec).getEngineDescriptor(); assertEquals(7, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @Test void discoverTestTemplateMethodByUniqueId() { - LauncherDiscoveryRequest spec = request().selectors( + LauncherDiscoveryRequest spec = defaultRequest().selectors( selectUniqueId(uniqueIdForTestTemplateMethod(TestTemplateClass.class, "testTemplate()"))).build(); - TestDescriptor engineDescriptor = discoverTests(spec); + TestDescriptor engineDescriptor = discoverTests(spec).getEngineDescriptor(); assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @Test void discoverTestTemplateMethodByMethodSelector() { - LauncherDiscoveryRequest spec = request().selectors( + LauncherDiscoveryRequest spec = defaultRequest().selectors( selectMethod(TestTemplateClass.class, "testTemplate")).build(); - TestDescriptor engineDescriptor = discoverTests(spec); + TestDescriptor engineDescriptor = discoverTests(spec).getEngineDescriptor(); assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors"); } @@ -137,9 +203,9 @@ List.of(TestCaseWithExtendedNested.class, TestCaseWithExtendedNested.ConcreteInner1.class), AbstractSuperClass.NestedInAbstractClass.class, AbstractSuperClass.NestedInAbstractClass.class.getDeclaredMethod("test")); - LauncherDiscoveryRequest spec = request().selectors(selector).build(); + LauncherDiscoveryRequest spec = defaultRequest().selectors(selector).build(); - TestDescriptor engineDescriptor = discoverTests(spec); + TestDescriptor engineDescriptor = discoverTests(spec).getEngineDescriptor(); ClassTestDescriptor topLevelClassDescriptor = (ClassTestDescriptor) getOnlyElement( engineDescriptor.getChildren()); @@ -160,16 +226,203 @@ assertThat(methodDescriptor.getTestMethod().getName()).isEqualTo("test"); } + @ParameterizedTest + @MethodSource("requestsForTestClassWithInvalidTestMethod") + void reportsWarningForTestClassWithInvalidTestMethod(LauncherDiscoveryRequest request) throws Exception { + + var method = InvalidTestCases.InvalidTestMethodTestCase.class.getDeclaredMethod("test"); + + var results = discoverTests(request); + + var discoveryIssues = results.getDiscoveryIssues().stream().sorted(comparing(DiscoveryIssue::message)).toList(); + assertThat(discoveryIssues).hasSize(3); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo("@Test method '%s' must not be private. It will not be executed.", method.toGenericString()); + assertThat(discoveryIssues.get(1).message()) // + .isEqualTo("@Test method '%s' must not be static. It will not be executed.", method.toGenericString()); + assertThat(discoveryIssues.getLast().message()) // + .isEqualTo("@Test method '%s' must not return a value. It will not be executed.", + method.toGenericString()); + } + + static List> requestsForTestClassWithInvalidTestMethod() { + return List.of( // + named("directly selected", + defaultRequest().selectors(selectClass(InvalidTestCases.InvalidTestMethodTestCase.class)).build()), // + named("indirectly selected", defaultRequest() // + .selectors(selectPackage(InvalidTestCases.InvalidTestMethodTestCase.class.getPackageName())) // + .filters(includeClassNamePatterns( + Pattern.quote(InvalidTestCases.InvalidTestMethodTestCase.class.getName()))).build()), // + named("subclasses", defaultRequest() // + .selectors(selectClass(InvalidTestCases.InvalidTestMethodSubclass1TestCase.class), + selectClass(InvalidTestCases.InvalidTestMethodSubclass2TestCase.class)) // + .build()) // + ); + } + + @ParameterizedTest + @MethodSource("requestsForTestClassWithInvalidStandaloneTestClass") + void reportsWarningForInvalidStandaloneTestClass(LauncherDiscoveryRequest request, Class testClass) { + + var results = discoverTests(request); + + var discoveryIssues = results.getDiscoveryIssues().stream().sorted(comparing(DiscoveryIssue::message)).toList(); + assertThat(discoveryIssues).hasSize(2); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo( + "Test class '%s' must not be an inner class unless annotated with @Nested. It will not be executed.", + testClass.getName()); + assertThat(discoveryIssues.getLast().message()) // + .isEqualTo("Test class '%s' must not be private. It will not be executed.", testClass.getName()); + } + + static List requestsForTestClassWithInvalidStandaloneTestClass() { + return List.of( // + argumentSet("directly selected", + defaultRequest().selectors(selectClass(InvalidTestCases.InvalidTestClassTestCase.class)).build(), + InvalidTestCases.InvalidTestClassTestCase.class), // + argumentSet("indirectly selected", defaultRequest() // + .selectors(selectPackage(InvalidTestCases.InvalidTestClassTestCase.class.getPackageName())) // + .filters(includeClassNamePatterns( + Pattern.quote(InvalidTestCases.InvalidTestClassTestCase.class.getName()))).build(), // + InvalidTestCases.InvalidTestClassTestCase.class), // + argumentSet("subclass", defaultRequest() // + .selectors(selectClass(InvalidTestCases.InvalidTestClassSubclassTestCase.class)) // + .build(), // + InvalidTestCases.InvalidTestClassSubclassTestCase.class) // + ); + } + + @ParameterizedTest + @MethodSource("requestsForTestClassWithInvalidNestedTestClass") + void reportsWarningForInvalidNestedTestClass(LauncherDiscoveryRequest request) { + + var results = discoverTests(request); + + var discoveryIssues = results.getDiscoveryIssues().stream().sorted(comparing(DiscoveryIssue::message)).toList(); + assertThat(discoveryIssues).hasSize(2); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo("@Nested class '%s' must not be private. It will not be executed.", + InvalidTestCases.InvalidTestClassTestCase.Inner.class.getName()); + assertThat(discoveryIssues.getLast().message()) // + .startsWith("@Nested class '%s' must not be static.".formatted( + InvalidTestCases.InvalidTestClassTestCase.Inner.class.getName())); + } + + static List> requestsForTestClassWithInvalidNestedTestClass() { + return List.of( // + named("directly selected", + defaultRequest().selectors(selectClass(InvalidTestCases.InvalidTestClassTestCase.Inner.class)).build()), // + named("subclass", defaultRequest() // + .selectors(selectNestedClass(List.of(InvalidTestCases.InvalidTestClassSubclassTestCase.class), + InvalidTestCases.InvalidTestClassTestCase.Inner.class)) // + .build()) // + ); + } + + @Test + void reportsWarningForTestClassWithPotentialNestedTestClasses() { + + var results = discoverTestsForClass(InvalidTestCases.class); + + var discoveryIssues = results.getDiscoveryIssues().stream().sorted(comparing(DiscoveryIssue::message)).toList(); + assertThat(discoveryIssues).hasSize(2); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo( + "Inner class '%s' looks like it was intended to be a test class but will not be executed. It must be static or annotated with @Nested.", + InvalidTestCases.InvalidTestClassSubclassTestCase.class.getName()); + assertThat(discoveryIssues.getLast().message()) // + .isEqualTo( + "Inner class '%s' looks like it was intended to be a test class but will not be executed. It must be static or annotated with @Nested.", + InvalidTestCases.InvalidTestClassTestCase.class.getName()); + } + + @Test + void ignoresUnrelatedClassDefinitionCycles() { + var results = discoverTestsForClass(UnrelatedRecursiveHierarchyTestCase.class); + + assertThat(results.getDiscoveryIssues()).isEmpty(); + } + + @Test + void ignoresRecursiveNonTestHierarchyCycles() { + var results = discoverTestsForClass(NonTestRecursiveHierarchyTestCase.class); + + assertThat(results.getDiscoveryIssues()).isEmpty(); + } + + @Test + void reportsMissingNestedAnnotationOnRecursiveHierarchy() { + var results = discoverTestsForClass(RecursiveHierarchyWithoutNestedTestCase.class); + + var discoveryIssues = results.getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + assertThat(discoveryIssues.getFirst().severity()) // + .isEqualTo(Severity.WARNING); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo( + "Inner class '%s' looks like it was intended to be a test class but will not be executed. It must be static or annotated with @Nested.", + RecursiveHierarchyWithoutNestedTestCase.Inner.class.getName()); + } + + @Test + void reportsWarningsForInvalidTags() throws Exception { + + var results = discoverTestsForClass(InvalidTagsTestCase.class); + + var discoveryIssues = results.getDiscoveryIssues().stream().sorted(comparing(DiscoveryIssue::message)).toList(); + assertThat(discoveryIssues).hasSize(2); + + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo("Invalid tag syntax in @Tag(\"\") declaration on class '%s'. Tag will be ignored.", + InvalidTagsTestCase.class.getName()); + assertThat(discoveryIssues.getFirst().source()) // + .contains(ClassSource.from(InvalidTagsTestCase.class)); + + var method = InvalidTagsTestCase.class.getDeclaredMethod("test"); + assertThat(discoveryIssues.getLast().message()) // + .isEqualTo("Invalid tag syntax in @Tag(\"|\") declaration on method '%s'. Tag will be ignored.", + method.toGenericString()); + assertThat(discoveryIssues.getLast().source()) // + .contains(org.junit.platform.engine.support.descriptor.MethodSource.from(method)); + } + + @Test + void reportsWarningsForBlankDisplayNames() throws Exception { + + var results = discoverTestsForClass(BlankDisplayNamesTestCase.class); + + var discoveryIssues = results.getDiscoveryIssues().stream().sorted(comparing(DiscoveryIssue::message)).toList(); + assertThat(discoveryIssues).hasSize(2); + + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo("@DisplayName on class '%s' must be declared with a non-blank value.", + BlankDisplayNamesTestCase.class.getName()); + assertThat(discoveryIssues.getFirst().source()) // + .contains(ClassSource.from(BlankDisplayNamesTestCase.class)); + + var method = BlankDisplayNamesTestCase.class.getDeclaredMethod("test"); + assertThat(discoveryIssues.getLast().message()) // + .isEqualTo("@DisplayName on method '%s' must be declared with a non-blank value.", + method.toGenericString()); + assertThat(discoveryIssues.getLast().source()) // + .contains(org.junit.platform.engine.support.descriptor.MethodSource.from(method)); + } + // ------------------------------------------------------------------- - private static abstract class AbstractTestCase { + @SuppressWarnings("unused") + static abstract class AbstractTestCase { @Test - void abstractTest() { - + void test() { } + + @Test + abstract void abstractTest(); } + @SuppressWarnings("JUnitMalformedDeclaration") static class LocalTestCase { @Test @@ -227,4 +480,105 @@ } } + static class InvalidTestCases { + + @SuppressWarnings("JUnitMalformedDeclaration") + static class InvalidTestMethodTestCase { + @Test + private static int test() { + return fail("should not be called"); + } + } + + static class InvalidTestMethodSubclass1TestCase extends InvalidTestMethodTestCase { + } + + static class InvalidTestMethodSubclass2TestCase extends InvalidTestMethodTestCase { + } + + @SuppressWarnings({ "JUnitMalformedDeclaration", "InnerClassMayBeStatic" }) + private class InvalidTestClassTestCase { + + @SuppressWarnings("unused") + @Test + void test() { + fail("should not be called"); + } + + @Nested + private static class Inner { + @SuppressWarnings("unused") + @Test + void test() { + fail("should not be called"); + } + } + + } + + private class InvalidTestClassSubclassTestCase extends InvalidTestClassTestCase { + } + + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class UnrelatedRecursiveHierarchyTestCase { + + @Test + void test() { + } + + @SuppressWarnings({ "InnerClassMayBeStatic", "unused" }) + class Inner { + class Recursive extends Inner { + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class RecursiveHierarchyWithoutNestedTestCase { + + @Test + void test() { + } + + @SuppressWarnings({ "InnerClassMayBeStatic", "unused" }) + class Inner extends RecursiveHierarchyWithoutNestedTestCase { + } + } + + @SuppressWarnings("unused") + static class NonTestRecursiveHierarchyTestCase { + @SuppressWarnings("InnerClassMayBeStatic") + class Inner extends NonTestRecursiveHierarchyTestCase { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @Tag("") + static class InvalidTagsTestCase { + @Test + @Tag("|") + void test() { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @DisplayName("") + static class BlankDisplayNamesTestCase { + @Test + @DisplayName("\t") + void test() { + } + } + + interface InterfaceTestCase { + @Test + default void test() { + } + } + + static class ConcreteImplementationOfInterfaceTestCase implements InterfaceTestCase { + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClassTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClassTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClassTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClassTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.function.Predicate; - -import org.junit.jupiter.api.Test; - -/** - * @since 5.0 - */ -class IsInnerClassTests { - - private final Predicate> isInnerClass = new IsInnerClass(); - - @Test - void innerClassEvaluatesToTrue() { - assertThat(isInnerClass).accepts(InnerClassesTestCase.InnerClass.class); - } - - @Test - void staticNestedClassEvaluatesToFalse() { - assertThat(isInnerClass).rejects(InnerClassesTestCase.StaticNestedClass.class); - } - - @Test - void privateInnerClassEvaluatesToFalse() { - assertThat(isInnerClass).rejects(InnerClassesTestCase.PrivateInnerClass.class); - } - - private static class InnerClassesTestCase { - - class InnerClass { - } - - static class StaticNestedClass { - } - - private class PrivateInnerClass { - } - - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClassTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClassTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClassTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClassTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.function.Predicate; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -/** - * @since 5.0 - */ -class IsNestedTestClassTests { - - private final Predicate> isNestedTestClass = new IsNestedTestClass(); - - @Test - void innerClassEvaluatesToTrue() { - assertThat(isNestedTestClass).accepts(NestedClassesTestCase.InnerClass.class); - } - - @Test - void staticNestedClassEvaluatesToFalse() { - assertThat(isNestedTestClass).rejects(NestedClassesTestCase.StaticNestedClass.class); - } - - @Test - void privateNestedClassEvaluatesToFalse() { - assertThat(isNestedTestClass).rejects(NestedClassesTestCase.PrivateInnerClass.class); - } - - private static class NestedClassesTestCase { - - @Nested - class InnerClass { - } - - @Nested - static class StaticNestedClass { - } - - @Nested - private class PrivateInnerClass { - } - - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainerTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainerTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainerTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - -/** - * @since 5.0 - */ -class IsPotentialTestContainerTests { - - private final IsPotentialTestContainer isPotentialTestContainer = new IsPotentialTestContainer(); - - @Test - void staticClassEvaluatesToTrue() { - assertTrue(isPotentialTestContainer.test(StaticClass.class)); - } - - @Test - void privateStaticClassEvaluatesToFalse() { - assertFalse(isPotentialTestContainer.test(PrivateStaticClass.class)); - } - - @Test - void abstractClassEvaluatesToFalse() { - assertFalse(isPotentialTestContainer.test(AbstractClass.class)); - } - - @Test - void localClassEvaluatesToFalse() { - - class LocalClass { - } - - assertFalse(isPotentialTestContainer.test(LocalClass.class)); - } - - @Test - void anonymousClassEvaluatesToFalse() { - - Object object = new Object() { - @Override - public String toString() { - return ""; - } - }; - - assertFalse(isPotentialTestContainer.test(object.getClass())); - } - - private static class PrivateStaticClass { - } - - static class StaticClass { - } - -} - -abstract class AbstractClass { -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTestsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTestsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTestsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestClassWithTestsTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,214 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.engine.discovery.predicates; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Predicate; - -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestFactory; -import org.junit.jupiter.api.TestTemplate; - -/** - * Unit tests for {@link IsTestClassWithTests}. - * - * @since 5.0 - */ -class IsTestClassWithTestsTests { - - private final Predicate> isTestClassWithTests = new IsTestClassWithTests(); - - @Test - void classWithTestMethodEvaluatesToTrue() { - assertTrue(isTestClassWithTests.test(ClassWithTestMethod.class)); - } - - @Test - void classWithTestFactoryEvaluatesToTrue() { - assertTrue(isTestClassWithTests.test(ClassWithTestFactory.class)); - } - - @Test - void classWithTestTemplateEvaluatesToTrue() { - assertTrue(isTestClassWithTests.test(ClassWithTestTemplate.class)); - } - - @Test - void classWithNestedTestClassEvaluatesToTrue() { - assertTrue(isTestClassWithTests.test(ClassWithNestedTestClass.class)); - } - - @Test - void staticTestClassEvaluatesToTrue() { - assertTrue(isTestClassWithTests.test(StaticTestCase.class)); - } - - // ------------------------------------------------------------------------- - - @Test - void privateClassWithTestMethodEvaluatesToFalse() { - assertFalse(isTestClassWithTests.test(PrivateClassWithTestMethod.class)); - } - - @Test - void privateClassWithTestFactoryEvaluatesToFalse() { - assertFalse(isTestClassWithTests.test(PrivateClassWithTestFactory.class)); - } - - @Test - void privateClassWithTestTemplateEvaluatesToFalse() { - assertFalse(isTestClassWithTests.test(PrivateClassWithTestTemplate.class)); - } - - @Test - void privateClassWithNestedTestCasesEvaluatesToFalse() { - assertFalse(isTestClassWithTests.test(PrivateClassWithNestedTestClass.class)); - } - - @Test - void privateStaticTestClassEvaluatesToFalse() { - assertFalse(isTestClassWithTests.test(PrivateStaticTestCase.class)); - } - - /** - * @see https://github.com/junit-team/junit5/issues/2249 - */ - @Test - void recursiveHierarchies() { - assertTrue(isTestClassWithTests.test(OuterClass.class)); - assertFalse(isTestClassWithTests.test(OuterClass.RecursiveInnerClass.class)); - } - - // ------------------------------------------------------------------------- - - private class PrivateClassWithTestMethod { - - @Test - void test() { - } - - } - - private class PrivateClassWithTestFactory { - - @TestFactory - Collection factory() { - return new ArrayList<>(); - } - - } - - private class PrivateClassWithTestTemplate { - - @TestTemplate - void template(int a) { - } - - } - - private class PrivateClassWithNestedTestClass { - - @Nested - class InnerClass { - - @Test - void first() { - } - - @Test - void second() { - } - - } - } - - // ------------------------------------------------------------------------- - - static class StaticTestCase { - - @Test - void test() { - } - } - - private static class PrivateStaticTestCase { - - @Test - void test() { - } - } - - static class OuterClass { - - @Nested - class InnerClass { - - @Test - void test() { - } - } - - // Intentionally commented out so that RecursiveInnerClass is NOT a candidate test class - // @Nested - class RecursiveInnerClass extends OuterClass { - } - } - -} - -// ----------------------------------------------------------------------------- - -class ClassWithTestMethod { - - @Test - void test() { - } - -} - -class ClassWithTestFactory { - - @TestFactory - Collection factory() { - return new ArrayList<>(); - } - -} - -class ClassWithTestTemplate { - - @TestTemplate - void template(int a) { - } - -} - -class ClassWithNestedTestClass { - - @Nested - class InnerClass { - - @Test - void first() { - } - - @Test - void second() { - } - - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestFactoryMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,17 +11,28 @@ package org.junit.jupiter.engine.discovery.predicates; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.function.Predicate; +import java.util.stream.Stream; -import org.junit.jupiter.api.Disabled; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DynamicContainer; +import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Unit tests for {@link IsTestFactoryMethod}. @@ -30,50 +41,104 @@ */ class IsTestFactoryMethodTests { - private static final Predicate isTestFactoryMethod = new IsTestFactoryMethod(); - - @Test - void factoryMethodReturningCollectionOfDynamicTests() { - assertThat(isTestFactoryMethod).accepts(method("dynamicTestsFactory")); - } - - @Test - void bogusFactoryMethodReturningVoid() { - assertThat(isTestFactoryMethod).rejects(method("bogusVoidFactory")); - } - - // TODO [#949] Enable test once IsTestFactoryMethod properly checks return type. - @Disabled("Disabled until IsTestFactoryMethod properly checks return type") - @Test - void bogusFactoryMethodReturningObject() { - assertThat(isTestFactoryMethod).rejects(method("bogusObjectFactory")); - } - - // TODO [#949] Enable test once IsTestFactoryMethod properly checks return type. - @Disabled("Disabled until IsTestFactoryMethod properly checks return type") - @Test - void bogusFactoryMethodReturningCollectionOfStrings() { - assertThat(isTestFactoryMethod).rejects(method("bogusStringsFactory")); + final List discoveryIssues = new ArrayList<>(); + final Predicate isTestFactoryMethod = new IsTestFactoryMethod( + DiscoveryIssueReporter.collecting(discoveryIssues)); + + @ParameterizedTest + @ValueSource(strings = { "dynamicTestsFactoryFromCollection", "dynamicTestsFactoryFromStreamWithExtendsWildcard", + "dynamicTestsFactoryFromNode", "dynamicTestsFactoryFromTest", "dynamicTestsFactoryFromContainer", + "dynamicTestsFactoryFromNodeArray", "dynamicTestsFactoryFromTestArray", + "dynamicTestsFactoryFromContainerArray" }) + void validFactoryMethods(String methodName) { + assertThat(isTestFactoryMethod).accepts(method(methodName)); + assertThat(discoveryIssues).isEmpty(); + } + + @ParameterizedTest + @ValueSource(strings = { "bogusVoidFactory", "bogusStringsFactory", "bogusStringArrayFactory", + "dynamicTestsFactoryFromStreamWithSuperWildcard" }) + void invalidFactoryMethods(String methodName) { + var method = method(methodName); + + assertThat(isTestFactoryMethod).rejects(method); + + var issue = getOnlyElement(discoveryIssues); + assertThat(issue.severity()).isEqualTo(DiscoveryIssue.Severity.WARNING); + assertThat(issue.message()).isEqualTo( + "@TestFactory method '%s' must return a single org.junit.jupiter.api.DynamicNode or a " + + "Stream, Collection, Iterable, Iterator, Iterator provider, or array of org.junit.jupiter.api.DynamicNode. " + + "It will not be executed.", + method.toGenericString()); + assertThat(issue.source()).contains(MethodSource.from(method)); + } + + @ParameterizedTest + @ValueSource(strings = { "objectFactory", "objectArrayFactory", "rawCollectionFactory", "unboundStreamFactory" }) + void suspiciousFactoryMethods(String methodName) { + var method = method(methodName); + + assertThat(isTestFactoryMethod).accepts(method); + + var issue = getOnlyElement(discoveryIssues); + assertThat(issue.severity()).isEqualTo(DiscoveryIssue.Severity.INFO); + assertThat(issue.message()).isEqualTo( + "The declared return type of @TestFactory method '%s' does not support static validation. " + + "It must return a single org.junit.jupiter.api.DynamicNode or a " + + "Stream, Collection, Iterable, Iterator, Iterator provider, or array of org.junit.jupiter.api.DynamicNode.", + method.toGenericString()); + assertThat(issue.source()).contains(MethodSource.from(method)); } private static Method method(String name) { - return ReflectionUtils.findMethod(ClassWithTestFactoryMethods.class, name).get(); + return ReflectionSupport.findMethod(ClassWithTestFactoryMethods.class, name).orElseThrow(); } + @SuppressWarnings("unused") private static class ClassWithTestFactoryMethods { @TestFactory - Collection dynamicTestsFactory() { + Collection dynamicTestsFactoryFromCollection() { return new ArrayList<>(); } @TestFactory - void bogusVoidFactory() { + Stream dynamicTestsFactoryFromStreamWithExtendsWildcard() { + return Stream.empty(); + } + + @TestFactory + DynamicTest dynamicTestsFactoryFromNode() { + return dynamicTest("foo", Assertions::fail); + } + + @TestFactory + DynamicTest dynamicTestsFactoryFromTest() { + return dynamicTest("foo", Assertions::fail); + } + + @TestFactory + DynamicNode dynamicTestsFactoryFromContainer() { + return dynamicContainer("foo", Stream.empty()); + } + + @TestFactory + DynamicNode[] dynamicTestsFactoryFromNodeArray() { + return new DynamicNode[0]; + } + + @TestFactory + DynamicTest[] dynamicTestsFactoryFromTestArray() { + return new DynamicTest[0]; } @TestFactory - Object bogusObjectFactory() { - return new Object(); + DynamicContainer[] dynamicTestsFactoryFromContainerArray() { + return new DynamicContainer[0]; + } + + @TestFactory + void bogusVoidFactory() { } @TestFactory @@ -81,6 +146,37 @@ return new ArrayList<>(); } + @TestFactory + String[] bogusStringArrayFactory() { + return new String[0]; + } + + @TestFactory + Stream dynamicTestsFactoryFromStreamWithSuperWildcard() { + return Stream.empty(); + } + + @TestFactory + Object objectFactory() { + return dynamicTest("foo", Assertions::fail); + } + + @TestFactory + Object[] objectArrayFactory() { + return new DynamicNode[0]; + } + + @SuppressWarnings("rawtypes") + @TestFactory + Collection rawCollectionFactory() { + return new ArrayList<>(); + } + + @TestFactory + Stream unboundStreamFactory() { + return Stream.of(); + } + } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,15 +10,26 @@ package org.junit.jupiter.engine.discovery.predicates; +import static java.util.Comparator.comparing; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; import java.util.function.Predicate; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.commons.support.ModifierSupport; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Unit tests for {@link IsTestMethod}. @@ -27,13 +38,14 @@ */ class IsTestMethodTests { - private static final Predicate isTestMethod = new IsTestMethod(); + final List discoveryIssues = new ArrayList<>(); + final Predicate isTestMethod = new IsTestMethod(DiscoveryIssueReporter.collecting(discoveryIssues)); @Test void publicTestMethod() { Method method = method("publicTestMethod"); // Ensure that somebody doesn't accidentally delete the public modifier again. - assertTrue(ReflectionUtils.isPublic(method)); + assertTrue(ModifierSupport.isPublic(method)); assertThat(isTestMethod).accepts(method); } @@ -41,7 +53,7 @@ void publicTestMethodWithArgument() { Method method = method("publicTestMethodWithArgument", TestInfo.class); // Ensure that somebody doesn't accidentally delete the public modifier again. - assertTrue(ReflectionUtils.isPublic(method)); + assertTrue(ModifierSupport.isPublic(method)); assertThat(isTestMethod).accepts(method); } @@ -57,49 +69,102 @@ @Test void bogusAbstractTestMethod() { - assertThat(isTestMethod).rejects(abstractMethod("bogusAbstractTestMethod")); + var method = abstractMethod("bogusAbstractTestMethod"); + + assertThat(isTestMethod).rejects(method); + assertThat(discoveryIssues).isEmpty(); } @Test - void bogusStaticTestMethod() { - assertThat(isTestMethod).rejects(method("bogusStaticTestMethod")); + void bogusAbstractNonVoidTestMethod() { + var method = abstractMethod("bogusAbstractNonVoidTestMethod"); + + assertThat(isTestMethod).rejects(method); + + var issue = getOnlyElement(discoveryIssues); + assertThat(issue.message()) // + .isEqualTo("@Test method '%s' must not return a value. It will not be executed.", + method.toGenericString()); } @Test - void bogusPrivateTestMethod() { - assertThat(isTestMethod).rejects(method("bogusPrivateTestMethod")); + void bogusStaticTestMethod() { + var method = method("bogusStaticTestMethod"); + + assertThat(isTestMethod).rejects(method); + + var issue = getOnlyElement(discoveryIssues); + assertThat(issue.severity()).isEqualTo(Severity.WARNING); + assertThat(issue.message()).isEqualTo("@Test method '%s' must not be static. It will not be executed.", + method.toGenericString()); + assertThat(issue.source()).contains(MethodSource.from(method)); } @Test - void bogusTestMethodReturningObject() { - assertThat(isTestMethod).rejects(method("bogusTestMethodReturningObject")); + void bogusPrivateTestMethod() { + var method = method("bogusPrivateTestMethod"); + + assertThat(isTestMethod).rejects(method); + + var issue = getOnlyElement(discoveryIssues); + assertThat(issue.severity()).isEqualTo(Severity.WARNING); + assertThat(issue.message()).isEqualTo("@Test method '%s' must not be private. It will not be executed.", + method.toGenericString()); + assertThat(issue.source()).contains(MethodSource.from(method)); } - @Test - void bogusTestMethodReturningVoidReference() { - assertThat(isTestMethod).rejects(method("bogusTestMethodReturningVoidReference")); + @ParameterizedTest + @ValueSource(strings = { "bogusTestMethodReturningObject", "bogusTestMethodReturningVoidReference", + "bogusTestMethodReturningPrimitive" }) + void bogusNonVoidTestMethods(String methodName) { + var method = method(methodName); + + assertThat(isTestMethod).rejects(method); + + var issue = getOnlyElement(discoveryIssues); + assertThat(issue.severity()).isEqualTo(Severity.WARNING); + assertThat(issue.message()).isEqualTo("@Test method '%s' must not return a value. It will not be executed.", + method.toGenericString()); + assertThat(issue.source()).contains(MethodSource.from(method)); } @Test - void bogusTestMethodReturningPrimitive() { - assertThat(isTestMethod).rejects(method("bogusTestMethodReturningPrimitive")); + void bogusStaticPrivateNonVoidTestMethod() { + var method = method("bogusStaticPrivateNonVoidTestMethod"); + + assertThat(isTestMethod).rejects(method); + + assertThat(discoveryIssues).hasSize(3); + discoveryIssues.sort(comparing(DiscoveryIssue::message)); + assertThat(discoveryIssues.getFirst().message()) // + .isEqualTo("@Test method '%s' must not be private. It will not be executed.", method.toGenericString()); + assertThat(discoveryIssues.get(1).message()) // + .isEqualTo("@Test method '%s' must not be static. It will not be executed.", method.toGenericString()); + assertThat(discoveryIssues.getLast().message()) // + .isEqualTo("@Test method '%s' must not return a value. It will not be executed.", + method.toGenericString()); } private static Method method(String name, Class... parameterTypes) { - return ReflectionUtils.findMethod(ClassWithTestMethods.class, name, parameterTypes).get(); + return ReflectionSupport.findMethod(ClassWithTestMethods.class, name, parameterTypes).orElseThrow(); } private Method abstractMethod(String name) { - return ReflectionUtils.findMethod(AbstractClassWithAbstractTestMethod.class, name).get(); + return ReflectionSupport.findMethod(AbstractClassWithAbstractTestMethod.class, name).orElseThrow(); } + @SuppressWarnings({ "JUnitMalformedDeclaration", "unused" }) private static abstract class AbstractClassWithAbstractTestMethod { @Test abstract void bogusAbstractTestMethod(); + @Test + abstract int bogusAbstractNonVoidTestMethod(); + } + @SuppressWarnings({ "JUnitMalformedDeclaration", "unused" }) private static class ClassWithTestMethods { @Test @@ -111,6 +176,11 @@ } @Test + private static int bogusStaticPrivateNonVoidTestMethod() { + return 42; + } + + @Test String bogusTestMethodReturningObject() { return ""; } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestTemplateMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,12 +11,18 @@ package org.junit.jupiter.engine.discovery.predicates; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestTemplate; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; /** * Unit tests for {@link IsTestTemplateMethod}. @@ -25,7 +31,9 @@ */ class IsTestTemplateMethodTests { - private static final IsTestTemplateMethod isTestTemplateMethod = new IsTestTemplateMethod(); + final List discoveryIssues = new ArrayList<>(); + final IsTestTemplateMethod isTestTemplateMethod = new IsTestTemplateMethod( + DiscoveryIssueReporter.collecting(discoveryIssues)); @Test void testTemplateMethodReturningVoid() { @@ -34,13 +42,22 @@ @Test void bogusTestTemplateMethodReturningObject() { - assertThat(isTestTemplateMethod).rejects(method("bogusTemplateReturningObject")); + var method = method("bogusTemplateReturningObject"); + + assertThat(isTestTemplateMethod).rejects(method); + + var issue = getOnlyElement(discoveryIssues); + assertThat(issue.severity()).isEqualTo(DiscoveryIssue.Severity.WARNING); + assertThat(issue.message()).isEqualTo( + "@TestTemplate method '%s' must not return a value. It will not be executed.", method.toGenericString()); + assertThat(issue.source()).contains(MethodSource.from(method)); } private static Method method(String name) { - return ReflectionUtils.findMethod(ClassWithTestTemplateMethods.class, name).get(); + return ReflectionSupport.findMethod(ClassWithTestTemplateMethods.class, name).orElseThrow(); } + @SuppressWarnings("unused") private static class ClassWithTestTemplateMethods { @TestTemplate diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicatesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicatesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicatesTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/TestClassPredicatesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,498 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.discovery.predicates; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestTemplate; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; + +public class TestClassPredicatesTests { + + private final List discoveryIssues = new ArrayList<>(); + private final TestClassPredicates predicates = new TestClassPredicates( + DiscoveryIssueReporter.collecting(discoveryIssues)); + + @Nested + class StandaloneTestClasses { + + @Test + void classWithTestMethodEvaluatesToTrue() { + assertTrue(predicates.looksLikeIntendedTestClass(ClassWithTestMethod.class)); + assertTrue(predicates.isValidStandaloneTestClass(ClassWithTestMethod.class)); + } + + @Test + void classWithTestFactoryEvaluatesToTrue() { + assertTrue(predicates.looksLikeIntendedTestClass(ClassWithTestFactory.class)); + assertTrue(predicates.isValidStandaloneTestClass(ClassWithTestFactory.class)); + } + + @Test + void classWithTestTemplateEvaluatesToTrue() { + assertTrue(predicates.looksLikeIntendedTestClass(ClassWithTestTemplate.class)); + assertTrue(predicates.isValidStandaloneTestClass(ClassWithTestTemplate.class)); + } + + @Test + void classWithNestedTestClassEvaluatesToTrue() { + assertTrue(predicates.looksLikeIntendedTestClass(ClassWithNestedTestClass.class)); + assertTrue(predicates.isValidStandaloneTestClass(ClassWithNestedTestClass.class)); + } + + @Test + void staticTestClassEvaluatesToTrue() { + assertTrue(predicates.looksLikeIntendedTestClass(TestCases.StaticTestCase.class)); + assertTrue(predicates.isValidStandaloneTestClass(TestCases.StaticTestCase.class)); + } + + // ------------------------------------------------------------------------- + + @Test + void abstractClassEvaluatesToFalse() { + assertTrue(predicates.looksLikeIntendedTestClass(AbstractClass.class)); + assertFalse(predicates.isValidStandaloneTestClass(AbstractClass.class)); + assertThat(discoveryIssues).isEmpty(); + } + + @Test + void localClassEvaluatesToFalse() { + + @SuppressWarnings({ "JUnitMalformedDeclaration", "NewClassNamingConvention" }) + class LocalClass { + @SuppressWarnings("unused") + @Test + void test() { + } + } + + var candidate = LocalClass.class; + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var issue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be a local class. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactly(issue); + } + + @Test + void anonymousClassEvaluatesToFalse() { + + Object object = new Object() { + @SuppressWarnings("unused") + @Test + void test() { + } + }; + + Class candidate = object.getClass(); + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var issue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be anonymous. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactly(issue); + } + + @Test + void privateClassWithTestMethodEvaluatesToFalse() { + var candidate = TestCases.PrivateClassWithTestMethod.class; + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var notPrivateIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be private. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + var notInnerClassIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be an inner class unless annotated with @Nested. It will not be executed.".formatted( + candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notPrivateIssue, notInnerClassIssue); + } + + @Test + void privateClassWithTestFactoryEvaluatesToFalse() { + var candidate = TestCases.PrivateClassWithTestFactory.class; + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var notPrivateIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be private. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + var notInnerClassIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be an inner class unless annotated with @Nested. It will not be executed.".formatted( + candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notPrivateIssue, notInnerClassIssue); + } + + @Test + void privateClassWithTestTemplateEvaluatesToFalse() { + var candidate = TestCases.PrivateClassWithTestTemplate.class; + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var notPrivateIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be private. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + var notInnerClassIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be an inner class unless annotated with @Nested. It will not be executed.".formatted( + candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notPrivateIssue, notInnerClassIssue); + } + + @Test + void privateClassWithNestedTestCasesEvaluatesToFalse() { + var candidate = TestCases.PrivateClassWithNestedTestClass.class; + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var notPrivateIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be private. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + var notInnerClassIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be an inner class unless annotated with @Nested. It will not be executed.".formatted( + candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactlyInAnyOrder(notPrivateIssue, notInnerClassIssue); + } + + @Test + void privateStaticTestClassEvaluatesToFalse() { + var candidate = TestCases.PrivateStaticTestCase.class; + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var notPrivateIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be private. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactly(notPrivateIssue); + } + + /* + * see https://github.com/junit-team/junit-framework/issues/2249 + */ + @Test + void recursiveHierarchies() { + assertTrue(predicates.looksLikeIntendedTestClass(TestCases.OuterClass.class)); + assertTrue(predicates.isValidStandaloneTestClass(TestCases.OuterClass.class)); + assertThat(discoveryIssues).isEmpty(); + + var candidate = TestCases.OuterClass.RecursiveInnerClass.class; + + assertTrue(predicates.looksLikeIntendedTestClass(candidate)); + assertFalse(predicates.isValidStandaloneTestClass(candidate)); + + var notInnerClassIssue = DiscoveryIssue.builder(Severity.WARNING, + "Test class '%s' must not be an inner class unless annotated with @Nested. It will not be executed.".formatted( + candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues).containsExactly(notInnerClassIssue); + } + + } + + @Nested + class NestedTestClasses { + + @Test + void innerClassEvaluatesToTrue() { + var candidate = TestCases.NestedClassesTestCase.InnerClass.class; + assertThat(predicates.isAnnotatedWithNested).accepts(candidate); + assertTrue(predicates.isValidNestedTestClass(candidate)); + assertThat(predicates.isAnnotatedWithNestedAndValid).accepts(candidate); + } + + @Test + void staticNestedClassEvaluatesToFalse() { + var candidate = TestCases.NestedClassesTestCase.StaticNestedClass.class; + assertThat(predicates.isAnnotatedWithNested).accepts(candidate); + assertFalse(predicates.isValidNestedTestClass(candidate)); + assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate); + + var issue = DiscoveryIssue.builder(Severity.WARNING, + "@Nested class '%s' must not be static. ".formatted(candidate.getName()) + + "It will only be executed if discovered as a standalone test class. " + + "You should remove the annotation or make it non-static to resolve this warning.") // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues.stream().distinct()).containsExactly(issue); + } + + @Test + void topLevelClassEvaluatesToFalse() { + var candidate = InvalidTopLevelNestedTestClass.class; + assertThat(predicates.isAnnotatedWithNested).accepts(candidate); + assertFalse(predicates.isValidNestedTestClass(candidate)); + assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate); + + var issue = DiscoveryIssue.builder(Severity.WARNING, + ("Top-level class '%s' must not be annotated with @Nested. ".formatted(candidate.getName()) + + "It will be executed anyway for backward compatibility. " + + "You should remove the @Nested annotation to resolve this warning.")) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues.stream().distinct()).containsExactly(issue); + } + + @Test + void privateNestedClassEvaluatesToFalse() { + var candidate = TestCases.NestedClassesTestCase.PrivateInnerClass.class; + assertThat(predicates.isAnnotatedWithNested).accepts(candidate); + assertFalse(predicates.isValidNestedTestClass(candidate)); + assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate); + + var issue = DiscoveryIssue.builder(Severity.WARNING, + "@Nested class '%s' must not be private. It will not be executed.".formatted(candidate.getName())) // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues.stream().distinct()).containsExactly(issue); + } + + @Test + void abstractInnerClassEvaluatesToFalse() { + var candidate = TestCases.NestedClassesTestCase.AbstractInnerClass.class; + assertThat(predicates.isAnnotatedWithNested).accepts(candidate); + assertFalse(predicates.isValidNestedTestClass(candidate)); + assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate); + assertThat(discoveryIssues).isEmpty(); + } + + @Test + void localClassEvaluatesToFalse() { + + @Nested + class LocalClass { + } + + var candidate = LocalClass.class; + + assertThat(predicates.isAnnotatedWithNested).accepts(candidate); + assertFalse(predicates.isValidNestedTestClass(candidate)); + assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate); + + var issue = DiscoveryIssue.builder(Severity.WARNING, + "@Nested class '%s' must not be static. ".formatted(candidate.getName()) + + "It will only be executed if discovered as a standalone test class. " + + "You should remove the annotation or make it non-static to resolve this warning.") // + .source(ClassSource.from(candidate)) // + .build(); + assertThat(discoveryIssues.stream().distinct()).containsExactly(issue); + } + } + + // ------------------------------------------------------------------------- + + static class TestCases { + + @SuppressWarnings({ "JUnitMalformedDeclaration", "InnerClassMayBeStatic" }) + private class PrivateClassWithTestMethod { + + @Test + void test() { + } + + } + + @SuppressWarnings("InnerClassMayBeStatic") + private class PrivateClassWithTestFactory { + + @TestFactory + Collection factory() { + return new ArrayList<>(); + } + + } + + @SuppressWarnings("InnerClassMayBeStatic") + private class PrivateClassWithTestTemplate { + + @TestTemplate + void template(int a) { + } + + } + + @SuppressWarnings("InnerClassMayBeStatic") + private class PrivateClassWithNestedTestClass { + + @Nested + class InnerClass { + + @Test + void first() { + } + + @Test + void second() { + } + + } + } + + // ------------------------------------------------------------------------- + + @SuppressWarnings("JUnitMalformedDeclaration") + static class StaticTestCase { + + @Test + void test() { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + private static class PrivateStaticTestCase { + + @Test + void test() { + } + } + + @SuppressWarnings("NewClassNamingConvention") + static class OuterClass { + + @Nested + class InnerClass { + + @Test + void test() { + } + } + + // Intentionally commented out so that RecursiveInnerClass is NOT a candidate test class + // @Nested + @SuppressWarnings("InnerClassMayBeStatic") + class RecursiveInnerClass extends OuterClass { + } + + } + + private static class NestedClassesTestCase { + + @Nested + class InnerClass { + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @Nested + static class StaticNestedClass { + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @Nested + private class PrivateInnerClass { + } + + @Nested + private abstract class AbstractInnerClass { + } + + } + } + +} + +// ----------------------------------------------------------------------------- + +abstract class AbstractClass { + @SuppressWarnings("unused") + @Test + void test() { + } +} + +@SuppressWarnings("NewClassNamingConvention") +class ClassWithTestMethod { + + @Test + void test() { + } + +} + +@SuppressWarnings("NewClassNamingConvention") +class ClassWithTestFactory { + + @TestFactory + Collection factory() { + return new ArrayList<>(); + } + +} + +@SuppressWarnings("NewClassNamingConvention") +class ClassWithTestTemplate { + + @TestTemplate + void template(int a) { + } + +} + +@SuppressWarnings("NewClassNamingConvention") +class ClassWithNestedTestClass { + + @Nested + class InnerClass { + + @Test + void first() { + } + + @Test + void second() { + } + + } +} + +@SuppressWarnings("NewClassNamingConvention") +@Nested +class InvalidTopLevelNestedTestClass { + @Test + void test() { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -28,6 +28,7 @@ import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ReflectionUtils; /** @@ -82,7 +83,8 @@ } private void testMethodWithASingleStringParameter() { - this.method = ReflectionUtils.findMethod(this.instance.getClass(), "singleStringParameter", String.class).get(); + this.method = ReflectionSupport.findMethod(this.instance.getClass(), "singleStringParameter", + String.class).get(); } private void register(ParameterResolver... resolvers) { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultExecutableInvokerTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultExecutableInvokerTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultExecutableInvokerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultExecutableInvokerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultTestInstancesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultTestInstancesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultTestInstancesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DefaultTestInstancesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DynamicTestIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DynamicTestIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DynamicTestIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/DynamicTestIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -32,7 +32,7 @@ * {@code -mx200m} VM argument will cause an {@link OutOfMemoryError} before * the 200 limit is reached. * - * @see Issue 1865 + * @see Issue 1865 */ @TestFactory Stream generateDynamicTestsThatReferenceLargeAmountsOfMemory() { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreConcurrencyTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreConcurrencyTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreConcurrencyTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreConcurrencyTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,8 +16,8 @@ import java.util.stream.IntStream; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ExtensionContext.Store; +import org.junit.platform.engine.support.store.Namespace; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; /** diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ExtensionContextStoreTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,9 +18,9 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ExtensionContextException; +import org.junit.platform.engine.support.store.Namespace; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.engine.support.store.NamespacedHierarchicalStoreException; diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/InterceptingExecutableInvokerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -31,8 +31,8 @@ @Override T invokeConstructor(Constructor constructor, Object outerInstance) { - return newInvoker().invoke(constructor, Optional.ofNullable(outerInstance), extensionContext, extensionRegistry, - passthroughInterceptor()); + return newInvoker().invoke(constructor, Optional.ofNullable(outerInstance), __ -> extensionContext, + extensionRegistry, passthroughInterceptor()); } private InterceptingExecutableInvoker newInvoker() { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -34,8 +34,10 @@ private final EngineExecutionListener engineExecutionListener = mock(); + private final LauncherStoreFacade launcherStoreFacade = mock(); + private final JupiterEngineExecutionContext originalContext = new JupiterEngineExecutionContext( - engineExecutionListener, configuration); + engineExecutionListener, configuration, launcherStoreFacade); @Test void executionListenerIsHandedOnWhenContextIsExtended() { @@ -98,7 +100,7 @@ assertThat(actualException) // .hasMessage("Failed to close extension context") // - .hasCauseReference(expectedCause); + .cause().isSameAs(expectedCause); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.jupiter.engine.execution; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; @@ -32,6 +33,7 @@ import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ReflectionUtils; /** @@ -68,7 +70,7 @@ register(new NumberParameterResolver()); Class outerClass = ConstructorInjectionTestCase.class; - ConstructorInjectionTestCase outer = ReflectionUtils.newInstance(outerClass, "str"); + ConstructorInjectionTestCase outer = ReflectionSupport.newInstance(outerClass, "str"); Class innerClass = ConstructorInjectionTestCase.NestedTestCase.class; Object[] arguments = resolveConstructorParameters(innerClass, outer); @@ -241,6 +243,20 @@ } @Test + void reportTypeMismatchBetweenParameterAndResolvedParameterWithArrayTypes() { + testMethodWithASingleStringArrayParameter(); + thereIsAParameterResolverThatResolvesTheParameterTo(new int[][] {}); + + assertThatExceptionOfType(ParameterResolutionException.class)// + .isThrownBy(this::resolveMethodParameters)// + .withMessageContaining(// + "resolved a value of type [int[][]] for parameter [java.lang.String[]", // + "in method", // + "but a value assignment compatible with [java.lang.String[]] is required." // + ); + } + + @Test void wrapAllExceptionsThrownDuringParameterResolutionIntoAParameterResolutionException() { anyTestMethodWithAtLeastOneParameter(); IllegalArgumentException cause = anyExceptionButParameterResolutionException(); @@ -308,12 +324,16 @@ testMethodWith("singleStringParameter", String.class); } + private void testMethodWithASingleStringArrayParameter() { + testMethodWith("singleStringArrayParameter", String[].class); + } + private void testMethodWithASinglePrimitiveIntParameter() { testMethodWith("primitiveParameterInt", int.class); } private void testMethodWith(String methodName, Class... parameterTypes) { - this.method = ReflectionUtils.findMethod(this.instance.getClass(), methodName, parameterTypes).get(); + this.method = ReflectionSupport.findMethod(this.instance.getClass(), methodName, parameterTypes).get(); } private void register(ParameterResolver... resolvers) { @@ -411,6 +431,8 @@ void singleStringParameter(String parameter); + void singleStringArrayParameter(String[] parameter); + void primitiveParameterInt(int parameter); void multipleParameters(String first, Integer second, Double third); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/UniqueIdParsingForArrayParameterIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/UniqueIdParsingForArrayParameterIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/UniqueIdParsingForArrayParameterIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/UniqueIdParsingForArrayParameterIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -27,7 +27,7 @@ * Integration tests for {@link UniqueId#parse(String)} for methods * with array type parameters. * - * @see #810 + * @see #810 * @see org.junit.platform.engine.UniqueIdTests * * @since 5.0 @@ -55,6 +55,7 @@ assertThat(UniqueId.parse(uniqueId.toString())).isEqualTo(uniqueId); } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(PrimitiveArrayParameterResolver.class) static class PrimitiveArrayMethodInjectionTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotation.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotation.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotation.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotation.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotationParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotationParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotationParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotationParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolver; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; /** * @since 5.0 @@ -29,7 +29,7 @@ @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - return ReflectionUtils.newInstance(parameterContext.getParameter().getType()); + return ReflectionSupport.newInstance(parameterContext.getParameter().getType()); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomType.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomType.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomType.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomType.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomTypeParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomTypeParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomTypeParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomTypeParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/DoubleParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/DoubleParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/DoubleParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/DoubleParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/LongParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/LongParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/LongParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/LongParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfListsTypeBasedParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfListsTypeBasedParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfListsTypeBasedParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfListsTypeBasedParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfStringsParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfStringsParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfStringsParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfStringsParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NullIntegerParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NullIntegerParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NullIntegerParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NullIntegerParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NumberParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NumberParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NumberParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/NumberParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveArrayParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveArrayParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveArrayParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveArrayParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveIntegerParameterResolver.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveIntegerParameterResolver.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveIntegerParameterResolver.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/PrimitiveIntegerParameterResolver.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/AutoCloseTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/AutoCloseTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/AutoCloseTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/AutoCloseTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -109,6 +109,7 @@ */ @Test void spyPermitsOnlyASingleAction() { + @SuppressWarnings("resource") AutoCloseSpy spy = new AutoCloseSpy("preconditions"); spy.close(); @@ -119,7 +120,7 @@ } /** - * @see #3684 + * @see #3684 */ @Test void fieldsAreProperlyClosedViaInterfaceMethods() { @@ -457,6 +458,7 @@ } @TestInstance(PER_METHOD) + @SuppressWarnings("JUnitMalformedDeclaration") static class InstancePerMethodTestCase { @AutoClose @@ -489,6 +491,7 @@ } @TestInstance(PER_CLASS) + @SuppressWarnings("JUnitMalformedDeclaration") static class InstancePerClassTestCase { static boolean closed = false; @@ -569,6 +572,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class SuperTestCase { @AutoClose @@ -589,6 +593,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class SubTestCase extends SuperTestCase { @AutoClose @@ -607,6 +612,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class FailingFieldsTestCase { @AutoClose @@ -639,6 +645,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class FailingFieldsEnclosingTestCase { @AutoClose diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterAllTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterAllTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterAllTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterAllTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -187,6 +187,7 @@ // ------------------------------------------------------------------------- // Must NOT be private; otherwise, the @Test method gets discovered but never executed. + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooClassLevelCallbacks.class, BarClassLevelCallbacks.class }) static class TopLevelTestCase { @@ -207,6 +208,7 @@ } // Must NOT be private; otherwise, the @Test method gets discovered but never executed. + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BazClassLevelCallbacks.class) static class SecondLevelTestCase extends TopLevelTestCase { @@ -227,6 +229,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(QuuxClassLevelCallbacks.class) static class ThirdLevelTestCase extends SecondLevelTestCase { @@ -247,6 +250,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(QuuxClassLevelCallbacks.class) static class ThirdLevelStaticHidingTestCase extends SecondLevelTestCase { @@ -287,6 +291,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooClassLevelCallbacks.class) static class ExceptionInBeforeAllMethodTestCase { @@ -307,6 +312,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooClassLevelCallbacks.class, ExceptionThrowingBeforeAllCallback.class }) static class ExceptionInBeforeAllCallbackTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterEachTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterEachTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterEachTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterEachTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -229,7 +229,7 @@ ); // @formatter:on - List expected = beforeEachMethodCallSequence.get(0).equals("beforeEachMethod1") ? list1 : list2; + List expected = beforeEachMethodCallSequence.getFirst().equals("beforeEachMethod1") ? list1 : list2; assertEquals(expected, callSequence, "wrong call sequence"); @@ -288,6 +288,7 @@ static class ParentTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BarMethodLevelCallbacks.class) static class ChildTestCase extends ParentTestCase { @@ -306,6 +307,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BarMethodLevelCallbacks.class) static class TestInterfaceTestCase implements TestInterface { @@ -315,6 +317,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooMethodLevelCallbacks.class, BarMethodLevelCallbacks.class }) static class OuterTestCase { @@ -354,6 +357,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooMethodLevelCallbacks.class, ExceptionThrowingBeforeEachCallback.class, BarMethodLevelCallbacks.class }) static class ExceptionInBeforeEachCallbackTestCase { @@ -374,6 +378,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooMethodLevelCallbacks.class, ExceptionThrowingAfterEachCallback.class, BarMethodLevelCallbacks.class }) static class ExceptionInAfterEachCallbackTestCase { @@ -394,6 +399,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooMethodLevelCallbacks.class) static class ExceptionInBeforeEachMethodTestCase { @@ -421,6 +427,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooMethodLevelCallbacks.class) static class ExceptionInAfterEachMethodTestCase { @@ -441,6 +448,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooMethodLevelCallbacks.class) static class ExceptionInTestMethodTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterTestExecutionCallbackTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterTestExecutionCallbackTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterTestExecutionCallbackTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/BeforeAndAfterTestExecutionCallbackTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -256,6 +256,7 @@ static class ParentTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BarTestExecutionCallbacks.class) static class ChildTestCase extends ParentTestCase { @@ -274,6 +275,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BarTestExecutionCallbacks.class) static class TestInterfaceTestCase implements TestInterface { @@ -283,6 +285,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooTestExecutionCallbacks.class, BarTestExecutionCallbacks.class }) static class OuterTestCase { @@ -322,6 +325,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooTestExecutionCallbacks.class, ExceptionThrowingBeforeTestExecutionCallback.class, BarTestExecutionCallbacks.class }) static class ExceptionInBeforeTestExecutionCallbackTestCase { @@ -342,6 +346,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooTestExecutionCallbacks.class, ExceptionThrowingAfterTestExecutionCallback.class, BarTestExecutionCallbacks.class }) static class ExceptionInAfterTestExecutionCallbackTestCase { @@ -362,6 +367,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooTestExecutionCallbacks.class) static class ExceptionInBeforeEachMethodTestCase { @@ -382,6 +388,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooTestExecutionCallbacks.class) static class ExceptionInTestMethodTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/CloseablePathTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/CloseablePathTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/CloseablePathTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/CloseablePathTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -37,9 +37,17 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.nio.file.FileSystem; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.LogRecord; import com.google.common.jimfs.Jimfs; @@ -49,11 +57,12 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.extension.AnnotatedElementContext; import org.junit.jupiter.api.extension.ExtensionConfigurationException; import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDirFactory; @@ -62,6 +71,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.engine.support.store.Namespace; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; /** @@ -94,7 +105,6 @@ * that {@link TempDirFactory#createTempDirectory(AnnotatedElementContext, ExtensionContext)} may provide. * * @since 5.11 - * * @see TempDirFactory */ @Nested @@ -236,7 +246,7 @@ @Override public void close() throws IOException { - TempDirFactory.super.close(); + fileSystem.close(); } } @@ -255,7 +265,6 @@ * set to {@link CleanupMode#ALWAYS}, {@link CleanupMode#NEVER}, or {@link CleanupMode#ON_SUCCESS}. * * @since 5.9 - * * @see TempDir * @see CleanupMode */ @@ -273,7 +282,7 @@ @DisplayName("is done for a cleanup mode of ALWAYS") @ParameterizedTest @ElementTypeSource - void always(Class elementType) throws IOException { + void always(Class elementType, @TrackLogRecords LogRecordListener listener) throws IOException { reset(factory); closeablePath = TempDirectory.createTempDir(factory, ALWAYS, elementType, elementContext, extensionContext); @@ -283,14 +292,18 @@ verify(factory).close(); assertThat(closeablePath.get()).doesNotExist(); + assertThat(listener.stream(Level.INFO)).map(LogRecord::getMessage)// + .noneMatch(m -> m.startsWith("Skipping cleanup of temp dir")); } @DisplayName("is not done for a cleanup mode of NEVER") @ParameterizedTest @ElementTypeSource - void never(Class elementType) throws IOException { + void never(Class elementType, @TrackLogRecords LogRecordListener listener) throws Exception { reset(factory); + when(elementContext.getAnnotatedElement()).thenReturn(TestCase.class.getDeclaredField("tempDir")); + closeablePath = TempDirectory.createTempDir(factory, NEVER, elementType, elementContext, extensionContext); assertThat(closeablePath.get()).isDirectory(); @@ -298,15 +311,56 @@ verify(factory).close(); assertThat(closeablePath.get()).exists(); + assertThat(listener.stream(Level.INFO)).map(LogRecord::getMessage)// + .anyMatch(m -> m.startsWith("Skipping cleanup of temp dir ") + && m.endsWith(" for field TestCase.tempDir due to CleanupMode.NEVER.")); + } + + @DisplayName("is not done for a cleanup mode of ON_SUCCESS, if there is an exception (for annotated field)") + @ParameterizedTest + @ElementTypeSource + void onSuccessWithExceptionForAnnotatedField(Class elementType, @TrackLogRecords LogRecordListener listener) + throws Exception { + + Field field = TestCase.class.getDeclaredField("tempDir"); + + onSuccessWithException(elementType, listener, field, + " for field TestCase.tempDir due to CleanupMode.ON_SUCCESS."); + } + + @DisplayName("is not done for a cleanup mode of ON_SUCCESS, if there is an exception (for annotated method parameter)") + @ParameterizedTest + @ElementTypeSource + void onSuccessWithExceptionForAnnotatedMethodParameter(Class elementType, + @TrackLogRecords LogRecordListener listener) throws Exception { + + Method method = TestCase.class.getDeclaredMethod("test", TestInfo.class, Path.class); + Parameter parameter = method.getParameters()[1]; + + onSuccessWithException(elementType, listener, parameter, + "for parameter 'tempDir' in method test(TestInfo, Path) due to CleanupMode.ON_SUCCESS."); } - @DisplayName("is not done for a cleanup mode of ON_SUCCESS, if there is an exception") + @DisplayName("is not done for a cleanup mode of ON_SUCCESS, if there is an exception (for annotated constructor parameter)") @ParameterizedTest @ElementTypeSource - void onSuccessWithException(Class elementType) throws IOException { + void onSuccessWithExceptionForAnnotatedConstructorParameter(Class elementType, + @TrackLogRecords LogRecordListener listener) throws Exception { + + Constructor constructor = TestCase.class.getDeclaredConstructor(TestInfo.class, Path.class); + Parameter parameter = constructor.getParameters()[1]; + + onSuccessWithException(elementType, listener, parameter, + "for parameter 'tempDir' in constructor TestCase(TestInfo, Path) due to CleanupMode.ON_SUCCESS."); + } + + private void onSuccessWithException(Class elementType, @TrackLogRecords LogRecordListener listener, + AnnotatedElement annotatedElement, String expectedMessage) throws Exception { + reset(factory); when(extensionContext.getExecutionException()).thenReturn(Optional.of(new Exception())); + when(elementContext.getAnnotatedElement()).thenReturn(annotatedElement); closeablePath = TempDirectory.createTempDir(factory, ON_SUCCESS, elementType, elementContext, extensionContext); @@ -316,12 +370,16 @@ verify(factory).close(); assertThat(closeablePath.get()).exists(); + assertThat(listener.stream(Level.INFO)).map(LogRecord::getMessage)// + .anyMatch(m -> m.startsWith("Skipping cleanup of temp dir ") && m.endsWith(expectedMessage)); } @DisplayName("is done for a cleanup mode of ON_SUCCESS, if there is no exception") @ParameterizedTest @ElementTypeSource - void onSuccessWithNoException(Class elementType) throws IOException { + void onSuccessWithNoException(Class elementType, @TrackLogRecords LogRecordListener listener) + throws IOException { + reset(factory); when(extensionContext.getExecutionException()).thenReturn(Optional.empty()); @@ -334,8 +392,80 @@ verify(factory).close(); assertThat(closeablePath.get()).doesNotExist(); + assertThat(listener.stream(Level.INFO)).map(LogRecord::getMessage)// + .noneMatch(m -> m.startsWith("Skipping cleanup of temp dir")); + } + + @DisplayName("deletes symbolic links targeting directory inside temp dir") + @ParameterizedTest + @ElementTypeSource + @DisabledOnOs(WINDOWS) + void deletesSymbolicLinksTargetingDirInsideTempDir(Class elementType, + @TrackLogRecords LogRecordListener listener) throws IOException { + + reset(factory); + + closeablePath = TempDirectory.createTempDir(factory, ON_SUCCESS, elementType, elementContext, + extensionContext); + var rootDir = closeablePath.get(); + assertThat(rootDir).isDirectory(); + + var subDir = createDirectory(rootDir.resolve("subDir")); + Files.createFile(subDir.resolve("file")); + Files.createSymbolicLink(rootDir.resolve("symbolicLink"), subDir); + + closeablePath.close(); + + verify(factory).close(); + assertThat(rootDir).doesNotExist(); + assertThat(listener.stream(Level.WARNING)).map(LogRecord::getMessage).isEmpty(); + + } + + @DisplayName("deletes symbolic links targeting directory outside temp dir") + @ParameterizedTest + @ElementTypeSource + @DisabledOnOs(WINDOWS) + void deletesSymbolicLinksTargetingDirOutsideTempDir(Class elementType, + @TrackLogRecords LogRecordListener listener) throws IOException { + + reset(factory); + + closeablePath = TempDirectory.createTempDir(factory, ON_SUCCESS, elementType, elementContext, + extensionContext); + var rootDir = closeablePath.get(); + assertThat(rootDir).isDirectory(); + + var directoryOutsideTempDir = createTempDirectory("junit-"); + try { + var symbolicLink = createSymbolicLink(rootDir.resolve("symbolicLink"), directoryOutsideTempDir); + + closeablePath.close(); + + verify(factory).close(); + assertThat(rootDir).doesNotExist(); + assertThat(directoryOutsideTempDir).isDirectory(); + assertThat(listener.stream(Level.WARNING)) // + .map(LogRecord::getMessage) // + .contains(("Deleting symbolic link from location inside of temp dir (%s) " + + "to location outside of temp dir (%s) but not the target file/directory").formatted( + symbolicLink, directoryOutsideTempDir.toRealPath())); + } + finally { + Files.deleteIfExists(directoryOutsideTempDir); + } } + } + + static class TestCase { + + Path tempDir; + TestCase(TestInfo testInfo, Path tempDir) { + } + + void test(TestInfo testInfo, Path tempDir) { + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ConfigLoaderExtension.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ConfigLoaderExtension.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ConfigLoaderExtension.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ConfigLoaderExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * Demo extension for auto-detection of extensions loaded via Java's + * {@link java.util.ServiceLoader} mechanism. + * + * @since 5.11 + */ +public class ConfigLoaderExtension implements BeforeAllCallback { + + @Override + public void beforeAll(ExtensionContext context) { + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/DefaultTestReporterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/DefaultTestReporterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/DefaultTestReporterTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/DefaultTestReporterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,156 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.MediaType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.function.ThrowingConsumer; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoSettings; + +@MockitoSettings +class DefaultTestReporterTests { + + @TempDir + Path tempDir; + + @Mock + ExtensionContext extensionContext; + + @Captor + ArgumentCaptor> actionCaptor; + + @InjectMocks + DefaultTestReporter testReporter; + + @Test + void copiesExistingFileToTarget() throws Throwable { + testReporter.publishFile(Files.writeString(tempDir.resolve("source"), "content"), MediaType.TEXT_PLAIN_UTF_8); + + verify(extensionContext).publishFile(eq("source"), eq(MediaType.TEXT_PLAIN_UTF_8), actionCaptor.capture()); + actionCaptor.getValue().accept(tempDir.resolve("target")); + + assertThat(tempDir.resolve("target")).usingCharset(UTF_8).hasContent("content"); + } + + @Test + void executesCustomActionWithTargetFile() throws Throwable { + testReporter.publishFile("target", MediaType.APPLICATION_OCTET_STREAM, + file -> Files.write(file, "content".getBytes())); + + verify(extensionContext).publishFile(eq("target"), eq(MediaType.APPLICATION_OCTET_STREAM), + actionCaptor.capture()); + actionCaptor.getValue().accept(tempDir.resolve("target")); + + assertThat(tempDir.resolve("target")).hasContent("content"); + } + + @Test + void copiesExistingDirectoryToTarget() throws Throwable { + var source = Files.createDirectory(tempDir.resolve("source")); + Files.writeString(source.resolve("source1"), "content1"); + var sourceSubDir = Files.createDirectory(source.resolve("subDir")); + Files.writeString(sourceSubDir.resolve("source2"), "content2"); + Files.writeString(Files.createDirectory(sourceSubDir.resolve("subSubDir")).resolve("source3"), "content3"); + + testReporter.publishDirectory(source); + + verify(extensionContext).publishDirectory(eq("source"), actionCaptor.capture()); + + var target = tempDir.resolve("target"); + actionCaptor.getValue().accept(target); + + assertThat(target).isDirectory(); + assertThat(target.resolve("source1")).usingCharset(UTF_8).hasContent("content1"); + var targetSubDir = target.resolve("subDir"); + assertThat(targetSubDir.resolve("source2")).usingCharset(UTF_8).hasContent("content2"); + assertThat(targetSubDir.resolve("subSubDir").resolve("source3")).usingCharset(UTF_8).hasContent("content3"); + } + + @Test + void executesCustomActionWithTargetDirectory() throws Throwable { + testReporter.publishDirectory("target", + dir -> Files.writeString(Files.createDirectory(dir).resolve("file"), "content", Charset.defaultCharset())); + + verify(extensionContext).publishDirectory(eq("target"), actionCaptor.capture()); + + var target = tempDir.resolve("target"); + actionCaptor.getValue().accept(target); + + assertThat(target.resolve("file")).hasContent("content"); + } + + @Test + @SuppressWarnings("DataFlowIssue") // publishFile() parameters are not @Nullable + void failsWhenPublishingNullFile() { + assertPreconditionViolationNotNullFor("file", () -> testReporter.publishFile(null, MediaType.TEXT_PLAIN)); + } + + @Test + @SuppressWarnings("DataFlowIssue") // publishFile() parameters are not @Nullable + void failsWhenPublishingFileWithNullMediaType() { + assertPreconditionViolationNotNullFor("mediaType", + () -> testReporter.publishFile(Path.of("test"), (MediaType) null)); + } + + @Test + void failsWhenPublishingMissingFile() { + var missingFile = tempDir.resolve("missingFile"); + + assertPreconditionViolationFor(() -> testReporter.publishFile(missingFile, MediaType.APPLICATION_OCTET_STREAM))// + .withMessage("file must exist: " + missingFile); + } + + @Test + void failsWhenPublishingDirectoryAsFile() { + assertPreconditionViolationFor(() -> testReporter.publishFile(tempDir, MediaType.APPLICATION_OCTET_STREAM))// + .withMessage("file must be a regular file: " + tempDir); + } + + @Test + @SuppressWarnings("DataFlowIssue") // publishDirectory() parameters are not @Nullable + void failsWhenPublishingNullDirectory() { + assertPreconditionViolationNotNullFor("directory", () -> testReporter.publishDirectory(null)); + } + + @Test + void failsWhenPublishingMissingDirectory() { + var missingDir = tempDir.resolve("missingDir"); + + assertPreconditionViolationFor(() -> testReporter.publishDirectory(missingDir))// + .withMessage("directory must exist: " + missingDir); + } + + @Test + void failsWhenPublishingFileAsDirectory() throws Exception { + var dir = Files.createFile(tempDir.resolve("source")); + + assertPreconditionViolationFor(() -> testReporter.publishDirectory(dir))// + .withMessage("path must represent a directory: " + dir); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EnigmaException.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EnigmaException.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EnigmaException.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EnigmaException.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EventuallyInterruptibleInvocation.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EventuallyInterruptibleInvocation.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EventuallyInterruptibleInvocation.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/EventuallyInterruptibleInvocation.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExecutionConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExecutionConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExecutionConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExecutionConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -151,6 +151,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @SystemProperty(key = FOO, value = BOGUS) @DeactivatedConditions static class TestCaseWithExecutionConditionOnClass { @@ -167,6 +168,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithExecutionConditionOnMethods { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionContextExecutionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionContextExecutionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionContextExecutionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionContextExecutionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -53,6 +53,7 @@ assertThat(Parent.counter).hasValue(1); } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(OnlyIncrementCounterOnce.class) static class Parent { static final AtomicInteger counter = new AtomicInteger(0); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,8 +15,8 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.DynamicTest.dynamicTest; import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields; -import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedFields; +import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; @@ -74,8 +74,8 @@ import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.commons.support.ModifierSupport; import org.junit.platform.commons.util.ExceptionUtils; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.testkit.engine.EngineExecutionResults; /** @@ -945,13 +945,13 @@ @Override public final void beforeAll(ExtensionContext context) { - injectFields("beforeAll", context.getRequiredTestClass(), null, ReflectionUtils::isStatic); + injectFields("beforeAll", context.getRequiredTestClass(), null, ModifierSupport::isStatic); } @Override public final void postProcessTestInstance(Object testInstance, ExtensionContext context) { injectFields("postProcessTestInstance", context.getRequiredTestClass(), testInstance, - ReflectionUtils::isNotStatic); + ModifierSupport::isNotStatic); } private void injectFields(String trigger, Class testClass, Object instance, Predicate predicate) { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,6 +20,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -31,6 +32,7 @@ import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; import org.junit.jupiter.engine.config.JupiterConfiguration; +import org.junit.platform.commons.util.ClassNamePatternFilterUtils; /** * Tests for the {@link MutableExtensionRegistry}. @@ -39,7 +41,10 @@ */ class ExtensionRegistryTests { - private static final int NUM_DEFAULT_EXTENSIONS = 7; + private static final int NUM_CORE_EXTENSIONS = 7; + private static final int NUM_AUTO_REGISTERED_EXTENSIONS_IN_THIS_PROJECT = 1; // OpenTestReportGenerationSystemPropertyOverride + private static final int NUM_DEFAULT_EXTENSIONS = NUM_CORE_EXTENSIONS + + NUM_AUTO_REGISTERED_EXTENSIONS_IN_THIS_PROJECT; private final JupiterConfiguration configuration = mock(); @@ -49,7 +54,7 @@ void newRegistryWithoutParentHasDefaultExtensions() { List extensions = registry.getExtensions(Extension.class); - assertEquals(NUM_DEFAULT_EXTENSIONS, extensions.size()); + assertEquals(NUM_CORE_EXTENSIONS, extensions.size()); assertDefaultGlobalExtensionsAreRegistered(); } @@ -57,11 +62,28 @@ void newRegistryWithoutParentHasDefaultExtensionsPlusAutodetectedExtensionsLoadedViaServiceLoader() { when(configuration.isExtensionAutoDetectionEnabled()).thenReturn(true); + when(configuration.getFilterForAutoDetectedExtensions()).thenReturn(__ -> true); + registry = createRegistryWithDefaultExtensions(configuration); + + List extensions = registry.getExtensions(Extension.class); + + assertEquals(NUM_DEFAULT_EXTENSIONS + 2, extensions.size()); + assertDefaultGlobalExtensionsAreRegistered(4); + + assertExtensionRegistered(registry, ServiceLoaderExtension.class); + assertEquals(4, countExtensions(registry, BeforeAllCallback.class)); + } + + @Test + void registryIncludesAndExcludesSpecificAutoDetectedExtensions() { + when(configuration.isExtensionAutoDetectionEnabled()).thenReturn(true); + when(configuration.getFilterForAutoDetectedExtensions()).thenReturn( + extensionFilter(ServiceLoaderExtension.class.getName(), ConfigLoaderExtension.class.getName())); registry = createRegistryWithDefaultExtensions(configuration); List extensions = registry.getExtensions(Extension.class); - assertEquals(NUM_DEFAULT_EXTENSIONS + 1, extensions.size()); + assertEquals(NUM_DEFAULT_EXTENSIONS, extensions.size()); assertDefaultGlobalExtensionsAreRegistered(3); assertExtensionRegistered(registry, ServiceLoaderExtension.class); @@ -69,6 +91,54 @@ } @Test + void registryIncludesAllAutoDetectedExtensionsAndExcludesNone() { + when(configuration.isExtensionAutoDetectionEnabled()).thenReturn(true); + when(configuration.getFilterForAutoDetectedExtensions()).thenReturn(extensionFilter("*", "")); + registry = createRegistryWithDefaultExtensions(configuration); + + List extensions = registry.getExtensions(Extension.class); + + assertEquals(NUM_DEFAULT_EXTENSIONS + 2, extensions.size()); + assertDefaultGlobalExtensionsAreRegistered(4); + + assertExtensionRegistered(registry, ServiceLoaderExtension.class); + assertExtensionRegistered(registry, ConfigLoaderExtension.class); + assertEquals(4, countExtensions(registry, BeforeAllCallback.class)); + } + + @Test + void registryIncludesSpecificAutoDetectedExtensionsAndExcludesAll() { + when(configuration.isExtensionAutoDetectionEnabled()).thenReturn(true); + when(configuration.getFilterForAutoDetectedExtensions()).thenReturn( + extensionFilter(ServiceLoaderExtension.class.getName(), "*")); + registry = createRegistryWithDefaultExtensions(configuration); + + List extensions = registry.getExtensions(Extension.class); + + assertEquals(NUM_CORE_EXTENSIONS, extensions.size()); + assertDefaultGlobalExtensionsAreRegistered(2); + + assertExtensionNotRegistered(registry, ServiceLoaderExtension.class); + assertEquals(2, countExtensions(registry, BeforeAllCallback.class)); + } + + @Test + void registryIncludesAndExcludesSameAutoDetectedExtension() { + when(configuration.isExtensionAutoDetectionEnabled()).thenReturn(true); + when(configuration.getFilterForAutoDetectedExtensions()).thenReturn( + extensionFilter(ServiceLoaderExtension.class.getName(), ServiceLoaderExtension.class.getName())); + registry = createRegistryWithDefaultExtensions(configuration); + + List extensions = registry.getExtensions(Extension.class); + + assertEquals(NUM_CORE_EXTENSIONS, extensions.size()); + assertDefaultGlobalExtensionsAreRegistered(2); + + assertExtensionNotRegistered(registry, ServiceLoaderExtension.class); + assertEquals(2, countExtensions(registry, BeforeAllCallback.class)); + } + + @Test void registerExtensionByImplementingClass() { registry.registerExtension(MyExtension.class); @@ -153,6 +223,11 @@ () -> extensionType.getSimpleName() + " should be present"); } + private void assertExtensionNotRegistered(ExtensionRegistry registry, Class extensionType) { + assertTrue(registry.getExtensions(extensionType).isEmpty(), + () -> extensionType.getSimpleName() + " should not be present"); + } + private void assertDefaultGlobalExtensionsAreRegistered() { assertDefaultGlobalExtensionsAreRegistered(2); } @@ -173,6 +248,12 @@ assertEquals(1, countExtensions(registry, InvocationInterceptor.class)); } + private static Predicate> extensionFilter(String includes, String excludes) { + var nameFilter = ClassNamePatternFilterUtils.includeMatchingClassNames(includes) // + .and(ClassNamePatternFilterUtils.excludeMatchingClassNames(excludes)); + return clazz -> nameFilter.test(clazz.getName()); + } + // ------------------------------------------------------------------------- interface MyExtensionApi extends Extension { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/InvocationInterceptorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/InvocationInterceptorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/InvocationInterceptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/InvocationInterceptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,8 @@ package org.junit.jupiter.engine.extension; +import static java.util.function.Function.identity; +import static java.util.function.Predicate.isEqual; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; @@ -22,7 +24,10 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import java.util.EnumSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.UnaryOperator; import java.util.stream.Stream; import org.junit.jupiter.api.AfterAll; @@ -30,9 +35,12 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestReporter; import org.junit.jupiter.api.extension.DynamicTestInvocationContext; import org.junit.jupiter.api.extension.ExtendWith; @@ -42,8 +50,6 @@ import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; import org.junit.platform.commons.JUnitException; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.testkit.engine.EngineExecutionResults; @@ -60,6 +66,7 @@ message(it -> it.startsWith("Chain of InvocationInterceptors never called invocation"))))); } + @SuppressWarnings("JUnitMalformedDeclaration") static class InvocationIgnoringInterceptorTestCase { @RegisterExtension Extension interceptor = new InvocationInterceptor() { @@ -83,6 +90,7 @@ results.testEvents().assertStatistics(stats -> stats.failed(0).succeeded(1)); } + @SuppressWarnings("JUnitMalformedDeclaration") static class InvocationSkippedTestCase { @RegisterExtension Extension interceptor = new InvocationInterceptor() { @@ -109,6 +117,7 @@ "Chain of InvocationInterceptors called invocation multiple times instead of just once"))))); } + @SuppressWarnings("JUnitMalformedDeclaration") static class DoubleInvocationInterceptorTestCase { @RegisterExtension Extension interceptor = new InvocationInterceptor() { @@ -127,33 +136,83 @@ } } - @ParameterizedTest(name = "{0}") - @EnumSource(InvocationType.class) - void callsInterceptors(InvocationType invocationType) { + @TestFactory + Stream callsInterceptors() { var results = executeTestsForClass(TestCaseWithThreeInterceptors.class); results.testEvents().assertStatistics(stats -> stats.failed(0).succeeded(3)); - assertThat(getEvents(results, EnumSet.of(invocationType)).distinct()) // - .containsExactly("before:foo", "before:bar", "before:baz", "test", "after:baz", "after:bar", - "after:foo"); + return Arrays.stream(InvocationType.values()) // + .map(it -> dynamicTest(it.name(), () -> verifyEvents(results, it))); } - private Stream getEvents(EngineExecutionResults results, EnumSet types) { - return results.allEvents().reportingEntryPublished() // - .map(event -> event.getPayload(ReportEntry.class).orElseThrow()) // - .map(ReportEntry::getKeyValuePairs) // - .filter(map -> map.keySet().stream().map(InvocationType::valueOf).anyMatch(types::contains)) // - .flatMap(map -> map.values().stream()); + private void verifyEvents(EngineExecutionResults results, InvocationType invocationType) { + var beforeEvents = List.of("before:foo", "before:bar", "before:baz"); + var testEvent = List.of("test"); + var afterEvents = List.of("after:baz", "after:bar", "after:foo"); + var allEvents = Stream.of(beforeEvents, testEvent, afterEvents).flatMap(Collection::stream).toList(); + String testClassName = TestCaseWithThreeInterceptors.class.getName(); + + var expectedElements = switch (invocationType) { + case BEFORE_ALL, AFTER_ALL -> prefixed(allEvents, testClassName); + case CONSTRUCTOR -> concatStreams( + prefixed(allEvents, it -> it.endsWith(":bar") ? testClassName : "test(TestReporter)"), + prefixed(allEvents, it -> it.endsWith(":bar") ? testClassName : "testTemplate(TestReporter)[1]"), + prefixed(allEvents, it -> it.endsWith(":bar") ? testClassName : "testFactory(TestReporter)")); + case BEFORE_EACH, AFTER_EACH -> concatStreams(prefixed(allEvents, "test(TestReporter)"), + prefixed(allEvents, "testTemplate(TestReporter)[1]"), prefixed(allEvents, "testFactory(TestReporter)")); + case TEST_METHOD -> prefixed(allEvents, "test(TestReporter)"); + case TEST_TEMPLATE_METHOD -> prefixed(allEvents, "testTemplate(TestReporter)[1]"); + case TEST_FACTORY_METHOD -> prefixed(allEvents, "testFactory(TestReporter)"); + case DYNAMIC_TEST -> concatStreams(prefixed(beforeEvents, "testFactory(TestReporter)[1]"), + prefixed(testEvent, "testFactory(TestReporter)"), + prefixed(afterEvents, "testFactory(TestReporter)[1]")); + }; + + assertThat(getEvents(results, invocationType)) // + .containsExactlyElementsOf(expectedElements.toList()); + } + + @SafeVarargs + @SuppressWarnings("varargs") + private static Stream concatStreams(Stream... items) { + return Stream.of(items).flatMap(identity()); + } + + private static Stream prefixed(List values, String prefix) { + return prefixed(values, __ -> prefix); + } + + private static Stream prefixed(List values, UnaryOperator prefixGenerator) { + return values.stream() // + .map(it -> "[%s] %s".formatted(prefixGenerator.apply(it), it)); } + private Stream getEvents(EngineExecutionResults results, InvocationType invocationType) { + return results.allEvents().reportingEntryPublished().stream() // + .flatMap(event -> { + var reportEntry = event.getPayload(ReportEntry.class).orElseThrow(); + var keyValuePairs = reportEntry.getKeyValuePairs(); + if (keyValuePairs.keySet().stream() // + .map(InvocationType::valueOf) // + .anyMatch(isEqual(invocationType))) { + return keyValuePairs.values().stream() // + .map(it -> "[%s] %s".formatted(event.getTestDescriptor().getLegacyReportingName(), it)); + } + return Stream.empty(); + }); + } + + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooInvocationInterceptor.class, BarInvocationInterceptor.class, BazInvocationInterceptor.class }) + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) static class TestCaseWithThreeInterceptors { public TestCaseWithThreeInterceptors(TestReporter reporter) { publish(reporter, InvocationType.CONSTRUCTOR); } + @SuppressWarnings("JUnitMalformedDeclaration") @BeforeAll static void beforeAll(TestReporter reporter) { publish(reporter, InvocationType.BEFORE_ALL); @@ -164,16 +223,19 @@ publish(reporter, InvocationType.BEFORE_EACH); } + @Order(1) @Test void test(TestReporter reporter) { publish(reporter, InvocationType.TEST_METHOD); } + @Order(2) @RepeatedTest(1) void testTemplate(TestReporter reporter) { publish(reporter, InvocationType.TEST_TEMPLATE_METHOD); } + @Order(3) @TestFactory DynamicTest testFactory(TestReporter reporter) { publish(reporter, InvocationType.TEST_FACTORY_METHOD); @@ -187,6 +249,7 @@ publish(reporter, InvocationType.AFTER_EACH); } + @SuppressWarnings("JUnitMalformedDeclaration") @AfterAll static void afterAll(TestReporter reporter) { publish(reporter, InvocationType.AFTER_ALL); @@ -219,6 +282,11 @@ } @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override public void interceptBeforeAllMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { @@ -293,8 +361,8 @@ assertThat(invocationContext.getExecutable()).isNotNull(); assertThat(extensionContext.getUniqueId()).isNotBlank(); assertThat(extensionContext.getElement()).isEmpty(); - assertThat(extensionContext.getParent().flatMap(ExtensionContext::getTestMethod)).contains( - testClass.getDeclaredMethod("testFactory", TestReporter.class)); + assertThat(extensionContext.getParent().flatMap(ExtensionContext::getTestMethod)) // + .contains(testClass.getDeclaredMethod("testFactory", TestReporter.class)); reportAndProceed(invocation, extensionContext, InvocationType.DYNAMIC_TEST); } @@ -344,6 +412,12 @@ BarInvocationInterceptor() { super("bar"); } + + @SuppressWarnings("deprecation") + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.DEFAULT; + } } static class BazInvocationInterceptor extends ReportingInvocationInterceptor { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/LifecycleMethodExecutionExceptionHandlerTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/LifecycleMethodExecutionExceptionHandlerTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/LifecycleMethodExecutionExceptionHandlerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/LifecycleMethodExecutionExceptionHandlerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -297,6 +297,7 @@ // ------------------------------------------ + @SuppressWarnings("JUnitMalformedDeclaration") static class BaseTestCase { @BeforeAll static void throwBeforeAll() { @@ -348,6 +349,7 @@ static class UnrecoverableExceptionTestCase extends BaseTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ShouldNotBeCalledHandler.class) @ExtendWith(SwallowExceptionHandler.class) @ExtendWith(RethrowExceptionHandler.class) diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,21 +18,32 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.LogRecord; +import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.ClassOrderer; +import org.junit.jupiter.api.ClassTemplate; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestClassOrder; import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContext; +import org.junit.jupiter.api.extension.ClassTemplateInvocationContextProvider; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.testkit.engine.EngineDiscoveryResults; import org.junit.platform.testkit.engine.EngineTestKit; import org.junit.platform.testkit.engine.Events; @@ -52,7 +63,22 @@ } @Test + void noOrderer() { + var discoveryIssues = discoverTests(null).getDiscoveryIssues(); + assertIneffectiveOrderAnnotationIssues(discoveryIssues); + + executeTests(null)// + .assertStatistics(stats -> stats.succeeded(callSequence.size())); + + assertThat(callSequence)// + .containsExactlyInAnyOrder("A_TestCase", "B_TestCase", "C_TestCase"); + } + + @Test void className() { + var discoveryIssues = discoverTests(ClassOrderer.ClassName.class).getDiscoveryIssues(); + assertIneffectiveOrderAnnotationIssues(discoveryIssues); + executeTests(ClassOrderer.ClassName.class)// .assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -80,6 +106,9 @@ @Test void displayName() { + var discoveryIssues = discoverTests(ClassOrderer.DisplayName.class).getDiscoveryIssues(); + assertIneffectiveOrderAnnotationIssues(discoveryIssues); + executeTests(ClassOrderer.DisplayName.class)// .assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -89,6 +118,9 @@ @Test void orderAnnotation() { + var discoveryIssues = discoverTests(ClassOrderer.OrderAnnotation.class).getDiscoveryIssues(); + assertThat(discoveryIssues).isEmpty(); + executeTests(ClassOrderer.OrderAnnotation.class)// .assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -124,10 +156,61 @@ @Test void random() { + var discoveryIssues = discoverTests(ClassOrderer.Random.class).getDiscoveryIssues(); + assertIneffectiveOrderAnnotationIssues(discoveryIssues); + executeTests(ClassOrderer.Random.class)// .assertStatistics(stats -> stats.succeeded(callSequence.size())); } + @Test + void classTemplateWithLocalConfig() { + var classTemplate = ClassTemplateWithLocalConfigTestCase.class; + var inner0 = ClassTemplateWithLocalConfigTestCase.Inner0.class; + var inner1 = ClassTemplateWithLocalConfigTestCase.Inner1.class; + var inner1Inner1 = ClassTemplateWithLocalConfigTestCase.Inner1.Inner1Inner1.class; + var inner1Inner0 = ClassTemplateWithLocalConfigTestCase.Inner1.Inner1Inner0.class; + + executeTests(ClassOrderer.Random.class, selectClass(classTemplate))// + .assertStatistics(stats -> stats.succeeded(callSequence.size())); + + var inner1InvocationCallSequence = Stream.of(inner1, inner1Inner1, inner1Inner0, inner1Inner0).toList(); + var inner1CallSequence = twice(inner1InvocationCallSequence).toList(); + var outerCallSequence = Stream.concat(Stream.of(classTemplate), + Stream.concat(inner1CallSequence.stream(), Stream.of(inner0))).toList(); + var expectedCallSequence = twice(outerCallSequence).map(Class::getSimpleName).toList(); + + assertThat(callSequence).containsExactlyElementsOf(expectedCallSequence); + } + + private static Stream twice(List values) { + return Stream.concat(values.stream(), values.stream()); + } + + @Test + void classTemplateWithGlobalConfig() { + var classTemplate = ClassTemplateWithLocalConfigTestCase.class; + var otherClass = A_TestCase.class; + + executeTests(ClassOrderer.OrderAnnotation.class, selectClass(otherClass), selectClass(classTemplate))// + .assertStatistics(stats -> stats.succeeded(callSequence.size())); + + assertThat(callSequence)// + .containsSubsequence(classTemplate.getSimpleName(), otherClass.getSimpleName()); + } + + private static void assertIneffectiveOrderAnnotationIssues(List discoveryIssues) { + assertThat(discoveryIssues).hasSize(2); + assertThat(discoveryIssues).extracting(DiscoveryIssue::severity).containsOnly(Severity.INFO); + assertThat(discoveryIssues).extracting(DiscoveryIssue::message) // + .allMatch(it -> it.startsWith("Ineffective @Order annotation on class") + && it.contains("It will not be applied because ClassOrderer.OrderAnnotation is not in use.") + && it.endsWith( + "Note that the annotation may be either directly present or meta-present on the class.")); + assertThat(discoveryIssues).extracting(DiscoveryIssue::source).extracting(Optional::orElseThrow) // + .containsExactlyInAnyOrder(ClassSource.from(A_TestCase.class), ClassSource.from(C_TestCase.class)); + } + private Events executeTests(Class classOrderer) { return executeTests(classOrderer, selectClass(A_TestCase.class), selectClass(B_TestCase.class), selectClass(C_TestCase.class)); @@ -135,14 +218,32 @@ private Events executeTests(Class classOrderer, DiscoverySelector... selectors) { // @formatter:off - return EngineTestKit.engine("junit-jupiter") - .configurationParameter(DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME, classOrderer.getName()) - .selectors(selectors) - .execute() - .testEvents(); + return testKit(classOrderer, selectors) + .execute() + .testEvents(); // @formatter:on } + private EngineDiscoveryResults discoverTests(Class classOrderer) { + return discoverTests(classOrderer, selectClass(A_TestCase.class), selectClass(B_TestCase.class), + selectClass(C_TestCase.class)); + } + + private EngineDiscoveryResults discoverTests(Class classOrderer, + DiscoverySelector... selectors) { + return testKit(classOrderer, selectors).discover(); + } + + private static EngineTestKit.Builder testKit(Class classOrderer, + DiscoverySelector[] selectors) { + + var testKit = EngineTestKit.engine("junit-jupiter"); + if (classOrderer != null) { + testKit.configurationParameter(DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME, classOrderer.getName()); + } + return testKit.selectors(selectors); + } + static abstract class BaseTestCase { @BeforeEach @@ -265,5 +366,74 @@ } } } + + @SuppressWarnings("JUnitMalformedDeclaration") + @Order(1) + @TestClassOrder(ClassOrderer.OrderAnnotation.class) + @ClassTemplate + @ExtendWith(ClassTemplateWithLocalConfigTestCase.Twice.class) + static class ClassTemplateWithLocalConfigTestCase { + + @Test + void test() { + callSequence.add(ClassTemplateWithLocalConfigTestCase.class.getSimpleName()); + } + + @Nested + @Order(1) + class Inner0 { + @Test + void test() { + callSequence.add(getClass().getSimpleName()); + } + } + + @Nested + @ClassTemplate + @Order(0) + class Inner1 { + + @Test + void test() { + callSequence.add(getClass().getSimpleName()); + } + + @Nested + @ClassTemplate + @Order(2) + class Inner1Inner0 { + @Test + void test() { + callSequence.add(getClass().getSimpleName()); + } + } + + @Nested + @Order(1) + class Inner1Inner1 { + @Test + void test() { + callSequence.add(getClass().getSimpleName()); + } + } + } + + private static class Twice implements ClassTemplateInvocationContextProvider { + + @Override + public boolean supportsClassTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideClassTemplateInvocationContexts( + ExtensionContext context) { + return Stream.of(new Ctx(), new Ctx()); + } + + private record Ctx() implements ClassTemplateInvocationContext { + } + } + } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.jupiter.engine.extension; +import static java.util.Comparator.comparing; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.DynamicTest.dynamicTest; import static org.junit.jupiter.api.MethodOrderer.Random.RANDOM_SEED_PROPERTY_NAME; @@ -18,11 +19,16 @@ import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME; import static org.junit.jupiter.engine.Constants.PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.launcher.LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -47,8 +53,15 @@ import org.junit.jupiter.api.TestReporter; import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.engine.JupiterTestEngine; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.commons.util.ClassUtils; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.testkit.engine.EngineDiscoveryResults; import org.junit.platform.testkit.engine.EngineTestKit; import org.junit.platform.testkit.engine.Events; import org.mockito.Mockito; @@ -83,7 +96,7 @@ // on the class names. assertThat(testClass.getSuperclass().getName()).isGreaterThan(testClass.getName()); - var tests = executeTestsInParallel(testClass); + var tests = executeTestsInParallel(testClass, Random.class); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -105,7 +118,7 @@ // on the class names. assertThat(testClass.getSuperclass().getName()).isLessThan(testClass.getName()); - var tests = executeTestsInParallel(testClass); + var tests = executeTestsInParallel(testClass, Random.class); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -116,7 +129,7 @@ @Test void displayName() { - var tests = executeTestsInParallel(DisplayNameTestCase.class); + var tests = executeTestsInParallel(DisplayNameTestCase.class, Random.class); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -139,7 +152,7 @@ @Test void orderAnnotationWithNestedTestClass() { - var tests = executeTestsInParallel(OrderAnnotationWithNestedClassTestCase.class); + var tests = executeTestsInParallel(OrderAnnotationWithNestedClassTestCase.class, Random.class); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -150,7 +163,7 @@ } private void assertOrderAnnotationSupport(Class testClass) { - var tests = executeTestsInParallel(testClass); + var tests = executeTestsInParallel(testClass, Random.class); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -161,16 +174,17 @@ @Test void random() { - var tests = executeTestsInParallel(RandomTestCase.class); + var tests = executeTestsInParallel(RandomTestCase.class, Random.class); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); assertThat(threadNames).hasSize(1); } - @Test - void defaultOrderer() { - var tests = executeTestsInParallel(WithoutTestMethodOrderTestCase.class, OrderAnnotation.class); + @ParameterizedTest + @ValueSource(classes = { WithoutTestMethodOrderTestCase.class, ClassTemplateTestCase.class }) + void defaultOrderer(Class testClass) { + var tests = executeTestsInParallel(testClass, OrderAnnotation.class); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); @@ -265,57 +279,97 @@ } @Test - void misbehavingMethodOrdererThatAddsElements(@TrackLogRecords LogRecordListener listener) { + void reportsDiscoveryIssuesForIneffectiveOrderAnnotations() throws Exception { + var results = discoverTests(WithoutTestMethodOrderTestCase.class, OrderAnnotation.class); + assertThat(results.getDiscoveryIssues()).isEmpty(); + + results = discoverTests(WithoutTestMethodOrderTestCase.class, null); + assertIneffectiveOrderAnnotationIssues(results.getDiscoveryIssues()); + + results = discoverTests(WithoutTestMethodOrderTestCase.class, Random.class); + assertIneffectiveOrderAnnotationIssues(results.getDiscoveryIssues()); + } + + @Test + void misbehavingMethodOrdererThatAddsElements() { Class testClass = MisbehavingByAddingTestCase.class; - executeTestsInParallel(testClass).assertStatistics(stats -> stats.succeeded(2)); + var discoveryIssues = discoverTests(testClass, null).getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); - assertThat(callSequence).containsExactlyInAnyOrder("test1()", "test2()"); + var issue = discoveryIssues.getFirst(); + assertThat(issue.severity()).isEqualTo(Severity.WARNING); + assertThat(issue.message()).isEqualTo( + "MethodOrderer [%s] added 2 MethodDescriptor(s) for test class [%s] which will be ignored.", + MisbehavingByAdding.class.getName(), testClass.getName()); + assertThat(issue.source()).contains(ClassSource.from(testClass)); - var expectedMessage = "MethodOrderer [" + MisbehavingByAdding.class.getName() - + "] added 2 MethodDescriptor(s) for test class [" + testClass.getName() + "] which will be ignored."; + executeTestsInParallel(testClass, null, Severity.ERROR) // + .assertStatistics(stats -> stats.succeeded(2)); - assertExpectedLogMessage(listener, expectedMessage); + assertThat(callSequence).containsExactly("test1()", "test2()"); } @Test - void misbehavingMethodOrdererThatRemovesElements(@TrackLogRecords LogRecordListener listener) { - Class testClass = MisbehavingByRemovingTestCase.class; + void misbehavingMethodOrdererThatImpersonatesElements() { + Class testClass = MisbehavingByImpersonatingTestCase.class; - executeTestsInParallel(testClass).assertStatistics(stats -> stats.succeeded(3)); + executeTestsInParallel(testClass, Random.class).assertStatistics(stats -> stats.succeeded(2)); - assertThat(callSequence).containsExactlyInAnyOrder("test1()", "test2()", "test3()"); + assertThat(callSequence).containsExactlyInAnyOrder("test1()", "test2()"); + } - var expectedMessage = "MethodOrderer [" + MisbehavingByRemoving.class.getName() - + "] removed 2 MethodDescriptor(s) for test class [" + testClass.getName() - + "] which will be retained with arbitrary ordering."; + @Test + void misbehavingMethodOrdererThatRemovesElements() { + Class testClass = MisbehavingByRemovingTestCase.class; - assertExpectedLogMessage(listener, expectedMessage); - } + var discoveryIssues = discoverTests(testClass, null).getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); - private void assertExpectedLogMessage(LogRecordListener listener, String expectedMessage) { - // @formatter:off - assertThat(listener.stream(Level.WARNING) - .map(LogRecord::getMessage)) - .contains(expectedMessage); - // @formatter:on + var issue = discoveryIssues.getFirst(); + assertThat(issue.severity()).isEqualTo(Severity.WARNING); + assertThat(issue.message()).isEqualTo( + "MethodOrderer [%s] removed 2 MethodDescriptor(s) for test class [%s] which will be retained with arbitrary ordering.", + MisbehavingByRemoving.class.getName(), testClass.getName()); + assertThat(issue.source()).contains(ClassSource.from(testClass)); + + executeTestsInParallel(testClass, null, Severity.ERROR) // + .assertStatistics(stats -> stats.succeeded(4)); + + assertThat(callSequence) // + .containsExactlyInAnyOrder("test1()", "test2()", "test3()", "test4()") // + .containsSubsequence("test3()", "test4()") // ordered in MisbehavingByRemoving + .containsSubsequence("test1()", "test3()") // removed item is re-added before ordered item + .containsSubsequence("test1()", "test4()") // removed item is re-added before ordered item + .containsSubsequence("test2()", "test3()") // removed item is re-added before ordered item + .containsSubsequence("test2()", "test4()");// removed item is re-added before ordered item } - private Events executeTestsInParallel(Class testClass) { - return executeTestsInParallel(testClass, Random.class); + private EngineDiscoveryResults discoverTests(Class testClass, Class defaultOrderer) { + return testKit(testClass, defaultOrderer, Severity.INFO).discover(); } private Events executeTestsInParallel(Class testClass, Class defaultOrderer) { - // @formatter:off - return EngineTestKit - .engine("junit-jupiter") - .configurationParameter(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME, "true") - .configurationParameter(DEFAULT_PARALLEL_EXECUTION_MODE, "concurrent") - .configurationParameter(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME, defaultOrderer.getName()) - .selectors(selectClass(testClass)) - .execute() + return executeTestsInParallel(testClass, defaultOrderer, Severity.INFO); + } + + private Events executeTestsInParallel(Class testClass, Class defaultOrderer, + Severity criticalSeverity) { + return testKit(testClass, defaultOrderer, criticalSeverity) // + .execute() // .testEvents(); - // @formatter:on + } + + private static EngineTestKit.Builder testKit(Class testClass, Class defaultOrderer, + Severity criticalSeverity) { + var testKit = EngineTestKit.engine("junit-jupiter") // + .configurationParameter(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME, "true") // + .configurationParameter(DEFAULT_PARALLEL_EXECUTION_MODE, "concurrent") // + .configurationParameter(CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, criticalSeverity.name()); + if (defaultOrderer != null) { + testKit.configurationParameter(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME, defaultOrderer.getName()); + } + return testKit.selectors(selectClass(testClass)); } private Events executeRandomTestCaseInParallelWithRandomSeed(String seed) { @@ -335,8 +389,24 @@ // @formatter:on } + private static void assertIneffectiveOrderAnnotationIssues(List discoveryIssues) throws Exception { + assertThat(discoveryIssues).hasSize(3); + assertThat(discoveryIssues).extracting(DiscoveryIssue::severity).containsOnly(Severity.INFO); + assertThat(discoveryIssues).extracting(DiscoveryIssue::message) // + .allMatch(it -> it.startsWith("Ineffective @Order annotation on method") + && it.contains("It will not be applied because MethodOrderer.OrderAnnotation is not in use.") + && it.endsWith( + "Note that the annotation may be either directly present or meta-present on the method.")); + var testClass = WithoutTestMethodOrderTestCase.class; + assertThat(discoveryIssues).extracting(DiscoveryIssue::source).extracting(Optional::orElseThrow) // + .containsExactlyInAnyOrder(MethodSource.from(testClass.getDeclaredMethod("test1")), + MethodSource.from(testClass.getDeclaredMethod("test2")), + MethodSource.from(testClass.getDeclaredMethod("test3"))); + } + // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class BaseTestCase { @Test @@ -349,7 +419,7 @@ } - @SuppressWarnings("unused") + @SuppressWarnings({ "unused", "JUnitMalformedDeclaration" }) @TestMethodOrder(MethodName.class) static class MethodNameTestCase extends BaseTestCase { @@ -402,7 +472,7 @@ } } - @SuppressWarnings({ "deprecation", "unused" }) + @SuppressWarnings({ "deprecation", "unused", "JUnitMalformedDeclaration" }) @TestMethodOrder(org.junit.jupiter.api.MethodOrderer.Alphanumeric.class) static class AlphanumericTestCase extends BaseTestCase { @@ -455,6 +525,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(MethodOrderer.DisplayName.class) static class DisplayNameTestCase { @@ -527,6 +598,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(OrderAnnotation.class) static class OrderAnnotationTestCase { @@ -590,10 +662,15 @@ static class OuterTestCase { @Nested - class NestedOrderAnnotationTestCase extends OrderAnnotationTestCase { + class InnerTestCase { + + @Nested + class NestedOrderAnnotationTestCase extends OrderAnnotationTestCase { + } } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(Random.class) static class RandomTestCase { @@ -626,6 +703,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(MisbehavingByAdding.class) static class MisbehavingByAddingTestCase { @@ -635,14 +713,33 @@ } @Test + void test2() { + } + + @Test void test1() { } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @TestMethodOrder(MisbehavingByImpersonating.class) + static class MisbehavingByImpersonatingTestCase { + + @BeforeEach + void trackInvocations(TestInfo testInfo) { + callSequence.add(testInfo.getDisplayName()); + } @Test void test2() { } + + @Test + void test1() { + } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(MisbehavingByRemoving.class) static class MisbehavingByRemovingTestCase { @@ -656,6 +753,10 @@ } @Test + void test4() { + } + + @Test void test2() { } @@ -692,6 +793,7 @@ @Override public void orderMethods(MethodOrdererContext context) { + context.getMethodDescriptors().sort(comparing(MethodDescriptor::getDisplayName)); context.getMethodDescriptors().add(mockMethodDescriptor()); context.getMethodDescriptors().add(mockMethodDescriptor()); } @@ -703,15 +805,72 @@ } + static class MisbehavingByImpersonating implements MethodOrderer { + + @Override + public void orderMethods(MethodOrdererContext context) { + context.getMethodDescriptors().sort(comparing(MethodDescriptor::getDisplayName)); + MethodDescriptor method1 = context.getMethodDescriptors().get(0); + MethodDescriptor method2 = context.getMethodDescriptors().get(1); + + context.getMethodDescriptors().set(0, createMethodDescriptorImpersonator(method1)); + context.getMethodDescriptors().set(1, createMethodDescriptorImpersonator(method2)); + } + + @SuppressWarnings("unchecked") + static T createMethodDescriptorImpersonator(MethodDescriptor method) { + MethodDescriptor stub = new MethodDescriptor() { + @Override + public Method getMethod() { + return null; + } + + @Override + public String getDisplayName() { + return null; + } + + @Override + public boolean isAnnotated(Class annotationType) { + return false; + } + + @Override + public Optional findAnnotation(Class annotationType) { + return null; + } + + @Override + public List findRepeatableAnnotations(Class annotationType) { + return null; + } + + @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + @Override + public boolean equals(Object obj) { + return method.equals(obj); + } + + @Override + public int hashCode() { + return method.hashCode(); + } + }; + return (T) stub; + } + } + static class MisbehavingByRemoving implements MethodOrderer { @Override public void orderMethods(MethodOrdererContext context) { - context.getMethodDescriptors().remove(0); - context.getMethodDescriptors().remove(0); + context.getMethodDescriptors().sort(comparing(MethodDescriptor::getDisplayName)); + context.getMethodDescriptors().removeFirst(); + context.getMethodDescriptors().removeFirst(); } } + @SuppressWarnings("JUnitMalformedDeclaration") static class WithoutTestMethodOrderTestCase { @BeforeEach @@ -737,4 +896,7 @@ } + static class ClassTemplateTestCase extends WithoutTestMethodOrderTestCase { + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedProgrammaticExtensionRegistrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedProgrammaticExtensionRegistrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedProgrammaticExtensionRegistrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedProgrammaticExtensionRegistrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -106,7 +106,7 @@ * non-annotated "after" callbacks. * * @since 5.6 - * @see gh-1924 + * @see gh-1924 */ @Test void instanceLevelWithDefaultOrderPlusOneAndDefaultOrder() { @@ -200,6 +200,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") private static class AbstractTestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ParameterResolverTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ParameterResolverTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ParameterResolverTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ParameterResolverTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -243,6 +243,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(CustomTypeParameterResolver.class) static class ConstructorInjectionTestCase { @@ -281,6 +282,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(CustomAnnotationParameterResolver.class) static class AnnotatedParameterConstructorInjectionTestCase { @@ -299,7 +301,7 @@ } @Nested - // See https://github.com/junit-team/junit5/issues/1345 + // See https://github.com/junit-team/junit-framework/issues/1345 class AnnotatedConstructorParameterNestedTestCase { private final TestInfo innerTestInfo; @@ -320,6 +322,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ CustomTypeParameterResolver.class, CustomAnnotationParameterResolver.class }) static class MethodInjectionTestCase { @@ -362,6 +365,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(NullIntegerParameterResolver.class) static class NullMethodInjectionTestCase { @@ -376,6 +380,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(PrimitiveIntegerParameterResolver.class) static class PrimitiveIntegerMethodInjectionTestCase { @@ -385,6 +390,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(PrimitiveArrayParameterResolver.class) static class PrimitiveArrayMethodInjectionTestCase { @@ -394,6 +400,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(NumberParameterResolver.class) static class PotentiallyIncompatibleTypeMethodInjectionTestCase { @@ -417,6 +424,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class BeforeAndAfterMethodInjectionTestCase { @BeforeEach @@ -435,6 +443,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("custom class name") static class BeforeAndAfterAllMethodInjectionTestCase { @@ -453,6 +462,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class ExtendWithOnMethodTestCase { /** @@ -461,8 +471,9 @@ * {@code ExtensionRegistry} as the one used for the corresponding * {@code @Test} method. * - * @see #523 + * @see #523 */ + @SuppressWarnings("JUnitMalformedDeclaration") @BeforeEach @AfterEach void setUpAndTearDown(CustomType customType, @CustomAnnotation String value) { @@ -479,6 +490,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class ParameterizedTypeTestCase { @Test @@ -489,6 +501,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TypeBasedParameterResolverTestCase { @Test @ExtendWith(MapOfListsTypeBasedParameterResolver.class) diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/PreInterruptCallbackTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/PreInterruptCallbackTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/PreInterruptCallbackTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/PreInterruptCallbackTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,259 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.engine.extension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.condition.OS.WINDOWS; +import static org.junit.jupiter.api.parallel.ResourceAccessMode.READ_WRITE; +import static org.junit.jupiter.api.parallel.Resources.SYSTEM_OUT; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.EventConditions.test; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.suppressed; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; + +import org.assertj.core.api.Condition; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.PreInterruptCallback; +import org.junit.jupiter.api.extension.PreInterruptContext; +import org.junit.jupiter.api.parallel.Isolated; +import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.jupiter.engine.Constants; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; +import org.junit.platform.testkit.engine.EngineExecutionResults; +import org.junit.platform.testkit.engine.Events; + +/** + * @since 5.12 + */ +@Isolated +class PreInterruptCallbackTests extends AbstractJupiterTestEngineTests { + + private static final String TC = "test"; + private static final String TIMEOUT_ERROR_MSG = TC + "() timed out after 1 microsecond"; + private static final AtomicBoolean interruptedTest = new AtomicBoolean(); + private static final CompletableFuture testThreadExecutionDone = new CompletableFuture<>(); + private static final AtomicReference interruptedTestThread = new AtomicReference<>(); + private static final AtomicBoolean interruptCallbackShallThrowException = new AtomicBoolean(); + private static final AtomicReference calledPreInterruptContext = new AtomicReference<>(); + + @BeforeEach + void setUp() { + interruptedTest.set(false); + interruptCallbackShallThrowException.set(false); + calledPreInterruptContext.set(null); + } + + @AfterEach + void tearDown() { + calledPreInterruptContext.set(null); + interruptedTestThread.set(null); + } + + @Test + @ResourceLock(value = SYSTEM_OUT, mode = READ_WRITE) + void testCaseWithDefaultInterruptCallbackEnabled() { + PrintStream orgOutStream = System.out; + EngineExecutionResults results; + String output; + try { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + PrintStream outStream = new PrintStream(buffer, false, StandardCharsets.UTF_8); + System.setOut(outStream); + // Use larger timeout to increase likelihood of the test being started when the timeout is reached + var timeout = WINDOWS.isCurrentOs() ? "1 s" : "100 ms"; + results = executeDefaultPreInterruptCallbackTimeoutOnMethodTestCase(timeout, request -> request // + .configurationParameter(Constants.EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME, "true")); + output = buffer.toString(StandardCharsets.UTF_8); + } + finally { + System.setOut(orgOutStream); + } + + assertTestHasTimedOut(results.testEvents(), message(it -> it.startsWith(TC + "() timed out after"))); + assertTrue(interruptedTest.get()); + Thread thread = Thread.currentThread(); + + assertThat(output) // + .containsSubsequence( + "Thread \"%s\" prio=%d Id=%d %s will be interrupted.".formatted(thread.getName(), + thread.getPriority(), thread.threadId(), Thread.State.TIMED_WAITING), // + "java.lang.Thread.sleep", // + "%s.test(PreInterruptCallbackTests.java".formatted( + DefaultPreInterruptCallbackTimeoutOnMethodTestCase.class.getName())); + + assertThat(output) // + .containsSubsequence( // + "junit-jupiter-timeout-watcher", // + "%s.beforeThreadInterrupt".formatted(PreInterruptThreadDumpPrinter.class.getName())); + } + + @Test + void testCaseWithNoInterruptCallbackEnabled() { + Events tests = executeDefaultPreInterruptCallbackTimeoutOnMethodTestCase("1 μs", UnaryOperator.identity()) // + .testEvents(); + assertTestHasTimedOut(tests); + assertTrue(interruptedTest.get()); + } + + private EngineExecutionResults executeDefaultPreInterruptCallbackTimeoutOnMethodTestCase(String timeout, + UnaryOperator configurer) { + return executeTests(request -> configurer.apply(request // + .selectors(selectClass(DefaultPreInterruptCallbackTimeoutOnMethodTestCase.class)) // + .configurationParameter(Constants.DEFAULT_TEST_METHOD_TIMEOUT_PROPERTY_NAME, timeout))); + } + + @Test + void testCaseWithDeclaredInterruptCallbackEnabled() { + Events tests = executeTestsForClass(DefaultPreInterruptCallbackWithExplicitCallbackTestCase.class).testEvents(); + assertTestHasTimedOut(tests); + assertTrue(interruptedTest.get()); + PreInterruptContext preInterruptContext = calledPreInterruptContext.get(); + assertNotNull(preInterruptContext); + assertNotNull(preInterruptContext.getThreadToInterrupt()); + assertEquals(preInterruptContext.getThreadToInterrupt(), interruptedTestThread.get()); + } + + @Test + void testCaseWithDeclaredInterruptCallbackEnabledWithSeparateThread() throws Exception { + Events tests = executeTestsForClass( + DefaultPreInterruptCallbackWithExplicitCallbackWithSeparateThreadTestCase.class).testEvents(); + assertOneFailedTest(tests); + tests.failed().assertEventsMatchExactly( + event(test(TC), finishedWithFailure(instanceOf(TimeoutException.class)))); + + //Wait until the real test thread was interrupted due to executor.shutdown(), otherwise the asserts below will be flaky. + testThreadExecutionDone.get(1, TimeUnit.SECONDS); + + assertTrue(interruptedTest.get()); + PreInterruptContext preInterruptContext = calledPreInterruptContext.get(); + assertNotNull(preInterruptContext); + assertNotNull(preInterruptContext.getThreadToInterrupt()); + assertEquals(preInterruptContext.getThreadToInterrupt(), interruptedTestThread.get()); + } + + @Test + void testCaseWithDeclaredInterruptCallbackThrowsException() { + interruptCallbackShallThrowException.set(true); + Events tests = executeTestsForClass(DefaultPreInterruptCallbackWithExplicitCallbackTestCase.class).testEvents(); + tests.failed().assertEventsMatchExactly(event(test(TC), + finishedWithFailure(instanceOf(TimeoutException.class), message(TIMEOUT_ERROR_MSG), + suppressed(0, instanceOf(InterruptedException.class)), + suppressed(1, instanceOf(IllegalStateException.class))))); + assertTrue(interruptedTest.get()); + PreInterruptContext preInterruptContext = calledPreInterruptContext.get(); + assertNotNull(preInterruptContext); + assertNotNull(preInterruptContext.getThreadToInterrupt()); + assertEquals(preInterruptContext.getThreadToInterrupt(), interruptedTestThread.get()); + } + + private static void assertTestHasTimedOut(Events tests) { + assertTestHasTimedOut(tests, message(TIMEOUT_ERROR_MSG)); + } + + private static void assertTestHasTimedOut(Events tests, Condition messageCondition) { + assertOneFailedTest(tests); + tests.failed().assertEventsMatchExactly( + event(test(TC), finishedWithFailure(instanceOf(TimeoutException.class), messageCondition, // + suppressed(0, instanceOf(InterruptedException.class))// + ))); + } + + private static void assertOneFailedTest(Events tests) { + tests.assertStatistics(stats -> stats.started(1).succeeded(0).failed(1)); + } + + static class TestPreInterruptCallback implements PreInterruptCallback { + + @Override + public void beforeThreadInterrupt(PreInterruptContext preInterruptContext, ExtensionContext extensionContext) { + assertNotNull(extensionContext); + + calledPreInterruptContext.set(preInterruptContext); + if (interruptCallbackShallThrowException.get()) { + throw new IllegalStateException("Test-Ex"); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class DefaultPreInterruptCallbackTimeoutOnMethodTestCase { + @Test + void test() throws InterruptedException { + try { + Thread.sleep(5_000); + } + catch (InterruptedException ex) { + interruptedTest.set(true); + interruptedTestThread.set(Thread.currentThread()); + throw ex; + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(TestPreInterruptCallback.class) + static class DefaultPreInterruptCallbackWithExplicitCallbackTestCase { + @Test + @Timeout(value = 1, unit = TimeUnit.MICROSECONDS) + void test() throws InterruptedException { + try { + Thread.sleep(1000); + } + catch (InterruptedException ex) { + interruptedTest.set(true); + interruptedTestThread.set(Thread.currentThread()); + throw ex; + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(TestPreInterruptCallback.class) + static class DefaultPreInterruptCallbackWithExplicitCallbackWithSeparateThreadTestCase { + @Test + @Timeout(value = 200, unit = TimeUnit.MILLISECONDS, threadMode = Timeout.ThreadMode.SEPARATE_THREAD) + void test() throws InterruptedException { + try { + Thread.sleep(2000); + } + catch (InterruptedException ex) { + interruptedTest.set(true); + interruptedTestThread.set(Thread.currentThread()); + throw ex; + } + finally { + testThreadExecutionDone.complete(null); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,7 +16,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedFields; +import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible; import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; @@ -47,7 +48,6 @@ import org.junit.jupiter.engine.JupiterTestEngine; import org.junit.jupiter.engine.execution.injection.sample.LongParameterResolver; import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.testkit.engine.EngineExecutionResults; @@ -299,6 +299,7 @@ assertEquals("Outlook good", wisdom, useCase); } + @SuppressWarnings("JUnitMalformedDeclaration") static class InstanceLevelExtensionRegistrationTestCase { @RegisterExtension @@ -321,6 +322,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExtensionInjector.class) static class InstanceLevelExtensionRegistrationWithInjectedExtensionTestCase { @@ -344,6 +346,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @TestInstance(PER_CLASS) static class InstanceLevelExtensionRegistrationWithTestInstancePerClassLifecycleTestCase { @@ -377,6 +380,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class ClassLevelExtensionRegistrationTestCase { @RegisterExtension @@ -409,8 +413,10 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class SubClassLevelExtensionRegistrationTestCase extends ClassLevelExtensionRegistrationTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @Test @Override void test(String wisdom) { @@ -446,8 +452,10 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class ExtensionRegistrationFromInterfaceTestCase implements ClassLevelExtensionRegistrationInterface { + @SuppressWarnings("JUnitMalformedDeclaration") @Test void test(String wisdom) { assertWisdom(crystalBall, wisdom, "@Test"); @@ -475,6 +483,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class ClassLevelExtensionRegistrationParentTestCase { @RegisterExtension @@ -500,6 +509,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class InstanceLevelExtensionRegistrationParentTestCase { @RegisterExtension @@ -564,8 +574,10 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class InstanceLevelCustomExtensionApiTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension CustomExtension extension = new CustomExtensionImpl(); @@ -576,8 +588,10 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class ClassLevelCustomExtensionApiTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension static CustomExtension extension = new CustomExtensionImpl(); @@ -588,6 +602,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AbstractTestCase { @Test @@ -598,6 +613,7 @@ static class InstanceLevelExtensionRegistrationWithPrivateFieldTestCase extends AbstractTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension private Extension extension = new Extension() { }; @@ -606,6 +622,7 @@ static class ClassLevelExtensionRegistrationWithPrivateFieldTestCase extends AbstractTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension private static Extension extension = new Extension() { }; @@ -628,6 +645,7 @@ static class InstanceLevelExtensionRegistrationWithNonExtensionFieldValueTestCase extends AbstractTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension Object extension = "not an extension type"; @@ -635,6 +653,7 @@ static class ClassLevelExtensionRegistrationWithNonExtensionFieldValueTestCase extends AbstractTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension static Object extension = "not an extension type"; @@ -704,7 +723,7 @@ @Override public void postProcessTestInstance(Object testInstance, ExtensionContext context) { // @formatter:off - AnnotationUtils.findAnnotatedFields(testInstance.getClass(), RegisterExtension.class, isCrystalBall).stream() + findAnnotatedFields(testInstance.getClass(), RegisterExtension.class, isCrystalBall).stream() .findFirst() .ifPresent(field -> { try { @@ -727,11 +746,13 @@ @Nested class A { + @SuppressWarnings("JUnitMalformedDeclaration") @Test void first(Long n) { assertEquals(42L, n); } + @SuppressWarnings("JUnitMalformedDeclaration") @Test void second(Long n) { assertEquals(42L, n); @@ -742,11 +763,13 @@ @Nested class B { + @SuppressWarnings("JUnitMalformedDeclaration") @Test void first(Long n) { assertEquals(42L, n); } + @SuppressWarnings("JUnitMalformedDeclaration") @Test void second(Long n) { assertEquals(42L, n); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/RepeatedTestTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/RepeatedTestTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/RepeatedTestTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/RepeatedTestTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,12 +12,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.engine.Constants.DEFAULT_PARALLEL_EXECUTION_MODE; import static org.junit.jupiter.engine.Constants.PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME; import static org.junit.jupiter.engine.Constants.PARALLEL_CONFIG_STRATEGY_PROPERTY_NAME; import static org.junit.jupiter.engine.Constants.PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.launcher.LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.testkit.engine.EventConditions.container; import static org.junit.platform.testkit.engine.EventConditions.displayName; @@ -43,7 +46,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.testkit.engine.Events; @@ -61,10 +65,13 @@ assertThat(testInfo.getDisplayName()).isEqualTo("repetition 1 of 1"); } - @RepeatedTest(1) - @DisplayName(" \t ") - void customDisplayNameWithBlankName(TestInfo testInfo) { - assertThat(testInfo.getDisplayName()).isEqualTo("repetition 1 of 1"); + @Test + void customDisplayNameWithBlankName() { + executeTests(request -> request // + .selectors(selectClass(BlankDisplayNameTestCase.class)) // + .configurationParameter(CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, Severity.ERROR.name())) // + .testEvents() // + .assertStatistics(stats -> stats.started(1).succeeded(1)); } @RepeatedTest(value = 1, name = "{displayName}") @@ -120,6 +127,11 @@ assertEquals(42, fortyTwo); } + // Can be injected into test class constructors if the test class only has @RepeatedTest methods + public LifecycleMethodTests(RepetitionInfo repetitionInfo) { + assertNotNull(repetitionInfo); + } + @BeforeEach @AfterEach void beforeAndAfterEach(TestInfo testInfo, RepetitionInfo repetitionInfo) { @@ -285,7 +297,7 @@ void failureThresholdWithConcurrentExecution() { Class testClass = TestCase.class; String methodName = "failureThresholdWithConcurrentExecution"; - Method method = ReflectionUtils.findMethod(testClass, methodName).get(); + Method method = ReflectionSupport.findMethod(testClass, methodName).get(); LauncherDiscoveryRequest request = request()// .selectors(selectMethod(testClass, method))// .configurationParameter(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME, "true")// @@ -313,7 +325,7 @@ private Events executeTest(String methodName) { Class testClass = TestCase.class; - Method method = ReflectionUtils.findMethod(testClass, methodName).get(); + Method method = ReflectionSupport.findMethod(testClass, methodName).get(); return executeTests(selectMethod(testClass, method)).allEvents(); } @@ -331,10 +343,12 @@ void testWithBlankPattern() { } + @SuppressWarnings("JUnitMalformedDeclaration") @RepeatedTest(-99) void negativeRepeatCount() { } + @SuppressWarnings("JUnitMalformedDeclaration") @RepeatedTest(0) void zeroRepeatCount() { } @@ -398,4 +412,13 @@ } + static class BlankDisplayNameTestCase { + + @RepeatedTest(1) + @DisplayName(" \t ") + void test(TestInfo testInfo) { + assertThat(testInfo.getDisplayName()).isEqualTo("repetition 1 of 1"); + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SameThreadTimeoutInvocationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -34,7 +34,8 @@ var exception = assertThrows(TimeoutException.class, () -> withExecutor(executor -> { var delegate = new EventuallyInterruptibleInvocation(); var duration = new TimeoutDuration(1, NANOSECONDS); - var timeoutInvocation = new SameThreadTimeoutInvocation<>(delegate, duration, executor, () -> "execution"); + var timeoutInvocation = new SameThreadTimeoutInvocation<>(delegate, duration, executor, () -> "execution", + PreInterruptCallbackInvocation.NOOP); timeoutInvocation.proceed(); })); assertFalse(Thread.currentThread().isInterrupted()); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/SeparateThreadTimeoutInvocationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -25,6 +25,7 @@ import org.junit.jupiter.api.extension.InvocationInterceptor.Invocation; import org.junit.jupiter.engine.execution.NamespaceAwareStore; import org.junit.jupiter.engine.extension.TimeoutInvocationFactory.TimeoutInvocationParameters; +import org.junit.platform.engine.support.store.Namespace; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; /** @@ -71,9 +72,11 @@ private static SeparateThreadTimeoutInvocation aSeparateThreadInvocation(Invocation invocation) { var namespace = ExtensionContext.Namespace.create(SeparateThreadTimeoutInvocationTests.class); - var store = new NamespaceAwareStore(new NamespacedHierarchicalStore<>(null), namespace); + var store = new NamespaceAwareStore(new NamespacedHierarchicalStore<>(null), + Namespace.create(namespace.getParts())); var parameters = new TimeoutInvocationParameters<>(invocation, - new TimeoutDuration(PREEMPTIVE_TIMEOUT_MILLIS, MILLISECONDS), () -> "method()"); + new TimeoutDuration(PREEMPTIVE_TIMEOUT_MILLIS, MILLISECONDS), () -> "method()", + PreInterruptCallbackInvocation.NOOP); return (SeparateThreadTimeoutInvocation) new TimeoutInvocationFactory(store) // .create(ThreadMode.SEPARATE_THREAD, parameters); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ServiceLoaderExtension.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ServiceLoaderExtension.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ServiceLoaderExtension.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ServiceLoaderExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static java.nio.file.Files.deleteIfExists; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.condition.OS.WINDOWS; import static org.junit.jupiter.api.io.CleanupMode.ALWAYS; import static org.junit.jupiter.api.io.CleanupMode.NEVER; import static org.junit.jupiter.api.io.CleanupMode.ON_SUCCESS; @@ -21,17 +22,23 @@ import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.logging.Level; +import java.util.logging.LogRecord; -import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.launcher.LauncherDiscoveryRequest; /** @@ -53,6 +60,7 @@ private static Path alwaysFieldDir; private static Path onSuccessFailingFieldDir; private static Path onSuccessPassingFieldDir; + private static Path onSuccessPassingParameterDir; /** * Ensure the cleanup mode defaults to ALWAYS for fields. @@ -145,6 +153,14 @@ assertThat(onSuccessFailingFieldDir).exists(); } + @Test + void cleanupModeOnSuccessFailingThenPassingField() { + executeTests(selectClass(OnSuccessFailingFieldCase.class), selectClass(OnSuccessPassingFieldCase.class)); + + assertThat(onSuccessFailingFieldDir).exists(); + assertThat(onSuccessPassingFieldDir).doesNotExist(); + } + /** * Ensure that ON_SUCCESS cleanup modes are obeyed for static fields when tests are failing. *

    @@ -167,21 +183,20 @@ */ @Test void cleanupModeOnSuccessFailingStaticFieldWithNesting() { - LauncherDiscoveryRequest request = request()// - .selectors(selectClass(OnSuccessFailingStaticFieldWithNestingCase.class))// - .build(); - executeTests(request); + executeTestsForClass(OnSuccessFailingStaticFieldWithNestingCase.class); assertThat(onSuccessFailingFieldDir).exists(); + assertThat(onSuccessPassingParameterDir).doesNotExist(); } - @AfterAll - static void afterAll() throws IOException { + @AfterEach + void deleteTempDirs() throws IOException { deleteIfNotNullAndExists(defaultFieldDir); deleteIfNotNullAndExists(neverFieldDir); deleteIfNotNullAndExists(alwaysFieldDir); deleteIfNotNullAndExists(onSuccessFailingFieldDir); deleteIfNotNullAndExists(onSuccessPassingFieldDir); + deleteIfNotNullAndExists(onSuccessPassingParameterDir); } static void deleteIfNotNullAndExists(Path dir) throws IOException { @@ -192,6 +207,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class DefaultFieldCase { @TempDir @@ -203,6 +219,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class NeverFieldCase { @TempDir(cleanup = NEVER) @@ -214,6 +231,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class AlwaysFieldCase { @TempDir(cleanup = ALWAYS) @@ -225,6 +243,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class OnSuccessPassingFieldCase { @TempDir(cleanup = ON_SUCCESS) @@ -236,6 +255,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class OnSuccessFailingFieldCase { @TempDir(cleanup = ON_SUCCESS) @@ -248,6 +268,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) static class OnSuccessFailingStaticFieldCase { @@ -273,13 +294,21 @@ static Path onSuccessFailingFieldDir; @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class NestedTestCase { @Test - void test() { + @Order(1) + void failingTest() { TempDirFieldTests.onSuccessFailingFieldDir = onSuccessFailingFieldDir; fail(); } + + @Test + @Order(2) + void passingTest(@TempDir(cleanup = ON_SUCCESS) Path tempDir) { + TempDirFieldTests.onSuccessPassingParameterDir = tempDir; + } } } @@ -387,8 +416,16 @@ assertThat(onSuccessFailingParameterDir).exists(); } - @AfterAll - static void afterAll() throws IOException { + @Test + void cleanupModeOnSuccessFailingThenPassingParameter() { + executeTestsForClass(OnSuccessFailingThenPassingParameterCase.class); + + assertThat(onSuccessFailingParameterDir).exists(); + assertThat(onSuccessPassingParameterDir).doesNotExist(); + } + + @AfterEach + void deleteTempDirs() throws IOException { TempDirFieldTests.deleteIfNotNullAndExists(defaultParameterDir); TempDirFieldTests.deleteIfNotNullAndExists(neverParameterDir); TempDirFieldTests.deleteIfNotNullAndExists(alwaysParameterDir); @@ -398,6 +435,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class DefaultParameterCase { @Test @@ -406,6 +444,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class NeverParameterCase { @Test @@ -414,6 +453,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class AlwaysParameterCase { @Test @@ -422,6 +462,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class OnSuccessPassingParameterCase { @Test @@ -430,6 +471,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class OnSuccessFailingParameterCase { @Test @@ -439,6 +481,82 @@ } } + @SuppressWarnings({ "JUnitMalformedDeclaration", "NewClassNamingConvention" }) + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + static class OnSuccessFailingThenPassingParameterCase { + + @Test + @Order(1) + void testOnSuccessFailingParameter(@TempDir(cleanup = ON_SUCCESS) Path onSuccessFailingParameterDir) { + TempDirParameterTests.onSuccessFailingParameterDir = onSuccessFailingParameterDir; + fail(); + } + + @Test + @Order(2) + void testOnSuccessPassingParameter(@TempDir(cleanup = ON_SUCCESS) Path onSuccessPassingParameterDir) { + TempDirParameterTests.onSuccessPassingParameterDir = onSuccessPassingParameterDir; + } + } + + } + + @Nested + @EnabledOnOs(WINDOWS) + class WindowsTests { + + @Test + void deletesBrokenJunctions(@TempDir Path dir) throws Exception { + var test = Files.createDirectory(dir.resolve("test")); + createWindowsJunction(dir.resolve("link"), test); + // The error might also occur without the source folder being deleted + // but it depends on the order that the TempDir cleanup does its work, + // so the following line forces the error to occur always + Files.delete(test); + } + + @Test + void doesNotFollowJunctions(@TempDir Path tempDir, @TrackLogRecords LogRecordListener listener) + throws IOException { + var outsideDir = Files.createDirectory(tempDir.resolve("outside")); + var testFile = Files.writeString(outsideDir.resolve("test.txt"), "test"); + + JunctionTestCase.target = outsideDir; + try { + executeTestsForClass(JunctionTestCase.class).testEvents() // + .assertStatistics(stats -> stats.started(1).succeeded(1)); + } + finally { + JunctionTestCase.target = null; + } + + assertThat(outsideDir).exists(); + assertThat(testFile).exists(); + assertThat(listener.stream(Level.WARNING)) // + .map(LogRecord::getMessage) // + .anyMatch(m -> m.matches( + "Deleting link from location inside of temp dir \\(.+\\) to location outside of temp dir \\(.+\\) but not the target file/directory")); + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class JunctionTestCase { + public static Path target; + + @Test + void createJunctionToTarget(@TempDir Path dir) throws Exception { + var link = createWindowsJunction(dir.resolve("link"), target); + try (var files = Files.list(link)) { + files.forEach(it -> System.out.println("- " + it)); + } + } + } + + private static Path createWindowsJunction(Path link, Path target) throws Exception { + // This creates a Windows "junction" which you can't do with Java code + String[] command = { "cmd.exe", "/c", "mklink", "/j", link.toString(), target.toString() }; + Runtime.getRuntime().exec(command).waitFor(); + return link; + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryMetaAnnotationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryMetaAnnotationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryMetaAnnotationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryMetaAnnotationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -44,6 +44,7 @@ .assertStatistics(stats -> stats.started(1).succeeded(1)); } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnFieldTestCase { @CustomTempDir @@ -56,6 +57,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnParameterTestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -96,6 +96,7 @@ BaseSharedTempDirParameterInjectionTestCase.tempDir = null; BaseSeparateTempDirsFieldInjectionTestCase.tempDirs.clear(); BaseSeparateTempDirsParameterInjectionTestCase.tempDirs.clear(); + BaseConstructorInjectionTestCase.tempDirs.clear(); } @Test @@ -217,6 +218,17 @@ AnnotationOnBeforeAllMethodParameterWithTestInstancePerClassTestCase.class); } + @Test + @DisplayName("when @TempDir is used on constructor parameter with @TestInstance(PER_CLASS)") + @Order(25) + void resolvesSharedTempDirWhenAnnotationIsUsedOnConstructorWithTestInstancePerClass() { + var results = executeTestsForClass(SharedTempDirsConstructorInjectionPerClassTestCase.class); + + results.testEvents().assertStatistics(stats -> stats.started(2).failed(0).succeeded(2)); + assertThat(BaseConstructorInjectionTestCase.tempDirs.getFirst()).doesNotExist(); + assertThat(BaseConstructorInjectionTestCase.tempDirs.getLast()).doesNotExist(); + } + private void assertSharedTempDirForFieldInjection( Class testClass) { @@ -296,6 +308,17 @@ assertThat(AnnotationOnAfterAllMethodParameterTestCase.secondTempDir).isNotNull().doesNotExist(); } + @Test + @DisplayName("when @TempDir is used on constructor parameter") + @Order(32) + void resolvesSeparateTempDirsWhenAnnotationIsUsedOnConstructorWithTestInstancePerMethod() { + var results = executeTestsForClass(SeparateTempDirsConstructorInjectionPerMethodTestCase.class); + + results.testEvents().assertStatistics(stats -> stats.started(2).failed(0).succeeded(2)); + assertThat(BaseConstructorInjectionTestCase.tempDirs.getFirst()).doesNotExist(); + assertThat(BaseConstructorInjectionTestCase.tempDirs.getLast()).doesNotExist(); + } + } @Nested @@ -371,26 +394,6 @@ } @Test - @DisplayName("when @TempDir is used on constructor parameter") - @Order(30) - void doesNotSupportTempDirAnnotationOnConstructorParameter() { - var results = executeTestsForClass(AnnotationOnConstructorParameterTestCase.class); - - assertSingleFailedTest(results, ParameterResolutionException.class, - "@TempDir is not supported on constructor parameters. Please use field injection instead."); - } - - @Test - @DisplayName("when @TempDir is used on constructor parameter with @TestInstance(PER_CLASS)") - @Order(31) - void doesNotSupportTempDirAnnotationOnConstructorParameterWithTestInstancePerClass() { - var results = executeTestsForClass(AnnotationOnConstructorParameterWithTestInstancePerClassTestCase.class); - - assertSingleFailedContainer(results, ParameterResolutionException.class, - "@TempDir is not supported on constructor parameters. Please use field injection instead."); - } - - @Test @DisplayName("when non-default @TempDir factory is set") @Order(32) void doesNotSupportNonDefaultTempDirFactory() { @@ -510,6 +513,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class BaseSharedTempDirFieldInjectionTestCase { static Path staticTempDir; @@ -610,6 +614,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnPrivateInstanceFieldTestCase { @SuppressWarnings("unused") @@ -623,6 +628,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnPrivateStaticFieldTestCase { @SuppressWarnings("unused") @@ -636,6 +642,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnStaticFieldWithUnsupportedTypeTestCase { @SuppressWarnings("unused") @@ -648,6 +655,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnInstanceFieldWithUnsupportedTypeTestCase { @SuppressWarnings("unused") @@ -660,6 +668,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class BaseSharedTempDirParameterInjectionTestCase { static Path tempDir; @@ -693,28 +702,79 @@ } - static class AnnotationOnConstructorParameterTestCase { + @SuppressWarnings("JUnitMalformedDeclaration") + static class BaseConstructorInjectionTestCase { - AnnotationOnConstructorParameterTestCase(@SuppressWarnings("unused") @TempDir Path tempDir) { - // never called + static final Deque tempDirs = new LinkedList<>(); + + private final Path tempDir; + + BaseConstructorInjectionTestCase(Path tempDir) { + this.tempDir = tempDir; } @Test - void test() { - // never called + void test1(@TempDir Path tempDir, TestInfo testInfo) throws Exception { + check(tempDir); + writeFile(tempDir, testInfo); + } + + @Test + void test2(TestInfo testInfo, @TempDir Path tempDir) throws Exception { + check(tempDir); + writeFile(tempDir, testInfo); + } + + @AfterEach + void afterEach(@TempDir Path tempDir) { + check(tempDir); + } + + void check(Path tempDir) { + assertThat(tempDirs.getLast())// + .isNotNull()// + .isSameAs(tempDir)// + .isSameAs(this.tempDir); + assertTrue(Files.exists(tempDir)); + } + + } + + static class SeparateTempDirsConstructorInjectionPerMethodTestCase extends BaseConstructorInjectionTestCase { + + SeparateTempDirsConstructorInjectionPerMethodTestCase(@TempDir Path tempDir) { + super(tempDir); } + @BeforeEach + void beforeEach(@TempDir Path tempDir) { + for (Path dir : tempDirs) { + assertThat(dir).doesNotExist(); + } + assertThat(tempDirs).doesNotContain(tempDir); + tempDirs.add(tempDir); + check(tempDir); + } } @TestInstance(PER_CLASS) - static class AnnotationOnConstructorParameterWithTestInstancePerClassTestCase - extends AnnotationOnConstructorParameterTestCase { + static class SharedTempDirsConstructorInjectionPerClassTestCase extends BaseConstructorInjectionTestCase { - AnnotationOnConstructorParameterWithTestInstancePerClassTestCase(@TempDir Path tempDir) { + SharedTempDirsConstructorInjectionPerClassTestCase(@TempDir Path tempDir) { super(tempDir); } + + @BeforeEach + void beforeEach(@TempDir Path tempDir) { + for (Path dir : tempDirs) { + assertThat(dir).isSameAs(tempDir).exists(); + } + tempDirs.add(tempDir); + check(tempDir); + } } + @SuppressWarnings("JUnitMalformedDeclaration") static class NonDefaultFactoryTestCase { @Test @@ -733,6 +793,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class StandardDefaultFactoryTestCase { @Test @@ -742,6 +803,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class CustomDefaultFactoryTestCase { @Test @@ -751,6 +813,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class CustomDefaultFactoryNotReturningDirectoryTestCase { @Test @@ -782,6 +845,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnAfterAllMethodParameterTestCase { static Path firstTempDir = null; @@ -802,6 +866,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class BaseSeparateTempDirsFieldInjectionTestCase { static final Deque tempDirs = new LinkedList<>(); @@ -855,6 +920,7 @@ extends SeparateTempDirsWhenUsedOnForEachLifecycleMethodsFieldInjectionTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") static class BaseSeparateTempDirsParameterInjectionTestCase { static final Deque tempDirs = new LinkedList<>(); @@ -901,6 +967,7 @@ extends SeparateTempDirsWhenUsedOnForEachLifecycleMethodsParameterInjectionTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") static class InvalidTestCase { @Test @@ -909,6 +976,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class FileInjectionTestCase { @TempDir @@ -937,6 +1005,7 @@ } // https://github.com/junit-team/junit5/issues/1748 + @SuppressWarnings("JUnitMalformedDeclaration") static class TempDirectoryDoesNotPreventConstructorParameterResolutionTestCase { TempDirectoryDoesNotPreventConstructorParameterResolutionTestCase(TestInfo testInfo) { @@ -950,6 +1019,7 @@ } // https://github.com/junit-team/junit5/issues/1801 + @SuppressWarnings("JUnitMalformedDeclaration") static class UserTempDirectoryDeletionDoesNotCauseFailureTestCase { @Test @@ -961,6 +1031,7 @@ } // https://github.com/junit-team/junit5/issues/2046 + @SuppressWarnings("JUnitMalformedDeclaration") static class NonWritableFileDoesNotCauseFailureTestCase { @Test @@ -975,6 +1046,7 @@ } // https://github.com/junit-team/junit5/issues/2171 + @SuppressWarnings("JUnitMalformedDeclaration") static class ReadOnlyFileInReadOnlyDirDoesNotCauseFailureTestCase { @Test @@ -988,6 +1060,7 @@ } // https://github.com/junit-team/junit5/issues/2171 + @SuppressWarnings("JUnitMalformedDeclaration") static class ReadOnlyFileInDirInReadOnlyDirDoesNotCauseFailureTestCase { @Test @@ -1012,7 +1085,7 @@ } // https://github.com/junit-team/junit5/issues/2609 - @SuppressWarnings("ResultOfMethodCallIgnored") + @SuppressWarnings({ "ResultOfMethodCallIgnored", "JUnitMalformedDeclaration" }) static class NonMintPermissionContentInTempDirectoryDoesNotCauseFailureTestCase { @Test @@ -1391,6 +1464,7 @@ } // https://github.com/junit-team/junit5/issues/2079 + @SuppressWarnings("JUnitMalformedDeclaration") static class TempDirUsageInsideNestedClassesTestCase { @TempDir @@ -1423,6 +1497,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class StaticTempDirUsageInsideNestedClassTestCase { @TempDir diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,6 +15,7 @@ import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; @@ -22,7 +23,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assumptions.assumeTrue; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; @@ -123,25 +123,37 @@ assertThat(AllPossibleDeclarationLocationsTestCase.tempDirs).hasSize(3); var classTempDirs = AllPossibleDeclarationLocationsTestCase.tempDirs.get("class"); - assertThat(classTempDirs).containsOnlyKeys("staticField1", "staticField2", "beforeAll1", "beforeAll2", - "afterAll1", "afterAll2"); - assertThat(classTempDirs.values()).hasSize(6).doesNotHaveDuplicates(); + assertThat(classTempDirs) // + .containsOnlyKeys("staticField1", "staticField2", "beforeAll1", "beforeAll2", "afterAll1", "afterAll2") // + .values().hasSize(6).doesNotHaveDuplicates().allMatch(Files::notExists); var testATempDirs = AllPossibleDeclarationLocationsTestCase.tempDirs.get("testA"); - assertThat(testATempDirs).containsOnlyKeys("staticField1", "staticField2", "instanceField1", "instanceField2", - "beforeEach1", "beforeEach2", "test1", "test2", "afterEach1", "afterEach2"); - assertThat(testATempDirs.values()).hasSize(10).doesNotHaveDuplicates(); + assertThat(testATempDirs) // + .containsOnlyKeys("staticField1", "staticField2", "instanceFieldSetViaConstructorInjection", + "instanceField1", "instanceField2", "beforeEach1", "beforeEach2", "test1", "test2", "afterEach1", + "afterEach2") // + .values().hasSize(11).doesNotHaveDuplicates().allMatch(Files::notExists); var testBTempDirs = AllPossibleDeclarationLocationsTestCase.tempDirs.get("testB"); - assertThat(testBTempDirs).containsOnlyKeys("staticField1", "staticField2", "instanceField1", "instanceField2", - "beforeEach1", "beforeEach2", "test1", "test2", "afterEach1", "afterEach2"); - assertThat(testBTempDirs.values()).hasSize(10).doesNotHaveDuplicates(); + assertThat(testBTempDirs) // + .containsOnlyKeys("staticField1", "staticField2", "instanceFieldSetViaConstructorInjection", + "instanceField1", "instanceField2", "beforeEach1", "beforeEach2", "test1", "test2", "afterEach1", + "afterEach2") // + .values().hasSize(11).doesNotHaveDuplicates().allMatch(Files::notExists); assertThat(testATempDirs).containsEntry("staticField1", classTempDirs.get("staticField1")); assertThat(testBTempDirs).containsEntry("staticField1", classTempDirs.get("staticField1")); assertThat(testATempDirs).containsEntry("staticField2", classTempDirs.get("staticField2")); assertThat(testBTempDirs).containsEntry("staticField2", classTempDirs.get("staticField2")); + switch (lifecycle) { + case PER_CLASS -> assertThat(testATempDirs) // + .containsEntry("instanceFieldSetViaConstructorInjection", + testBTempDirs.get("instanceFieldSetViaConstructorInjection")); + case PER_METHOD -> assertThat(testATempDirs) // + .doesNotContainEntry("instanceFieldSetViaConstructorInjection", + testBTempDirs.get("instanceFieldSetViaConstructorInjection")); + } assertThat(testATempDirs).doesNotContainEntry("instanceField1", testBTempDirs.get("instanceField1")); assertThat(testATempDirs).doesNotContainEntry("instanceField2", testBTempDirs.get("instanceField2")); assertThat(testATempDirs).doesNotContainEntry("beforeEach1", testBTempDirs.get("beforeEach1")); @@ -153,6 +165,12 @@ } @Test + void supportsConstructorInjectionOnRecords() { + executeTestsForClass(TempDirRecordTestCase.class).testEvents()// + .assertStatistics(stats -> stats.started(1).succeeded(1)); + } + + @Test @DisplayName("does not prevent constructor parameter resolution") void tempDirectoryDoesNotPreventConstructorParameterResolution() { executeTestsForClass(TempDirectoryDoesNotPreventConstructorParameterResolutionTestCase.class).testEvents()// @@ -279,26 +297,6 @@ } @Test - @DisplayName("when @TempDir is used on constructor parameter") - @Order(30) - void doesNotSupportTempDirAnnotationOnConstructorParameter() { - var results = executeTestsForClass(AnnotationOnConstructorParameterTestCase.class); - - assertSingleFailedTest(results, ParameterResolutionException.class, - "@TempDir is not supported on constructor parameters. Please use field injection instead."); - } - - @Test - @DisplayName("when @TempDir is used on constructor parameter with @TestInstance(PER_CLASS)") - @Order(31) - void doesNotSupportTempDirAnnotationOnConstructorParameterWithTestInstancePerClass() { - var results = executeTestsForClass(AnnotationOnConstructorParameterWithTestInstancePerClassTestCase.class); - - assertSingleFailedContainer(results, ParameterResolutionException.class, - "@TempDir is not supported on constructor parameters. Please use field injection instead."); - } - - @Test @DisplayName("when @TempDir factory does not return directory") @Order(32) void doesNotSupportTempDirFactoryNotReturningDirectory() { @@ -524,6 +522,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnPrivateInstanceFieldTestCase { @SuppressWarnings("unused") @@ -537,6 +536,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnPrivateStaticFieldTestCase { @SuppressWarnings("unused") @@ -550,6 +550,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnStaticFieldWithUnsupportedTypeTestCase { @SuppressWarnings("unused") @@ -562,6 +563,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class AnnotationOnInstanceFieldWithUnsupportedTypeTestCase { @SuppressWarnings("unused") @@ -574,28 +576,7 @@ } - static class AnnotationOnConstructorParameterTestCase { - - AnnotationOnConstructorParameterTestCase(@SuppressWarnings("unused") @TempDir Path tempDir) { - // never called - } - - @Test - void test() { - // never called - } - - } - - @TestInstance(PER_CLASS) - static class AnnotationOnConstructorParameterWithTestInstancePerClassTestCase - extends AnnotationOnConstructorParameterTestCase { - - AnnotationOnConstructorParameterWithTestInstancePerClassTestCase(@TempDir Path tempDir) { - super(tempDir); - } - } - + @SuppressWarnings("JUnitMalformedDeclaration") static class InvalidTestCase { @Test @@ -629,7 +610,8 @@ } - // https://github.com/junit-team/junit5/issues/1748 + // https://github.com/junit-team/junit-framework/issues/1748 + @SuppressWarnings("JUnitMalformedDeclaration") static class TempDirectoryDoesNotPreventConstructorParameterResolutionTestCase { @TempDir @@ -646,7 +628,8 @@ } - // https://github.com/junit-team/junit5/issues/1801 + // https://github.com/junit-team/junit-framework/issues/1801 + @SuppressWarnings("JUnitMalformedDeclaration") static class UserTempDirectoryDeletionDoesNotCauseFailureTestCase { @Test @@ -657,7 +640,8 @@ } - // https://github.com/junit-team/junit5/issues/2046 + // https://github.com/junit-team/junit-framework/issues/2046 + @SuppressWarnings("JUnitMalformedDeclaration") static class NonWritableFileDoesNotCauseFailureTestCase { @Test @@ -671,7 +655,8 @@ } - // https://github.com/junit-team/junit5/issues/2171 + // https://github.com/junit-team/junit-framework/issues/2171 + @SuppressWarnings("JUnitMalformedDeclaration") static class ReadOnlyFileInReadOnlyDirDoesNotCauseFailureTestCase { @Test @@ -684,7 +669,8 @@ } - // https://github.com/junit-team/junit5/issues/2171 + // https://github.com/junit-team/junit-framework/issues/2171 + @SuppressWarnings("JUnitMalformedDeclaration") static class ReadOnlyFileInDirInReadOnlyDirDoesNotCauseFailureTestCase { @Test @@ -699,8 +685,8 @@ } - // https://github.com/junit-team/junit5/issues/2609 - @SuppressWarnings("ResultOfMethodCallIgnored") + // https://github.com/junit-team/junit-framework/issues/2609 + @SuppressWarnings({ "ResultOfMethodCallIgnored", "JUnitMalformedDeclaration" }) static class NonMintPermissionContentInTempDirectoryDoesNotCauseFailureTestCase { @Test @@ -778,7 +764,7 @@ } } - // https://github.com/junit-team/junit5/issues/2609 + // https://github.com/junit-team/junit-framework/issues/2609 @SuppressWarnings("ResultOfMethodCallIgnored") static class NonMintTempDirectoryPermissionsDoNotCauseFailureTestCase { @@ -1078,7 +1064,8 @@ } } - // https://github.com/junit-team/junit5/issues/2079 + // https://github.com/junit-team/junit-framework/issues/2079 + @SuppressWarnings("JUnitMalformedDeclaration") static class TempDirUsageInsideNestedClassesTestCase { @TempDir @@ -1111,6 +1098,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class StaticTempDirUsageInsideNestedClassTestCase { @TempDir @@ -1137,6 +1125,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("class") static class AllPossibleDeclarationLocationsTestCase { @@ -1148,6 +1137,8 @@ @TempDir static Path staticField2; + final Path instanceFieldSetViaConstructorInjection; + @TempDir Path instanceField1; @@ -1162,6 +1153,11 @@ "beforeAll1", param1, // "beforeAll2", param2 // )); + assertAllTempDirsExist(testInfo); + } + + AllPossibleDeclarationLocationsTestCase(@TempDir Path tempDir) { + this.instanceFieldSetViaConstructorInjection = tempDir; } @BeforeEach @@ -1169,11 +1165,13 @@ getTempDirs(testInfo).putAll(Map.of( // "staticField1", staticField1, // "staticField2", staticField2, // + "instanceFieldSetViaConstructorInjection", instanceFieldSetViaConstructorInjection, // "instanceField1", instanceField1, // "instanceField2", instanceField2, // "beforeEach1", param1, // "beforeEach2", param2 // )); + assertAllTempDirsExist(testInfo); } @Test @@ -1183,6 +1181,7 @@ "test1", param1, // "test2", param2 // )); + assertAllTempDirsExist(testInfo); } @Test @@ -1192,6 +1191,7 @@ "test1", param1, // "test2", param2 // )); + assertAllTempDirsExist(testInfo); } @AfterEach @@ -1200,6 +1200,7 @@ "afterEach1", param1, // "afterEach2", param2 // )); + assertAllTempDirsExist(testInfo); } @AfterAll @@ -1208,11 +1209,16 @@ "afterAll1", param1, // "afterAll2", param2 // )); + assertAllTempDirsExist(testInfo); } private static Map getTempDirs(TestInfo testInfo) { return tempDirs.computeIfAbsent(testInfo.getDisplayName(), __ -> new LinkedHashMap<>()); } + + private static void assertAllTempDirsExist(TestInfo testInfo) { + assertAll(getTempDirs(testInfo).values().stream().map(tempDir -> () -> assertTrue(Files.exists(tempDir)))); + } } static class UndeletableTestCase { @@ -1241,6 +1247,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class UndeletableDirectoryTestCase extends UndeletableTestCase { @Test void test() throws Exception { @@ -1248,6 +1255,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class UndeletableFileTestCase extends UndeletableTestCase { @Test void test() throws Exception { @@ -1255,6 +1263,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryWithTestMethodNameAsPrefixTestCase { @Test @@ -1274,7 +1283,8 @@ } - // https://github.com/junit-team/junit5/issues/2088 + // https://github.com/junit-team/junit-framework/issues/2088 + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryWithCustomParentDirectoryTestCase { @Test @@ -1300,6 +1310,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryWithMemoryFileSystemTestCase { @Test @@ -1328,6 +1339,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryWithJimfsTestCase { @Test @@ -1356,6 +1368,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryWithAnnotatedElementNameAsPrefixTestCase { @TempDir(factory = Factory.class) @@ -1383,6 +1396,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryWithCustomMetaAnnotationTestCase { @TempDirForField @@ -1429,6 +1443,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryNotReturningDirectoryTestCase { @Test @@ -1446,6 +1461,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryReturningNonDefaultFileSystemPathForFileAnnotatedElementTestCase { @Test @@ -1471,6 +1487,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class StandardDefaultFactoryTestCase { @Test @@ -1482,6 +1499,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class CustomDefaultFactoryTestCase { @Test @@ -1493,6 +1511,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class CustomDefaultFactoryWithStandardDeclarationTestCase { @Test @@ -1504,6 +1523,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class CustomDefaultFactoryNotReturningDirectoryTestCase { @Test @@ -1513,4 +1533,12 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") + record TempDirRecordTestCase(@TempDir Path tempDir) { + @Test + void shouldExists() { + assertTrue(Files.exists(tempDir)); + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPreconditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPreconditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPreconditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPreconditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -87,6 +87,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class ParameterTypeTestCase { @Test @@ -98,6 +99,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class FinalStaticFieldTestCase { static final @TempDir Path path = Paths.get("."); @@ -107,6 +109,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class FinalInstanceFieldTestCase { final @TempDir Path path = Paths.get("."); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestExecutionExceptionHandlerTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestExecutionExceptionHandlerTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestExecutionExceptionHandlerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestExecutionExceptionHandlerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -133,6 +133,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class ATestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInfoParameterResolverTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInfoParameterResolverTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInfoParameterResolverTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInfoParameterResolverTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.launcher.LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME; import java.util.Arrays; import java.util.List; @@ -26,6 +28,8 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.platform.engine.DiscoveryIssue.Severity; /** * Integration tests for {@link TestInfoParameterResolver}. @@ -33,10 +37,15 @@ * @since 5.0 */ @Tag("class-tag") -class TestInfoParameterResolverTests { +class TestInfoParameterResolverTests extends AbstractJupiterTestEngineTests { - private static List allDisplayNames = Arrays.asList("defaultDisplayName(TestInfo)", "custom display name", - "getTags(TestInfo)", "customDisplayNameThatIsEmpty(TestInfo)"); + private static final List allDisplayNames = Arrays.asList("defaultDisplayName(TestInfo)", + "custom display name", "getTags(TestInfo)", "customDisplayNameThatIsEmpty()"); + + public TestInfoParameterResolverTests(TestInfo testInfo) { + assertThat(testInfo.getTestClass()).contains(TestInfoParameterResolverTests.class); + assertThat(testInfo.getTestMethod()).isPresent(); + } @Test void defaultDisplayName(TestInfo testInfo) { @@ -49,11 +58,13 @@ assertEquals("custom display name", testInfo.getDisplayName()); } - // TODO Update test to expect an exception once #743 is fixed. @Test - @DisplayName("") - void customDisplayNameThatIsEmpty(TestInfo testInfo) { - assertEquals("customDisplayNameThatIsEmpty(TestInfo)", testInfo.getDisplayName()); + void customDisplayNameThatIsEmpty() { + executeTests(request -> request // + .selectors(selectClass(BlankDisplayNameTestCase.class)) // + .configurationParameter(CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, Severity.ERROR.name())) // + .testEvents() // + .assertStatistics(stats -> stats.started(1).succeeded(1)); } @Test @@ -83,4 +94,14 @@ assertEquals(TestInfoParameterResolverTests.class.getSimpleName(), testInfo.getDisplayName()); } + @SuppressWarnings("JUnitMalformedDeclaration") + static class BlankDisplayNameTestCase { + + @Test + @DisplayName("") + void test(TestInfo testInfo) { + assertEquals("test(TestInfo)", testInfo.getDisplayName()); + } + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstanceFactoryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope.TEST_METHOD; import static org.junit.platform.commons.util.ClassUtils.nullSafeToString; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.testkit.engine.EventConditions.container; import static org.junit.platform.testkit.engine.EventConditions.engine; import static org.junit.platform.testkit.engine.EventConditions.event; @@ -43,8 +46,9 @@ import org.junit.jupiter.api.extension.TestInstanceFactoryContext; import org.junit.jupiter.api.extension.TestInstantiationException; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.jupiter.engine.Constants; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.test.TestClassLoader; -import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.testkit.engine.EngineExecutionResults; /** @@ -276,7 +280,8 @@ // @formatter:off assertThat(callSequence).containsExactly( "FooInstanceFactory instantiated: ParentTestCase", - "parentTest" + "parentTest", + "close ParentTestCase" ); // @formatter:on } @@ -305,8 +310,10 @@ assertThat(callSequence).containsExactly( "FooInstanceFactory instantiated: InheritedFactoryTestCase", "parentTest", + "close InheritedFactoryTestCase", "FooInstanceFactory instantiated: InheritedFactoryTestCase", - "childTest" + "childTest", + "close InheritedFactoryTestCase" ); // @formatter:on } @@ -324,17 +331,23 @@ // OuterTestCase "FooInstanceFactory instantiated: OuterTestCase", "outerTest", + "close OuterTestCase", // InnerTestCase "FooInstanceFactory instantiated: OuterTestCase", "FooInstanceFactory instantiated: InnerTestCase", "innerTest1", + "close InnerTestCase", + "close OuterTestCase", // InnerInnerTestCase "FooInstanceFactory instantiated: OuterTestCase", "FooInstanceFactory instantiated: InnerTestCase", "FooInstanceFactory instantiated: InnerInnerTestCase", - "innerTest2" + "innerTest2", + "close InnerInnerTestCase", + "close InnerTestCase", + "close OuterTestCase" ); // @formatter:on } @@ -349,7 +362,8 @@ // @formatter:off assertThat(callSequence).containsExactly( "FooInstanceFactory instantiated: FactoryFromInterfaceTestCase", - "test" + "test", + "close FactoryFromInterfaceTestCase" ); // @formatter:on } @@ -386,13 +400,71 @@ "test1", "@BeforeEach", "test2", - "@AfterAll" + "@AfterAll", + "close PerClassLifecycleTestCase" + ); + // @formatter:on + } + + @Test + void instanceFactoryWithLegacyContext() { + EngineExecutionResults executionResults = executeTestsForClass(LegacyContextTestCase.class); + + assertEquals(3, executionResults.testEvents().started().count(), "# tests started"); + assertEquals(3, executionResults.testEvents().succeeded().count(), "# tests succeeded"); + + // @formatter:off + assertThat(callSequence).containsExactly( + "LegacyInstanceFactory instantiated: LegacyContextTestCase", + "outerTest", + "LegacyInstanceFactory instantiated: LegacyContextTestCase", + "LegacyInstanceFactory instantiated: InnerTestCase", + "innerTest1", + "LegacyInstanceFactory instantiated: LegacyContextTestCase", + "LegacyInstanceFactory instantiated: InnerTestCase", + "innerTest2", + "close InnerTestCase", + "close InnerTestCase", + "close LegacyContextTestCase", + "close LegacyContextTestCase", + "close LegacyContextTestCase" + ); + // @formatter:on + } + + @Test + void instanceFactoryWithLegacyContextAndChangedDefaultScope() { + var executionResults = executeTests(request() // + .selectors(selectClass(LegacyContextTestCase.class)) // + .configurationParameter( + Constants.DEFAULT_TEST_CLASS_INSTANCE_CONSTRUCTION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME, + TEST_METHOD.name())); + + assertEquals(3, executionResults.testEvents().started().count(), "# tests started"); + assertEquals(3, executionResults.testEvents().succeeded().count(), "# tests succeeded"); + + // @formatter:off + assertThat(callSequence).containsExactly( + "LegacyInstanceFactory instantiated: LegacyContextTestCase", + "outerTest", + "close LegacyContextTestCase", + "LegacyInstanceFactory instantiated: LegacyContextTestCase", + "LegacyInstanceFactory instantiated: InnerTestCase", + "innerTest1", + "close InnerTestCase", + "close LegacyContextTestCase", + "LegacyInstanceFactory instantiated: LegacyContextTestCase", + "LegacyInstanceFactory instantiated: InnerTestCase", + "innerTest2", + "close InnerTestCase", + "close LegacyContextTestCase" ); // @formatter:on } // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooInstanceFactory.class, BarInstanceFactory.class }) static class MultipleFactoriesRegisteredOnSingleTestCase { @@ -402,6 +474,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(NullTestInstanceFactory.class) static class NullTestInstanceFactoryTestCase { @@ -415,6 +488,7 @@ static class PerClassLifecycleNullTestInstanceFactoryTestCase extends NullTestInstanceFactoryTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BogusTestInstanceFactory.class) static class BogusTestInstanceFactoryTestCase { @@ -428,6 +502,7 @@ static class PerClassLifecycleBogusTestInstanceFactoryTestCase extends BogusTestInstanceFactoryTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExplosiveTestInstanceFactory.class) static class ExplosiveTestInstanceFactoryTestCase { @@ -450,6 +525,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(MultipleConstructorsTestInstanceFactory.class) static class MultipleConstructorsTestCase { @@ -469,6 +545,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooInstanceFactory.class) static class ParentTestCase { @@ -478,6 +555,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class InheritedFactoryTestCase extends ParentTestCase { @Test @@ -486,6 +564,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BarInstanceFactory.class) static class MultipleFactoriesRegisteredWithinClassHierarchyTestCase extends ParentTestCase { @@ -495,6 +574,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooInstanceFactory.class) static class OuterTestCase { @@ -522,6 +602,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooInstanceFactory.class) static class MultipleFactoriesRegisteredWithinNestedClassStructureTestCase { @@ -543,6 +624,7 @@ interface TestInterface { } + @SuppressWarnings("JUnitMalformedDeclaration") static class FactoryFromInterfaceTestCase implements TestInterface { @Test @@ -551,6 +633,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class LambdaFactoryTestCase { private final String text; @@ -573,6 +656,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooInstanceFactory.class) @TestInstance(PER_CLASS) static class PerClassLifecycleTestCase { @@ -609,6 +693,31 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(LegacyInstanceFactory.class) + static class LegacyContextTestCase { + + @Test + void outerTest() { + callSequence.add("outerTest"); + } + + @Nested + class InnerTestCase { + + @Test + void innerTest1() { + callSequence.add("innerTest1"); + } + + @Test + void innerTest2() { + callSequence.add("innerTest2"); + } + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ProxyTestInstanceFactory.class) @TestInstance(PER_CLASS) static class ProxiedTestCase { @@ -633,18 +742,32 @@ Class testClass = factoryContext.getTestClass(); instantiated(getClass(), testClass); + extensionContext.getStore(ExtensionContext.Namespace.create(this)).put(new Object(), + (AutoCloseable) () -> callSequence.add("close " + testClass.getSimpleName())); + if (factoryContext.getOuterInstance().isPresent()) { - return ReflectionUtils.newInstance(testClass, factoryContext.getOuterInstance().get()); + return ReflectionSupport.newInstance(testClass, factoryContext.getOuterInstance().get()); } // else - return ReflectionUtils.newInstance(testClass); + return ReflectionSupport.newInstance(testClass); } } private static class FooInstanceFactory extends AbstractTestInstanceFactory { + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } } private static class BarInstanceFactory extends AbstractTestInstanceFactory { + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } + } + + private static class LegacyInstanceFactory extends AbstractTestInstanceFactory { } /** @@ -698,7 +821,7 @@ try (var testClassLoader = TestClassLoader.forClasses(testClass)) { // Load test class from different class loader Class clazz = testClassLoader.loadClass(className); - return ReflectionUtils.newInstance(clazz); + return ReflectionSupport.newInstance(clazz); } catch (Exception ex) { throw new RuntimeException("Failed to load class [" + className + "]", ex); @@ -706,8 +829,8 @@ } } - private static boolean instantiated(Class factoryClass, Class testClass) { - return callSequence.add(factoryClass.getSimpleName() + " instantiated: " + testClass.getSimpleName()); + private static void instantiated(Class factoryClass, Class testClass) { + callSequence.add(factoryClass.getSimpleName() + " instantiated: " + testClass.getSimpleName()); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorAndPreDestroyCallbackTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorAndPreDestroyCallbackTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorAndPreDestroyCallbackTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorAndPreDestroyCallbackTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -120,6 +120,7 @@ // ------------------------------------------------------------------------- // Must NOT be private; otherwise, the @Test method gets discovered but never executed. + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith({ FooTestInstanceCallbacks.class, BarTestInstanceCallbacks.class }) static class TopLevelTestCase { @@ -130,6 +131,7 @@ } // Must NOT be private; otherwise, the @Test method gets discovered but never executed. + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(BazTestInstanceCallbacks.class) static class SecondLevelTestCase extends TopLevelTestCase { @@ -140,6 +142,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(QuuxTestInstanceCallbacks.class) static class ThirdLevelTestCase extends SecondLevelTestCase { @@ -150,6 +153,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExceptionThrowingTestInstancePreDestroyCallback.class) static class ExceptionInTestInstancePreDestroyCallbackTestCase { @@ -159,6 +163,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExceptionThrowingTestInstancePostProcessor.class) static class ExceptionInTestInstancePostProcessorTestCase { @@ -168,6 +173,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooTestInstanceCallbacks.class) static class ExceptionInTestClassConstructorTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePostProcessorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,9 +12,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope.TEST_METHOD; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -46,18 +49,28 @@ assertThat(callSequence).containsExactly( // OuterTestCase - "fooPostProcessTestInstance:OuterTestCase", + "foo:OuterTestCase", + "legacy:OuterTestCase", "beforeOuterMethod", "testOuter", + "close:foo:OuterTestCase", // InnerTestCase - "fooPostProcessTestInstance:OuterTestCase", - "fooPostProcessTestInstance:InnerTestCase", - "barPostProcessTestInstance:InnerTestCase", + "foo:OuterTestCase", + "legacy:OuterTestCase", + "foo:InnerTestCase", + "legacy:InnerTestCase", + "bar:InnerTestCase", "beforeOuterMethod", "beforeInnerMethod", - "testInner" + "testInner", + "close:bar:InnerTestCase", + "close:foo:InnerTestCase", + "close:foo:OuterTestCase", + "close:legacy:InnerTestCase", + "close:legacy:OuterTestCase", + "close:legacy:OuterTestCase" ); // @formatter:on } @@ -65,22 +78,34 @@ @Test void testSpecificTestInstancePostProcessorIsCalled() { executeTestsForClass(TestCaseWithTestSpecificTestInstancePostProcessor.class).testEvents()// - .assertStatistics(stats -> stats.started(1).succeeded(1)); + .assertStatistics(stats -> stats.started(2).succeeded(2)); + // @formatter:off assertThat(callSequence).containsExactly( - "fooPostProcessTestInstance:TestCaseWithTestSpecificTestInstancePostProcessor", "beforeEachMethod", "test"); + "foo:TestCaseWithTestSpecificTestInstancePostProcessor", + "legacy:TestCaseWithTestSpecificTestInstancePostProcessor", + "beforeEachMethod", + "test1", + "close:foo:TestCaseWithTestSpecificTestInstancePostProcessor", + "beforeEachMethod", + "test2", + "close:legacy:TestCaseWithTestSpecificTestInstancePostProcessor" + ); + // @formatter:on } // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooInstancePostProcessor.class) + @ExtendWith(LegacyInstancePostProcessor.class) static class OuterTestCase implements Named { - private String outerName; + private final Map outerNames = new HashMap<>(); @Override - public void setName(String name) { - this.outerName = name; + public void setName(String source, String name) { + outerNames.put(source, name); } @BeforeEach @@ -90,7 +115,9 @@ @Test void testOuter() { - assertEquals("foo:" + OuterTestCase.class.getSimpleName(), outerName); + assertEquals( + Map.of("foo", OuterTestCase.class.getSimpleName(), "legacy", OuterTestCase.class.getSimpleName()), + outerNames); callSequence.add("testOuter"); } @@ -98,11 +125,11 @@ @ExtendWith(BarInstancePostProcessor.class) class InnerTestCase implements Named { - private String innerName; + private final Map innerNames = new HashMap<>(); @Override - public void setName(String name) { - this.innerName = name; + public void setName(String source, String name) { + innerNames.put(source, name); } @BeforeEach @@ -112,21 +139,25 @@ @Test void testInner() { - assertEquals("foo:" + OuterTestCase.class.getSimpleName(), outerName); - assertEquals("bar:" + InnerTestCase.class.getSimpleName(), innerName); + assertEquals( + Map.of("foo", InnerTestCase.class.getSimpleName(), "legacy", OuterTestCase.class.getSimpleName()), + outerNames); + assertEquals(Map.of("foo", InnerTestCase.class.getSimpleName(), "bar", + InnerTestCase.class.getSimpleName(), "legacy", InnerTestCase.class.getSimpleName()), innerNames); callSequence.add("testInner"); } } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithTestSpecificTestInstancePostProcessor implements Named { - private String name; + private final Map names = new HashMap<>(); @Override - public void setName(String name) { - this.name = name; + public void setName(String source, String name) { + names.put(source, name); } @BeforeEach @@ -135,38 +166,70 @@ } @ExtendWith(FooInstancePostProcessor.class) + @ExtendWith(LegacyInstancePostProcessor.class) + @Test + void test1() { + callSequence.add("test1"); + assertEquals(Map.of("foo", getClass().getSimpleName(), "legacy", getClass().getSimpleName()), names); + } + @Test - void test() { - callSequence.add("test"); - assertEquals("foo:" + getClass().getSimpleName(), name); + void test2() { + callSequence.add("test2"); + assertEquals(Map.of(), names); } } - static class FooInstancePostProcessor implements TestInstancePostProcessor { + static abstract class AbstractInstancePostProcessor implements TestInstancePostProcessor { + private final String name; + + AbstractInstancePostProcessor(String name) { + this.name = name; + } @Override public void postProcessTestInstance(Object testInstance, ExtensionContext context) { if (testInstance instanceof Named) { - ((Named) testInstance).setName("foo:" + context.getRequiredTestClass().getSimpleName()); + ((Named) testInstance).setName(name, context.getRequiredTestClass().getSimpleName()); } - callSequence.add("fooPostProcessTestInstance:" + testInstance.getClass().getSimpleName()); + String instanceType = testInstance.getClass().getSimpleName(); + callSequence.add(name + ":" + instanceType); + context.getStore(ExtensionContext.Namespace.create(this)).put(new Object(), + (AutoCloseable) () -> callSequence.add("close:" + name + ":" + instanceType)); } } - static class BarInstancePostProcessor implements TestInstancePostProcessor { + static class FooInstancePostProcessor extends AbstractInstancePostProcessor { + FooInstancePostProcessor() { + super("foo"); + } @Override - public void postProcessTestInstance(Object testInstance, ExtensionContext context) { - if (testInstance instanceof Named) { - ((Named) testInstance).setName("bar:" + context.getRequiredTestClass().getSimpleName()); - } - callSequence.add("barPostProcessTestInstance:" + testInstance.getClass().getSimpleName()); + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } + } + + static class BarInstancePostProcessor extends AbstractInstancePostProcessor { + BarInstancePostProcessor() { + super("bar"); + } + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } + } + + static class LegacyInstancePostProcessor extends AbstractInstancePostProcessor { + LegacyInstancePostProcessor() { + super("legacy"); } } private interface Named { - void setName(String name); + void setName(String source, String name); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreConstructCallbackTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreConstructCallbackTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreConstructCallbackTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreConstructCallbackTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.jupiter.engine.extension; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope.TEST_METHOD; import java.util.ArrayList; import java.util.List; @@ -59,12 +60,14 @@ "beforeEach", "test1", "afterEach", + "close: name=foo, testClass=InstancePreConstructTestCase", "PreConstructCallback: name=foo, testClass=InstancePreConstructTestCase, outerInstance: null", "constructor", "beforeEach", "test2", "afterEach", + "close: name=foo, testClass=InstancePreConstructTestCase", "afterAll" ); @@ -86,6 +89,7 @@ "beforeEach", "test1", "afterEach", + "close: name=foo, testClass=FactoryPreConstructTestCase", "PreConstructCallback: name=foo, testClass=FactoryPreConstructTestCase, outerInstance: null", "testInstanceFactory", @@ -93,6 +97,7 @@ "beforeEach", "test2", "afterEach", + "close: name=foo, testClass=FactoryPreConstructTestCase", "afterAll" ); @@ -113,12 +118,14 @@ "beforeEach", "outerTest1", "afterEach", + "close: name=foo, testClass=PreConstructInNestedTestCase", "PreConstructCallback: name=foo, testClass=PreConstructInNestedTestCase, outerInstance: null", "constructor", "beforeEach", "outerTest2", "afterEach", + "close: name=foo, testClass=PreConstructInNestedTestCase", "PreConstructCallback: name=foo, testClass=PreConstructInNestedTestCase, outerInstance: null", "constructor", @@ -133,6 +140,11 @@ "afterEachInner", "afterEach", + "close: name=baz, testClass=InnerTestCase", + "close: name=bar, testClass=InnerTestCase", + "close: name=foo, testClass=InnerTestCase", + "close: name=foo, testClass=PreConstructInNestedTestCase", + "afterAll" ); // @formatter:on @@ -150,6 +162,7 @@ "beforeEach", "test1", "afterEach", + "close: name=foo, testClass=PreConstructOnMethod", "constructor", "beforeEach", @@ -172,7 +185,57 @@ "beforeEach", "test1", "beforeEach", - "test2" + "test2", + "close: name=bar, testClass=PreConstructWithClassLifecycle", + "close: name=foo, testClass=PreConstructWithClassLifecycle" + ); + // @formatter:on + } + + @Test + void legacyPreConstruct() { + executeTestsForClass(LegacyPreConstructTestCase.class).testEvents()// + .assertStatistics(stats -> stats.started(3).succeeded(3)); + + // @formatter:off + assertThat(callSequence).containsExactly( + "beforeAll", + + "PreConstructCallback: name=foo, testClass=LegacyPreConstructTestCase, outerInstance: null", + "PreConstructCallback: name=legacy, testClass=LegacyPreConstructTestCase, outerInstance: null", + "constructor", + "beforeEach", + "outerTest1", + "afterEach", + "close: name=foo, testClass=LegacyPreConstructTestCase", + + "PreConstructCallback: name=foo, testClass=LegacyPreConstructTestCase, outerInstance: null", + "PreConstructCallback: name=legacy, testClass=LegacyPreConstructTestCase, outerInstance: null", + "constructor", + "beforeEach", + "outerTest2", + "afterEach", + "close: name=foo, testClass=LegacyPreConstructTestCase", + + "PreConstructCallback: name=foo, testClass=LegacyPreConstructTestCase, outerInstance: null", + "PreConstructCallback: name=legacy, testClass=LegacyPreConstructTestCase, outerInstance: null", + "constructor", + "PreConstructCallback: name=foo, testClass=InnerTestCase, outerInstance: LegacyPreConstructTestCase", + "PreConstructCallback: name=legacy, testClass=InnerTestCase, outerInstance: LegacyPreConstructTestCase", + "constructorInner", + "beforeEach", + "beforeEachInner", + "innerTest1", + "afterEachInner", + "afterEach", + "close: name=foo, testClass=InnerTestCase", + "close: name=foo, testClass=LegacyPreConstructTestCase", + + "close: name=legacy, testClass=InnerTestCase", + "afterAll", + "close: name=legacy, testClass=LegacyPreConstructTestCase", + "close: name=legacy, testClass=LegacyPreConstructTestCase", + "close: name=legacy, testClass=LegacyPreConstructTestCase" ); // @formatter:on } @@ -183,6 +246,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(InstancePreConstructCallbackRecordingFoo.class) static class InstancePreConstructTestCase extends CallSequenceRecordingTestCase { @@ -221,6 +285,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(InstancePreConstructCallbackRecordingFoo.class) static class FactoryPreConstructTestCase extends CallSequenceRecordingTestCase { @@ -265,6 +330,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(InstancePreConstructCallbackRecordingFoo.class) static class PreConstructInNestedTestCase extends CallSequenceRecordingTestCase { @@ -342,6 +408,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class PreConstructOnMethod extends CallSequenceRecordingTestCase { PreConstructOnMethod() { record("constructor"); @@ -369,6 +436,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(InstancePreConstructCallbackRecordingFoo.class) @ExtendWith(InstancePreConstructCallbackRecordingBar.class) @@ -393,6 +461,74 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(InstancePreConstructCallbackRecordingFoo.class) + @ExtendWith(InstancePreConstructCallbackRecordingLegacy.class) + static class LegacyPreConstructTestCase extends CallSequenceRecordingTestCase { + + LegacyPreConstructTestCase() { + record("constructor"); + } + + @BeforeAll + static void beforeAll() { + record("beforeAll"); + } + + @BeforeEach + void beforeEach() { + record("beforeEach"); + } + + @Test + void outerTest1() { + record("outerTest1"); + } + + @Test + void outerTest2() { + record("outerTest2"); + } + + @AfterEach + void afterEach() { + record("afterEach"); + } + + @AfterAll + static void afterAll() { + record("afterAll"); + } + + @Override + public String toString() { + return "LegacyPreConstructTestCase"; + } + + @Nested + class InnerTestCase extends CallSequenceRecordingTestCase { + + InnerTestCase() { + record("constructorInner"); + } + + @BeforeEach + void beforeEachInner() { + record("beforeEachInner"); + } + + @Test + void innerTest1() { + record("innerTest1"); + } + + @AfterEach + void afterEachInner() { + record("afterEachInner"); + } + } + } + static abstract class AbstractTestInstancePreConstructCallback implements TestInstancePreConstructCallback { private final String name; @@ -404,10 +540,20 @@ public void preConstructTestInstance(TestInstanceFactoryContext factoryContext, ExtensionContext context) { assertThat(context.getTestInstance()).isNotPresent(); assertThat(context.getTestClass()).isPresent(); - assertThat(factoryContext.getTestClass()).isSameAs(context.getTestClass().get()); - callSequence.add( - "PreConstructCallback: name=" + name + ", testClass=" + factoryContext.getTestClass().getSimpleName() - + ", outerInstance: " + factoryContext.getOuterInstance().orElse(null)); + if (name.equals("legacy")) { + assertThat(factoryContext.getTestClass()).isSameAs(context.getTestClass().get()); + } + else if (context.getTestInstanceLifecycle().orElse(null) != TestInstance.Lifecycle.PER_CLASS) { + assertThat(context.getTestMethod()).isPresent(); + } + else { + assertThat(context.getTestMethod()).isEmpty(); + } + String testClass = factoryContext.getTestClass().getSimpleName(); + callSequence.add("PreConstructCallback: name=" + name + ", testClass=" + testClass + ", outerInstance: " + + factoryContext.getOuterInstance().orElse(null)); + context.getStore(ExtensionContext.Namespace.create(this)).put(new Object(), + (AutoCloseable) () -> callSequence.add("close: name=" + name + ", testClass=" + testClass)); } } @@ -415,18 +561,39 @@ InstancePreConstructCallbackRecordingFoo() { super("foo"); } + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } } static class InstancePreConstructCallbackRecordingBar extends AbstractTestInstancePreConstructCallback { InstancePreConstructCallbackRecordingBar() { super("bar"); } + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } } static class InstancePreConstructCallbackRecordingBaz extends AbstractTestInstancePreConstructCallback { InstancePreConstructCallbackRecordingBaz() { super("baz"); } + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return TEST_METHOD; + } + } + + static class InstancePreConstructCallbackRecordingLegacy extends AbstractTestInstancePreConstructCallback { + InstancePreConstructCallbackRecordingLegacy() { + super("legacy"); + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -104,6 +104,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(FooInstancePreDestroyCallback.class) static class OuterTestCase extends Destroyable { @@ -136,6 +137,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithTestSpecificTestInstancePreDestroyCallback extends Destroyable { @BeforeEach @@ -151,6 +153,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestInstance(PER_CLASS) @ExtendWith(FooInstancePreDestroyCallback.class) @ExtendWith(BarInstancePreDestroyCallback.class) diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackUtilityMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackUtilityMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackUtilityMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestInstancePreDestroyCallbackUtilityMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -35,7 +35,7 @@ @ValueSource(classes = { PerMethodLifecycleOnAllLevels.class, PerMethodWithinPerClassLifecycle.class, PerClassWithinPerMethodLifecycle.class, PerClassLifecycleOnAllLevels.class }) void destroysWhatWasPostProcessed(Class testClass) { - executeTestsForClass(testClass).allEvents().debug() // + executeTestsForClass(testClass).allEvents() // .assertStatistics(stats -> stats.reportingEntryPublished(4)) // .assertEventsMatchLooselyInOrder( // reportEntry(Map.of("post-process", testClass.getSimpleName())), diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestReporter; import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; /** * @since 5.0 @@ -49,7 +49,7 @@ } private Parameter findParameterOfMethod(String methodName, Class... parameterTypes) { - Method method = ReflectionUtils.findMethod(Sample.class, methodName, parameterTypes).get(); + Method method = ReflectionSupport.findMethod(Sample.class, methodName, parameterTypes).get(); return method.getParameters()[0]; } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -355,6 +355,7 @@ TestWatcher watcher = new TrackingTestWatcher(); } + @SuppressWarnings("JUnitMalformedDeclaration") static class MethodLevelTestWatcherTestCase extends AbstractDisabledMethodsTestCase { @Override @@ -431,7 +432,7 @@ /** * {@link TestWatcher} that retrieves data from the {@link ExtensionContext.Store}. - * @see #3944 + * @see #3944 */ static class DataRetrievingTestWatcher implements BeforeTestExecutionCallback, TestWatcher { @@ -456,6 +457,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(DataRetrievingTestWatcher.class) static class DataRetrievingTestWatcherTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationParserTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationParserTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationParserTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationParserTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutDurationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactoryTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactoryTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactoryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExceptionFactoryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -503,6 +503,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TimeoutAnnotatedTestMethodTestCase { @Test @Timeout(value = 10, unit = MILLISECONDS) @@ -524,6 +525,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TimeoutAnnotatedBeforeAllMethodTestCase { @BeforeAll @Timeout(value = 10, unit = MILLISECONDS) @@ -537,6 +539,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TimeoutAnnotatedBeforeEachMethodTestCase { @BeforeEach @Timeout(value = 10, unit = MILLISECONDS) @@ -550,6 +553,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TimeoutAnnotatedAfterEachMethodTestCase { @Test void testMethod() { @@ -563,6 +567,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TimeoutAnnotatedAfterAllMethodTestCase { @Test void testMethod() { @@ -601,6 +606,7 @@ static class InheritedTimeoutAnnotatedClassTestCase extends TimeoutAnnotatedClassTestCase { } + @SuppressWarnings("JUnitMalformedDeclaration") static class MethodWithoutInterruptedExceptionTestCase { @Test @Timeout(value = 1, unit = MILLISECONDS) @@ -609,6 +615,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class PlainTestCase { public static String slowMethod; @@ -656,6 +663,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class UnrecoverableExceptionTestCase { @Test @Timeout(value = 1, unit = NANOSECONDS) @@ -665,6 +673,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @Timeout(10) static class NonTimeoutExceedingTestCase { @Test @@ -705,6 +714,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class IllegalTimeoutDurationTestCase { @Test @@ -714,6 +724,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class TimeoutExceedingWithInferredThreadModeTestCase { @Test @Timeout(value = 10, unit = MILLISECONDS) @@ -722,6 +733,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TimeoutExceedingSeparateThreadTestCase { @Test @Timeout(value = 100, unit = MILLISECONDS, threadMode = SEPARATE_THREAD) @@ -730,6 +742,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class NonTimeoutExceedingSeparateThreadTestCase { @Test @Timeout(value = 100, unit = MILLISECONDS, threadMode = SEPARATE_THREAD) @@ -737,6 +750,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class UnrecoverableExceptionInSeparateThreadTestCase { @Test @Timeout(value = 100, unit = SECONDS, threadMode = SEPARATE_THREAD) @@ -745,6 +759,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class ExceptionInSeparateThreadTestCase { @Test @Timeout(value = 5, unit = SECONDS, threadMode = SEPARATE_THREAD) @@ -753,6 +768,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class FailedAssertionInSeparateThreadTestCase { @Test @Timeout(value = 5, unit = SECONDS, threadMode = SEPARATE_THREAD) @@ -767,6 +783,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @Timeout(value = 100, unit = MILLISECONDS, threadMode = SEPARATE_THREAD) static class TimeoutExceededOnClassLevelTestCase { @Test @@ -775,6 +792,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @Timeout(value = 100, unit = MILLISECONDS, threadMode = SEPARATE_THREAD) static class NonTimeoutExceededOnClassLevelTestCase { @Test @@ -782,6 +800,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(OrderAnnotation.class) static class OneTestStuckForeverAndTheOthersNotTestCase { @@ -805,6 +824,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class MixedSameThreadAndSeparateThreadTestCase { @Test @Timeout(value = 10, unit = MILLISECONDS, threadMode = SEPARATE_THREAD) @@ -825,6 +845,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(OrderAnnotation.class) static class OneTestStuckForeverAndTheOthersInSameThreadNotTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactoryTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactoryTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactoryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/TimeoutInvocationFactoryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,35 +18,46 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout.ThreadMode; +import org.junit.jupiter.api.extension.DisabledInEclipse; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.InvocationInterceptor.Invocation; import org.junit.jupiter.engine.execution.NamespaceAwareStore; import org.junit.jupiter.engine.extension.TimeoutInvocationFactory.SingleThreadExecutorResource; import org.junit.jupiter.engine.extension.TimeoutInvocationFactory.TimeoutInvocationParameters; +import org.junit.platform.engine.support.store.Namespace; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; +// org.mockito.exceptions.base.MockitoException: Unable to initialize @Spy annotated field 'store'. +// Mockito cannot mock this class: class org.junit.jupiter.engine.execution.NamespaceAwareStore. +// You are seeing this disclaimer because Mockito is configured to create inlined mocks. +// Byte Buddy could not instrument all classes within the mock's type hierarchy. +@DisabledInEclipse("Mockito cannot create a spy for NamespaceAwareStore using the inline MockMaker in Eclipse IDE") @DisplayName("TimeoutInvocationFactory") @ExtendWith(MockitoExtension.class) class TimeoutInvocationFactoryTests { @Spy private final Store store = new NamespaceAwareStore(new NamespacedHierarchicalStore<>(null), - ExtensionContext.Namespace.create(TimeoutInvocationFactoryTests.class)); + Namespace.create(TimeoutInvocationFactoryTests.class)); + @Mock private Invocation invocation; + @Mock private TimeoutDuration timeoutDuration; + private TimeoutInvocationFactory timeoutInvocationFactory; + private TimeoutInvocationParameters parameters; @BeforeEach void setUp() { - parameters = new TimeoutInvocationParameters<>(invocation, timeoutDuration, () -> "description"); + parameters = new TimeoutInvocationParameters<>(invocation, timeoutDuration, () -> "description", + PreInterruptCallbackInvocation.NOOP); timeoutInvocationFactory = new TimeoutInvocationFactory(store); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AlwaysDisabledCondition.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AlwaysDisabledCondition.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AlwaysDisabledCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AlwaysDisabledCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AnotherAlwaysDisabledCondition.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AnotherAlwaysDisabledCondition.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AnotherAlwaysDisabledCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/AnotherAlwaysDisabledCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/SystemPropertyCondition.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/SystemPropertyCondition.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/SystemPropertyCondition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/sub/SystemPropertyCondition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,7 @@ package org.junit.jupiter.engine.extension.sub; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/subpackage/SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/subpackage/SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/subpackage/SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/subpackage/SuperClassWithPackagePrivateLifecycleMethodInDifferentPackageTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.TestReporter; /** * @since 5.9 @@ -28,7 +30,8 @@ } @Test - void test() { + void test(TestInfo testInfo, TestReporter reporter) { + reporter.publishEntry("invokedSuper", testInfo.getTestMethod().orElseThrow().toGenericString()); assertThat(this.beforeEachInvoked).isTrue(); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollectorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollectorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/engine/support/OpenTest4JAndJUnit4AwareThrowableCollectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -24,6 +24,7 @@ import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.api.function.Executable; import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.util.ReflectionUtils; /** @@ -42,10 +43,10 @@ // Ensure that our custom ClassLoader actually throws a ClassNotFoundException // when attempting to load the AssumptionViolatedException class. assertThrows(ClassNotFoundException.class, - () -> ReflectionUtils.tryToLoadClass(AssumptionViolatedException.class.getName()).get()); + () -> ReflectionSupport.tryToLoadClass(AssumptionViolatedException.class.getName()).get()); Class clazz = classLoader.loadClass(OpenTest4JAndJUnit4AwareThrowableCollector.class.getName()); - assertNotNull(ReflectionUtils.newInstance(clazz)); + assertNotNull(ReflectionSupport.newInstance(clazz)); // @formatter:off assertThat(listener.stream(Level.FINE).map(LogRecord::getMessage).findFirst().orElse("")) diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/JupiterMigrationSupportTestSuite.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/JupiterMigrationSupportTestSuite.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/JupiterMigrationSupportTestSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/JupiterMigrationSupportTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreAnnotationIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreAnnotationIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreAnnotationIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreAnnotationIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreConditionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreConditionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/conditions/IgnoreConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -106,6 +106,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(IgnoreCondition.class) @Ignore static class IgnoredClassWithDefaultMessageTestCase { @@ -116,6 +117,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(IgnoreCondition.class) @Ignore("Ignored Class") static class IgnoredClassWithCustomMessageTestCase { @@ -126,6 +128,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(IgnoreCondition.class) static class IgnoredMethodsTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/AbstractTestRuleAdapterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/AbstractTestRuleAdapterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/AbstractTestRuleAdapterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/AbstractTestRuleAdapterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupportWithBothRuleTypesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupportWithBothRuleTypesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupportWithBothRuleTypesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupportWithBothRuleTypesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupportTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupportTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupportTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExpectedExceptionSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -76,6 +76,7 @@ return EngineTestKit.execute("junit-jupiter", request().selectors(selectClass(testClass)).build()).testEvents(); } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExpectedExceptionSupport.class) static class ExpectedExceptionTestCase { @@ -107,6 +108,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(ExpectedExceptionSupport.class) static class ExpectedExceptionSupportWithoutExpectedExceptionRuleTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForDifferentDeclaredReturnTypesRulesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForDifferentDeclaredReturnTypesRulesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForDifferentDeclaredReturnTypesRulesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForDifferentDeclaredReturnTypesRulesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMixedMethodAndFieldRulesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMixedMethodAndFieldRulesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMixedMethodAndFieldRulesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMixedMethodAndFieldRulesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -45,11 +45,13 @@ @Rule public ExternalResource fieldRule2 = new MyExternalResource("fieldRule2"); + @SuppressWarnings("JUnitMalformedDeclaration") @Rule ExternalResource methodRule1() { return new MyExternalResource("methodRule1"); } + @SuppressWarnings("JUnitMalformedDeclaration") @Rule ExternalResource methodRule2() { return new MyExternalResource("methodRule2"); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleFieldRulesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleFieldRulesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleFieldRulesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleFieldRulesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleMethodRulesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleMethodRulesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleMethodRulesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForMultipleMethodRulesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForTemporaryFolderFieldTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForTemporaryFolderFieldTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForTemporaryFolderFieldTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportForTemporaryFolderFieldTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportWithInheritanceTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportWithInheritanceTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportWithInheritanceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceSupportWithInheritanceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceWithoutAdapterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceWithoutAdapterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceWithoutAdapterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/ExternalResourceWithoutAdapterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/FailAfterAllHelper.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/FailAfterAllHelper.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/FailAfterAllHelper.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/FailAfterAllHelper.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/LauncherBasedEnableRuleMigrationSupportTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/LauncherBasedEnableRuleMigrationSupportTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/LauncherBasedEnableRuleMigrationSupportTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/LauncherBasedEnableRuleMigrationSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -52,6 +52,7 @@ return EngineTestKit.execute("junit-jupiter", request().selectors(selectClass(testClass)).build()).testEvents(); } + @SuppressWarnings("JUnitMalformedDeclaration") @EnableRuleMigrationSupport static class EnableRuleMigrationSupportWithBothRuleTypesTestCase { @@ -93,6 +94,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(VerifierSupport.class) static class VerifierSupportForErrorCollectorTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/VerifierSupportForMixedMethodAndFieldRulesTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/VerifierSupportForMixedMethodAndFieldRulesTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/VerifierSupportForMixedMethodAndFieldRulesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/VerifierSupportForMixedMethodAndFieldRulesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierFieldTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierFieldTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierFieldTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierFieldTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierMethodTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierMethodTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierMethodTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/migrationsupport/rules/WrongExtendWithForVerifierMethodTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterInfoIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterInfoIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterInfoIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterInfoIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * @since 1.14 + */ +class ParameterInfoIntegrationTests extends AbstractJupiterTestEngineTests { + + @Test + void storesParameterInfoInExtensionContextStoreOnDifferentLevels() { + var results = executeTestsForClass(TestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(7).succeeded(7)); + } + + @ParameterizedClass + @ValueSource(ints = 1) + @ExtendWith(ParameterInfoConsumingExtension.class) + record TestCase(int i) { + + @Nested + @ParameterizedClass + @ValueSource(ints = 2) + class Inner { + + @Parameter + int j; + + @ParameterizedTest + @ValueSource(ints = 3) + void test(int k) { + assertEquals(1, i); + assertEquals(2, j); + assertEquals(3, k); + } + } + } + + private static class ParameterInfoConsumingExtension + implements BeforeClassTemplateInvocationCallback, BeforeEachCallback { + + @Override + public void beforeClassTemplateInvocation(ExtensionContext parameterizedClassInvocationContext) { + if (TestCase.Inner.class.equals(parameterizedClassInvocationContext.getRequiredTestClass())) { + assertParameterInfo(parameterizedClassInvocationContext, "j", 2); + + var nestedParameterizedClassContext = parameterizedClassInvocationContext.getParent().orElseThrow(); + assertParameterInfo(nestedParameterizedClassContext, "i", 1); + + parameterizedClassInvocationContext = nestedParameterizedClassContext.getParent().orElseThrow(); + } + + assertParameterInfo(parameterizedClassInvocationContext, "i", 1); + + var outerParameterizedClassContext = parameterizedClassInvocationContext.getParent().orElseThrow(); + assertNull(ParameterInfo.get(outerParameterizedClassContext)); + } + + @Override + public void beforeEach(ExtensionContext parameterizedTestInvocationContext) { + assertParameterInfo(parameterizedTestInvocationContext, "k", 3); + + var parameterizedTestContext = parameterizedTestInvocationContext.getParent().orElseThrow(); + assertParameterInfo(parameterizedTestContext, "j", 2); + + var nestedParameterizedClassInvocationContext = parameterizedTestContext.getParent().orElseThrow(); + assertParameterInfo(nestedParameterizedClassInvocationContext, "j", 2); + + var nestedParameterizedClassContext = nestedParameterizedClassInvocationContext.getParent().orElseThrow(); + assertParameterInfo(nestedParameterizedClassContext, "i", 1); + + var outerParameterizedClassInvocationContext = nestedParameterizedClassContext.getParent().orElseThrow(); + assertParameterInfo(outerParameterizedClassInvocationContext, "i", 1); + + var outerParameterizedClassContext = outerParameterizedClassInvocationContext.getParent().orElseThrow(); + assertNull(ParameterInfo.get(outerParameterizedClassContext)); + } + + private static void assertParameterInfo(ExtensionContext context, String parameterName, int argumentValue) { + var parameterInfo = ParameterInfo.get(context); + var declaration = parameterInfo.getDeclarations().get(0).orElseThrow(); + assertEquals(parameterName, declaration.getParameterName().orElseThrow()); + assertEquals(int.class, declaration.getParameterType()); + assertEquals(argumentValue, parameterInfo.getArguments().getInteger(0)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedClassIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedClassIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedClassIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedClassIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,2258 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static java.util.Comparator.comparing; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.junit.jupiter.params.ArgumentCountValidationMode.NONE; +import static org.junit.jupiter.params.ArgumentCountValidationMode.STRICT; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENTS_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.DISPLAY_NAME_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.INDEX_PLACEHOLDER; +import static org.junit.jupiter.params.provider.Arguments.argumentSet; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.testkit.engine.EventConditions.container; +import static org.junit.platform.testkit.engine.EventConditions.displayName; +import static org.junit.platform.testkit.engine.EventConditions.dynamicTestRegistered; +import static org.junit.platform.testkit.engine.EventConditions.engine; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.EventConditions.started; +import static org.junit.platform.testkit.engine.EventConditions.test; +import static org.junit.platform.testkit.engine.EventConditions.uniqueId; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.suppressed; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.assertj.core.api.Condition; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Named; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.extension.AnnotatedElementContext; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.TemplateInvocationValidationException; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.jupiter.engine.Constants; +import org.junit.jupiter.engine.descriptor.ClassTemplateInvocationTestDescriptor; +import org.junit.jupiter.params.aggregator.AggregateWith; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.aggregator.ArgumentsAggregationException; +import org.junit.jupiter.params.aggregator.SimpleArgumentsAggregator; +import org.junit.jupiter.params.converter.ArgumentConversionException; +import org.junit.jupiter.params.converter.ArgumentConverter; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.converter.SimpleArgumentConverter; +import org.junit.jupiter.params.converter.TypedArgumentConverter; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.params.provider.CsvFileSource; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.EmptySource; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.FieldSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.params.support.FieldContext; +import org.junit.jupiter.params.support.ParameterDeclarations; +import org.junit.platform.commons.util.StringUtils; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.testkit.engine.EngineExecutionResults; +import org.junit.platform.testkit.engine.Event; +import org.junit.platform.testkit.engine.Events; + +@SuppressWarnings("JUnitMalformedDeclaration") +public class ParameterizedClassIntegrationTests extends AbstractJupiterTestEngineTests { + + @ParameterizedTest + @ValueSource(classes = { ConstructorInjectionTestCase.class, RecordTestCase.class, + RecordWithParameterAnnotationOnComponentTestCase.class, FieldInjectionTestCase.class, + RecordWithBuiltInConverterTestCase.class, RecordWithRegisteredConversionTestCase.class, + FieldInjectionWithRegisteredConversionTestCase.class, RecordWithBuiltInAggregatorTestCase.class, + FieldInjectionWithBuiltInAggregatorTestCase.class, RecordWithCustomAggregatorTestCase.class, + FieldInjectionWithCustomAggregatorTestCase.class }) + void injectsParametersIntoClass(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + String parameterNamePrefix = classTemplateClass.getSimpleName().contains("Aggregator") ? "" : "value="; + + results.allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(classTemplateClass), started()), // + + event(dynamicTestRegistered("#1"), displayName("[1] %s-1".formatted(parameterNamePrefix))), // + event(container("#1"), started()), // + event(dynamicTestRegistered("test1")), // + event(dynamicTestRegistered("test2")), // + event(test("test1"), started()), // + event(test("test1"), finishedSuccessfully()), // + event(test("test2"), started()), // + event(test("test2"), finishedSuccessfully()), // + event(container("#1"), finishedSuccessfully()), // + + event(dynamicTestRegistered("#2"), displayName("[2] %s1".formatted(parameterNamePrefix))), // + event(container("#2"), started()), // + event(dynamicTestRegistered("test1")), // + event(dynamicTestRegistered("test2")), // + event(test("test1"), started()), // + event(test("test1"), finishedWithFailure(message(it -> it.contains("negative")))), // + event(test("test2"), started()), // + event(test("test2"), finishedWithFailure(message(it -> it.contains("negative")))), // + event(container("#2"), finishedSuccessfully()), // + + event(container(classTemplateClass), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + + @ParameterizedTest + @ValueSource(classes = { ArgumentConversionPerInvocationConstructorInjectionTestCase.class, + ArgumentConversionPerInvocationFieldInjectionTestCase.class }) + void argumentConverterIsOnlyCalledOncePerInvocation(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(5).succeeded(5)); + } + + @Nested + class Sources { + + @ParameterizedTest + @ValueSource(classes = { NullAndEmptySourceConstructorInjectionTestCase.class, + NullAndEmptySourceConstructorFieldInjectionTestCase.class }) + void supportsNullAndEmptySource(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("[1] value=null", "[2] value="); + } + + @ParameterizedTest + @ValueSource(classes = { CsvFileSourceConstructorInjectionTestCase.class, + CsvFileSourceFieldInjectionTestCase.class }) + void supportsCsvFileSource(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(10).succeeded(10)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("[1] name=foo, value=1", "[2] name=bar, value=2", "[3] name=baz, value=3", + "[4] name=qux, value=4"); + } + + @ParameterizedTest + @ValueSource(classes = { SingleEnumSourceConstructorInjectionTestCase.class, + SingleEnumSourceFieldInjectionTestCase.class }) + void supportsSingleEnumSource(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("[1] value=FOO"); + } + + @ParameterizedTest + @ValueSource(classes = { RepeatedEnumSourceConstructorInjectionTestCase.class, + RepeatedEnumSourceFieldInjectionTestCase.class }) + void supportsRepeatedEnumSource(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("[1] value=FOO", "[2] value=BAR"); + } + + @ParameterizedTest + @ValueSource(classes = { MethodSourceConstructorInjectionTestCase.class, + MethodSourceFieldInjectionTestCase.class }) + void supportsMethodSource(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("[1] value=foo", "[2] value=bar"); + } + + @Test + void doesNotSupportDerivingMethodName() { + + var results = executeTestsForClass(MethodSourceWithoutMethodNameTestCase.class); + + results.allEvents().failed() // + .assertEventsMatchExactly(finishedWithFailure( + message("You must specify a method name when using @MethodSource with @ParameterizedClass"))); + } + + @ParameterizedTest + @ValueSource(classes = { FieldSourceConstructorInjectionTestCase.class, + FieldSourceFieldInjectionTestCase.class }) + void supportsFieldSource(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("[1] value=foo", "[2] value=bar"); + } + + @Test + void doesNotSupportDerivingFieldName() { + + var results = executeTestsForClass(FieldSourceWithoutFieldNameTestCase.class); + + results.allEvents().failed() // + .assertEventsMatchExactly(finishedWithFailure( + message("You must specify a field name when using @FieldSource with @ParameterizedClass"))); + } + + @ParameterizedTest + @ValueSource(classes = { ArgumentsSourceConstructorInjectionTestCase.class, + ArgumentsSourceFieldInjectionTestCase.class }) + void supportsArgumentsSource(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("[1] value=foo", "[2] value=bar"); + } + + @Test + void failsWhenNoArgumentsSourceIsDeclared() { + var results = executeTestsForClass(NoArgumentSourceTestCase.class); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message( + "Configuration error: You must configure at least one arguments source for this @ParameterizedClass")))); + } + + @Test + void annotationsAreInherited() { + var results = executeTestsForClass(ConcreteInheritanceTestCase.class); + + int numArgumentSets = 13; + var numContainers = numArgumentSets * 3; // once for outer invocation, once for nested class, once for inner invocation + var numTests = numArgumentSets * 2; // once for outer test, once for inner test + results.containerEvents() // + .assertStatistics(stats -> stats.started(numContainers + 2).succeeded(numContainers + 2)); + results.testEvents() // + .assertStatistics(stats -> stats.started(numTests).succeeded(numTests)); + } + } + + @Nested + class AnnotationAttributes { + + @Test + void supportsCustomNamePatterns() { + + var results = executeTestsForClass(CustomNamePatternTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + assertThat(invocationDisplayNames(results)) // + .containsExactly("1 | TesT | 1, foo | set", "2 | TesT | 2, bar | number=2, name=bar"); + } + + @Test + void closesAutoCloseableArguments() { + AutoCloseableArgument.closeCounter = 0; + + var results = executeTestsForClass(AutoCloseableArgumentTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + assertThat(AutoCloseableArgument.closeCounter).isEqualTo(2); + } + + @Test + void doesNotCloseAutoCloseableArgumentsWhenDisabled() { + AutoCloseableArgument.closeCounter = 0; + + var results = executeTestsForClass(AutoCloseableArgumentWithDisabledCleanupTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + assertThat(AutoCloseableArgument.closeCounter).isEqualTo(0); + } + + @Test + void failsOnStrictArgumentCountValidationMode() { + var results = executeTestsForClass(StrictArgumentCountValidationModeTestCase.class); + + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message( + "Configuration error: @ParameterizedClass consumes 1 parameter but there were 2 arguments provided.%nNote: the provided arguments were [foo, unused]".formatted())))); + } + + @ParameterizedTest + @ValueSource(classes = { NoneArgumentCountValidationModeTestCase.class, + DefaultArgumentCountValidationModeTestCase.class }) + void doesNotFailOnNoneOrDefaultArgumentCountValidationMode(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + @Test + void failsOnStrictArgumentCountValidationModeSetViaConfigurationParameter() { + var results = executeTests(request -> request // + .selectors(selectClass(DefaultArgumentCountValidationModeTestCase.class)).configurationParameter( + ArgumentCountValidator.ARGUMENT_COUNT_VALIDATION_KEY, STRICT.name())); + + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message( + "Configuration error: @ParameterizedClass consumes 1 parameter but there were 2 arguments provided.%nNote: the provided arguments were [foo, unused]".formatted())))); + } + + @Test + void failsForSkippedParameters() { + var results = executeTestsForClass(InvalidUnusedParameterIndexesTestCase.class); + + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message( + "2 configuration errors:%n- no field annotated with @Parameter(0) declared%n- no field annotated with @Parameter(2) declared".formatted())))); + } + + @Test + void failsWhenInvocationIsRequiredButNoArgumentSetsAreProvided() { + var results = executeTestsForClass(ForbiddenZeroInvocationsTestCase.class); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, + event(finishedWithFailure(instanceOf(TemplateInvocationValidationException.class), message( + "Configuration error: You must configure at least one set of arguments for this @ParameterizedClass")))); + } + + @Test + void doesNotFailWhenInvocationIsNotRequiredAndNoArgumentSetsAreProvided() { + var results = executeTestsForClass(AllowedZeroInvocationsTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(2).succeeded(2)); + } + } + + @Nested + class Nesting { + + @ParameterizedTest + @ValueSource(classes = { NestedFieldInjectionTestCase.class, NestedConstructorInjectionTestCase.class }) + void supportsNestedParameterizedClass(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.containerEvents().assertStatistics(stats -> stats.started(14).succeeded(14)); + results.testEvents().assertStatistics(stats -> stats.started(8).succeeded(8)); + assertThat(invocationDisplayNames(results)) // + .containsExactly( // + "[1] number=1", "[1] text=foo", "[2] text=bar", // + "[2] number=2", "[1] text=foo", "[2] text=bar" // + ); + assertThat(allReportEntries(results)).map(it -> it.get("value")).containsExactly( + // @formatter:off + "beforeAll: %s".formatted(classTemplateClass.getSimpleName()), + "beforeParameterizedClassInvocation: %s".formatted(classTemplateClass.getSimpleName()), + "beforeAll: InnerTestCase", + "beforeParameterizedClassInvocation: InnerTestCase", + "beforeEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [1] flag=true [InnerTestCase]", + "test(1, foo, true)", + "afterEach: [1] flag=true [InnerTestCase]", + "afterEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [InnerTestCase]", + "test(1, foo, false)", + "afterEach: [2] flag=false [InnerTestCase]", + "afterEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "afterParameterizedClassInvocation: InnerTestCase", + "beforeParameterizedClassInvocation: InnerTestCase", + "beforeEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [1] flag=true [InnerTestCase]", + "test(1, bar, true)", + "afterEach: [1] flag=true [InnerTestCase]", + "afterEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [InnerTestCase]", + "test(1, bar, false)", + "afterEach: [2] flag=false [InnerTestCase]", + "afterEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "afterParameterizedClassInvocation: InnerTestCase", + "afterAll: InnerTestCase", + "afterParameterizedClassInvocation: %s".formatted(classTemplateClass.getSimpleName()), + "beforeParameterizedClassInvocation: %s".formatted(classTemplateClass.getSimpleName()), + "beforeAll: InnerTestCase", + "beforeParameterizedClassInvocation: InnerTestCase", + "beforeEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [1] flag=true [InnerTestCase]", + "test(2, foo, true)", + "afterEach: [1] flag=true [InnerTestCase]", + "afterEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [InnerTestCase]", + "test(2, foo, false)", + "afterEach: [2] flag=false [InnerTestCase]", + "afterEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "afterParameterizedClassInvocation: InnerTestCase", + "beforeParameterizedClassInvocation: InnerTestCase", + "beforeEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [1] flag=true [InnerTestCase]", + "test(2, bar, true)", + "afterEach: [1] flag=true [InnerTestCase]", + "afterEach: [1] flag=true [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "beforeEach: [2] flag=false [InnerTestCase]", + "test(2, bar, false)", + "afterEach: [2] flag=false [InnerTestCase]", + "afterEach: [2] flag=false [%s]".formatted(classTemplateClass.getSimpleName()), + "afterParameterizedClassInvocation: InnerTestCase", + "afterAll: InnerTestCase", + "afterParameterizedClassInvocation: %s".formatted(classTemplateClass.getSimpleName()), + "afterAll: %s".formatted(classTemplateClass.getSimpleName()) + // @formatter:on + ); + } + + @ParameterizedTest + @ValueSource(classes = { ConstructorInjectionWithRegularNestedTestCase.class, + FieldInjectionWithRegularNestedTestCase.class }) + void supportsRegularNestedTestClassesInsideParameterizedClass(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.containerEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + results.testEvents().assertStatistics(stats -> stats.started(2).succeeded(2)); + } + } + + @Nested + class FieldInjection { + + @Test + void supportsMultipleAggregatorFields() { + + var results = executeTestsForClass(MultiAggregatorFieldInjectionTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + } + + @Test + void supportsInjectionOfInheritedFields() { + + var results = executeTestsForClass(InheritedHiddenParameterFieldTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(6).succeeded(6)); + + assertThat(allReportEntries(results)) // + .extracting(it -> tuple(it.get("super.value"), it.get("this.value"))) // + .containsExactly(tuple("foo", "1"), tuple("bar", "2")); + } + + @Test + void doesNotSupportInjectionForFinalFields() { + + var classTemplateClass = InvalidFinalFieldTestCase.class; + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message( + "Configuration error: @Parameter field [final int %s.i] must not be declared as final.".formatted( + classTemplateClass.getName())))); + } + + @Test + void aggregatorFieldsMustNotDeclareIndex() { + + var classTemplateClass = InvalidAggregatorFieldWithIndexTestCase.class; + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message( + "Configuration error: no index may be declared in @Parameter(0) annotation on aggregator field [%s %s.accessor].".formatted( + ArgumentsAccessor.class.getName(), classTemplateClass.getName())))); + } + + @Test + void declaredIndexMustNotBeNegative() { + + var classTemplateClass = InvalidParameterIndexTestCase.class; + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message( + "Configuration error: index must be greater than or equal to zero in @Parameter(-42) annotation on field [int %s.i].".formatted( + classTemplateClass.getName())))); + } + + @Test + void declaredIndexMustBeUnique() { + + var classTemplateClass = InvalidDuplicateParameterDeclarationTestCase.class; + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message( + "Configuration error: duplicate index declared in @Parameter(0) annotation on fields [int %s.i, long %s.l].".formatted( + classTemplateClass.getName(), classTemplateClass.getName())))); + } + + @Test + void failsWithMeaningfulErrorWhenTooFewArgumentsProvidedForFieldInjection() { + var results = executeTestsForClass(NotEnoughArgumentsForFieldsTestCase.class); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message(withPlatformSpecificLineSeparator( + """ + Configuration error: @ParameterizedClass has 2 required parameters (due to field injection) but there was 1 argument provided. + Note: the provided arguments were [1]""")))); + } + } + + @Nested + class PerClassLifecycle { + + @Test + void supportsFieldInjectionForTestInstanceLifecyclePerClass() { + + var results = executeTestsForClass(FieldInjectionWithPerClassTestInstanceLifecycleTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(8).succeeded(8)); + + Supplier>> valueTrackingReportEntries = () -> allReportEntries(results) // + .filter(it -> it.containsKey("instanceHashCode")); + Supplier>> lifecycleReportEntries = () -> allReportEntries(results) // + .filter(it -> !it.containsKey("instanceHashCode")); + + assertThat(valueTrackingReportEntries.get().map(it -> it.get("value"))) // + .containsExactly("foo", "foo", "bar", "bar"); + assertThat(valueTrackingReportEntries.get().map(it -> it.get("instanceHashCode")).distinct()) // + .hasSize(1); + assertThat(lifecycleReportEntries.get().map(it -> it.get("value"))) // + .containsExactly( + //@formatter:off + "beforeParameterizedClassInvocation1", + "beforeParameterizedClassInvocation2", + "test1", + "test2", + "afterParameterizedClassInvocation1", + "afterParameterizedClassInvocation2", + "beforeParameterizedClassInvocation1", + "beforeParameterizedClassInvocation2", + "test1", + "test2", + "afterParameterizedClassInvocation1", + "afterParameterizedClassInvocation2" + //@formatter:on + ); + } + + @Test + void doesNotSupportConstructorInjectionForTestInstanceLifecyclePerClass() { + + var results = executeTests(request -> request // + .selectors(selectClass(ConstructorInjectionTestCase.class)) // + .configurationParameter(Constants.DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME, PER_CLASS.name())); + + results.allEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message(it -> it.contains( + "Constructor injection is not supported for @ParameterizedClass classes with @TestInstance(Lifecycle.PER_CLASS)")))); + } + } + + @Nested + class LifecycleMethods { + + @ParameterizedTest + @CsvSource(textBlock = """ + NonStaticBeforeLifecycleMethodTestCase, @BeforeParameterizedClassInvocation, beforeParameterizedClassInvocation + NonStaticAfterLifecycleMethodTestCase, @AfterParameterizedClassInvocation, afterParameterizedClassInvocation + """) + void lifecycleMethodsNeedToBeStaticByDefault(String simpleClassName, String annotationName, + String lifecycleMethodName) throws Exception { + + var className = ParameterizedClassIntegrationTests.class.getName() + "$" + simpleClassName; + + var results = discoverTestsForClass(Class.forName(className)); + + var issue = getOnlyElement(results.getDiscoveryIssues()); + assertThat(issue.severity()) // + .isEqualTo(Severity.ERROR); + assertThat(issue.message()) // + .isEqualTo( + "%s method 'void %s.%s()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).", + annotationName, className, lifecycleMethodName); + assertThat(issue.source()) // + .containsInstanceOf(org.junit.platform.engine.support.descriptor.MethodSource.class); + } + + @Test + void lifecycleMethodsMustNotBePrivate() { + + var results = discoverTestsForClass(PrivateLifecycleMethodTestCase.class); + + var issue = getOnlyElement(results.getDiscoveryIssues()); + assertThat(issue.severity()) // + .isEqualTo(Severity.ERROR); + assertThat(issue.message()) // + .isEqualTo( + "@BeforeParameterizedClassInvocation method 'private static void %s.beforeParameterizedClassInvocation()' must not be private.", + PrivateLifecycleMethodTestCase.class.getName()); + assertThat(issue.source()) // + .containsInstanceOf(org.junit.platform.engine.support.descriptor.MethodSource.class); + } + + @Test + void lifecycleMethodsMustNotDeclareReturnType() { + + var results = discoverTestsForClass(NonVoidLifecycleMethodTestCase.class); + + var issue = getOnlyElement(results.getDiscoveryIssues()); + assertThat(issue.severity()) // + .isEqualTo(Severity.ERROR); + assertThat(issue.message()) // + .isEqualTo( + "@BeforeParameterizedClassInvocation method 'static int %s.beforeParameterizedClassInvocation()' must not return a value.", + NonVoidLifecycleMethodTestCase.class.getName()); + assertThat(issue.source()) // + .containsInstanceOf(org.junit.platform.engine.support.descriptor.MethodSource.class); + } + + @Test + void lifecycleMethodsFromSuperclassAreWrappedAroundLifecycleMethodsFromTestClass() { + + var results = executeTestsForClass(LifecycleMethodsFromSuperclassTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + + assertThat(allReportEntries(results).map(it -> it.get("value"))) // + .containsExactly("zzz_before", "aaa_before", "test", "aaa_after", "zzz_after"); + } + + @Test + void exceptionsInLifecycleMethodsArePropagated() { + + var results = executeTestsForClass(LifecycleMethodsErrorHandlingTestCase.class); + + results.allEvents().assertStatistics(stats -> stats.started(3).failed(1).succeeded(2)); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure( // + message("zzz_before"), // + suppressed(0, message("aaa_after")), // + suppressed(1, message("zzz_after")))); + + assertThat(allReportEntries(results).map(it -> it.get("value"))) // + .containsExactly("zzz_before", "aaa_after", "zzz_after"); + } + + @ParameterizedTest + @ValueSource(classes = { LifecycleMethodArgumentInjectionWithConstructorInjectionTestCase.class, + LifecycleMethodArgumentInjectionWithFieldInjectionTestCase.class }) + void supportsInjectingArgumentsIntoLifecycleMethods(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(5).succeeded(5)); + } + + @ParameterizedTest + @ValueSource(classes = { CustomConverterAnnotationsWithLifecycleMethodsAndConstructorInjectionTestCase.class, + CustomConverterAnnotationsWithLifecycleMethodsAndFieldInjectionTestCase.class }) + void convertersHaveAccessToTheirAnnotations(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + @ParameterizedTest + @ValueSource(classes = { ValidLifecycleMethodInjectionWithConstructorInjectionTestCase.class, + ValidLifecycleMethodInjectionWithFieldInjectionTestCase.class }) + void supportsMixedInjectionsForLifecycleMethods(Class classTemplateClass) { + + var results = executeTestsForClass(classTemplateClass); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + @Test + void failsForLifecycleMethodWithInvalidParameters() { + + var results = executeTestsForClass(LifecycleMethodWithInvalidParametersTestCase.class); + + var expectedMessage = withPlatformSpecificLineSeparator( + """ + 2 configuration errors: + - parameter 'value' with index 0 is incompatible with the parameter declared on the parameterized class: \ + expected type 'int' but found 'long' + - parameter 'anotherValue' with index 1 must not be annotated with @ConvertWith"""); + + var failedResult = getFirstTestExecutionResult(results.containerEvents().failed()); + assertThat(failedResult.getThrowable().orElseThrow()) // + .hasMessage( + "Invalid @BeforeParameterizedClassInvocation lifecycle method declaration: static void %s.before(long,int)".formatted( + LifecycleMethodWithInvalidParametersTestCase.class.getName())) // + .cause().hasMessage(expectedMessage); + } + + @Test + void failsForLifecycleMethodWithInvalidParameterOrder() { + + var results = executeTestsForClass(LifecycleMethodWithInvalidParameterOrderTestCase.class); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure(message( + ("@BeforeParameterizedClassInvocation method [static void %s.before(%s,int,%s)] declares formal parameters in an invalid order: " + + "argument aggregators must be declared after any indexed arguments and before any arguments resolved by another ParameterResolver.").formatted( + LifecycleMethodWithInvalidParameterOrderTestCase.class.getName(), + ArgumentsAccessor.class.getName(), ArgumentsAccessor.class.getName())))); + } + + @Test + void failsForLifecycleMethodWithParameterAfterAggregator() { + + var results = executeTestsForClass(LifecycleMethodWithParameterAfterAggregatorTestCase.class); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, finishedWithFailure( + message(it -> it.contains("No ParameterResolver registered for parameter [int value]")))); + } + + @Test + void lifecycleMethodsMustNotBeDeclaredInRegularTestClasses() { + var testClassName = RegularClassWithLifecycleMethodsTestCase.class.getName(); + + var results = discoverTestsForClass(RegularClassWithLifecycleMethodsTestCase.class); + + assertThat(results.getDiscoveryIssues()).hasSize(2); + + var issues = results.getDiscoveryIssues().stream() // + .sorted(comparing(DiscoveryIssue::message)) // + .toList(); + + assertThat(issues) // + .extracting(DiscoveryIssue::severity) // + .containsOnly(Severity.ERROR); + assertThat(issues) // + .extracting(DiscoveryIssue::source) // + .extracting(Optional::orElseThrow) // + .allMatch(org.junit.platform.engine.support.descriptor.MethodSource.class::isInstance); + assertThat(issues.getFirst().message()) // + .isEqualTo( + "@AfterParameterizedClassInvocation method 'static void %s.after()' must not be declared in test class '%s' because it is not annotated with @ParameterizedClass.", + testClassName, testClassName); + assertThat(issues.getLast().message()) // + .isEqualTo( + "@BeforeParameterizedClassInvocation method 'static void %s.before()' must not be declared in test class '%s' because it is not annotated with @ParameterizedClass.", + testClassName, testClassName); + } + } + + private static String withPlatformSpecificLineSeparator(String textBlock) { + return textBlock.replace("\n", System.lineSeparator()); + } + + // ------------------------------------------------------------------- + + private static Stream invocationDisplayNames(EngineExecutionResults results) { + return results.containerEvents() // + .started() // + .filter(uniqueId(lastSegmentType(ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE))::matches) // + .map(Event::getTestDescriptor) // + .map(TestDescriptor::getDisplayName); + } + + private static Stream> allReportEntries(EngineExecutionResults results) { + return results.allEvents().reportingEntryPublished() // + .map(e -> e.getRequiredPayload(ReportEntry.class)) // + .map(ReportEntry::getKeyValuePairs); + } + + private static Condition lastSegmentType(@SuppressWarnings("SameParameterValue") String segmentType) { + return new Condition<>(it -> segmentType.equals(it.getLastSegment().getType()), "last segment type is '%s'", + segmentType); + } + + private static TestExecutionResult getFirstTestExecutionResult(Events events) { + return events.stream() // + .findFirst() // + .flatMap(Event::getPayload) // + .map(TestExecutionResult.class::cast) // + .orElseThrow(); + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClassWithNegativeAndPositiveValue + static class ConstructorInjectionTestCase { + + private int value; + private final TestInfo testInfo; + + public ConstructorInjectionTestCase(int value, TestInfo testInfo) { + this.value = value; + this.testInfo = testInfo; + } + + @Test + void test1() { + assertEquals("test1()", testInfo.getDisplayName()); + assertTrue(value < 0, "negative"); + value *= -1; + } + + @Test + void test2() { + assertEquals("test2()", testInfo.getDisplayName()); + assertTrue(value < 0, "negative"); + value *= -1; + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClassWithNegativeAndPositiveValue + record RecordTestCase(int value, TestInfo testInfo) { + + @Test + void test1() { + assertEquals("test1()", testInfo.getDisplayName()); + assertTrue(value < 0, "negative"); + } + + @Test + void test2() { + assertEquals("test2()", testInfo.getDisplayName()); + assertTrue(value < 0, "negative"); + } + } + + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + record RecordWithParameterAnnotationOnComponentTestCase(@Parameter int value) { + + @Test + void test1() { + assertTrue(value < 0, "negative"); + } + + @Test + void test2() { + assertTrue(value < 0, "negative"); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + static class FieldInjectionTestCase { + + @Parameter + private int value; + + @Test + void test1() { + assertTrue(value < 0, "negative"); + value *= -1; + } + + @Test + void test2() { + assertTrue(value < 0, "negative"); + value *= -1; + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @CsvSource({ "-1", "1" }) + record RecordWithBuiltInConverterTestCase(int value) { + + @Test + void test1() { + assertTrue(value < 0, "negative"); + } + + @Test + void test2() { + assertTrue(value < 0, "negative"); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + record RecordWithRegisteredConversionTestCase(@ConvertWith(CustomIntegerToStringConverter.class) String value) { + + @Test + void test1() { + assertTrue(value.startsWith("minus"), "negative"); + } + + @Test + void test2() { + assertTrue(value.startsWith("minus"), "negative"); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + static class FieldInjectionWithRegisteredConversionTestCase { + + @Parameter + @ConvertWith(CustomIntegerToStringConverter.class) + private String value; + + @Test + void test1() { + assertTrue(value.startsWith("minus"), "negative"); + } + + @Test + void test2() { + assertTrue(value.startsWith("minus"), "negative"); + } + } + + private static class CustomIntegerToStringConverter extends TypedArgumentConverter { + + CustomIntegerToStringConverter() { + super(Integer.class, String.class); + } + + @Override + protected String convert(Integer source) throws ArgumentConversionException { + return switch (source) { + case -1 -> "minus one"; + case +1 -> "plus one"; + default -> throw new IllegalArgumentException("Unsupported value: " + source); + }; + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + record RecordWithBuiltInAggregatorTestCase(ArgumentsAccessor accessor) { + + @Test + void test1() { + assertTrue(accessor.getInteger(0) < 0, "negative"); + } + + @Test + void test2() { + assertTrue(accessor.getInteger(0) < 0, "negative"); + } + + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + static class FieldInjectionWithBuiltInAggregatorTestCase { + + @Parameter + private ArgumentsAccessor accessor; + + @Test + void test1() { + assertTrue(accessor.getInteger(0) < 0, "negative"); + } + + @Test + void test2() { + assertTrue(accessor.getInteger(0) < 0, "negative"); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + record RecordWithCustomAggregatorTestCase(@AggregateWith(TimesTwoAggregator.class) int value) { + + @Test + void test1() { + assertTrue(value <= -2, "negative"); + } + + @Test + void test2() { + assertTrue(value <= -2, "negative"); + } + + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + static class FieldInjectionWithCustomAggregatorTestCase { + + @TimesTwo + private int value; + + @Test + void test1() { + assertTrue(value <= -2, "negative"); + } + + @Test + void test2() { + assertTrue(value <= -2, "negative"); + } + + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @ParameterizedClass + @ValueSource(ints = { -1, 1 }) + @interface ParameterizedClassWithNegativeAndPositiveValue { + } + + private static class TimesTwoAggregator extends SimpleArgumentsAggregator { + + @Override + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException { + + assertThat(targetType).isEqualTo(int.class); + return accessor.getInteger(0) * 2; + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @NullAndEmptySource + record NullAndEmptySourceConstructorInjectionTestCase(String value) { + @Test + void test() { + assertTrue(StringUtils.isBlank(value)); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @NullAndEmptySource + static class NullAndEmptySourceConstructorFieldInjectionTestCase { + + @Parameter + String value; + + @Test + void test() { + assertTrue(StringUtils.isBlank(value)); + } + } + + @ParameterizedClass + @CsvFileSource(resources = "two-column.csv") + record CsvFileSourceConstructorInjectionTestCase(String name, int value) { + @Test + void test() { + assertNotNull(name); + assertTrue(value > 0 && value < 5); + } + } + + @ParameterizedClass + @CsvFileSource(resources = "two-column.csv") + static class CsvFileSourceFieldInjectionTestCase { + + @Parameter(0) + String name; + + @Parameter(1) + int value; + + @Test + void test() { + assertNotNull(name); + assertTrue(value > 0 && value < 5); + } + } + + @ParameterizedClass + @EnumSource + record SingleEnumSourceConstructorInjectionTestCase(EnumOne value) { + @Test + void test() { + assertEquals(EnumOne.FOO, value); + } + } + + @ParameterizedClass + @EnumSource + static class SingleEnumSourceFieldInjectionTestCase { + + @Parameter + EnumOne value; + + @Test + void test() { + assertEquals(EnumOne.FOO, value); + } + } + + @ParameterizedClass + @EnumSource(EnumOne.class) + @EnumSource(EnumTwo.class) + record RepeatedEnumSourceConstructorInjectionTestCase(Object value) { + @Test + void test() { + assertTrue(value == EnumOne.FOO || value == EnumTwo.BAR); + } + } + + @ParameterizedClass + @EnumSource(EnumOne.class) + @EnumSource(EnumTwo.class) + static class RepeatedEnumSourceFieldInjectionTestCase { + + @Parameter + Object value; + + @Test + void test() { + assertTrue(value == EnumOne.FOO || value == EnumTwo.BAR); + } + } + + private enum EnumOne { + FOO + } + + private enum EnumTwo { + BAR + } + + @ParameterizedClass + @MethodSource("parameters") + record MethodSourceConstructorInjectionTestCase(String value) { + + static Stream parameters() { + return Stream.of("foo", "bar"); + } + + @Test + void test() { + assertTrue(value.equals("foo") || value.equals("bar")); + } + } + + @ParameterizedClass + @MethodSource("parameters") + static class MethodSourceFieldInjectionTestCase { + + static Stream parameters() { + return Stream.of("foo", "bar"); + } + + @Parameter + String value; + + @Test + void test() { + assertTrue(value.equals("foo") || value.equals("bar")); + } + } + + @ParameterizedClass + @MethodSource + record MethodSourceWithoutMethodNameTestCase(String value) { + + @Test + void test() { + fail("should not be executed"); + } + } + + @ParameterizedClass + @FieldSource("parameters") + record FieldSourceConstructorInjectionTestCase(String value) { + + static final List parameters = List.of("foo", "bar"); + + @Test + void test() { + assertTrue(value.equals("foo") || value.equals("bar")); + } + } + + @ParameterizedClass + @FieldSource("parameters") + static class FieldSourceFieldInjectionTestCase { + + static final List parameters = List.of("foo", "bar"); + + @Parameter + String value; + + @Test + void test() { + assertTrue(value.equals("foo") || value.equals("bar")); + } + } + + @ParameterizedClass + @FieldSource + record FieldSourceWithoutFieldNameTestCase(String value) { + + @Test + void test() { + fail("should not be executed"); + } + } + + @ParameterizedClass + @ArgumentsSource(CustomArgumentsProvider.class) + record ArgumentsSourceConstructorInjectionTestCase(String value) { + @Test + void test() { + assertTrue(value.equals("foo") || value.equals("bar")); + } + } + + @ParameterizedClass + @ArgumentsSource(CustomArgumentsProvider.class) + static class ArgumentsSourceFieldInjectionTestCase { + + @Parameter + String value; + + @Test + void test() { + assertTrue(value.equals("foo") || value.equals("bar")); + } + } + + static class CustomArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context) + throws Exception { + return Stream.of("foo", "bar").map(Arguments::of); + } + } + + @ParameterizedClass(name = INDEX_PLACEHOLDER + " | " // + + DISPLAY_NAME_PLACEHOLDER + " | " // + + ARGUMENTS_PLACEHOLDER + " | " // + + ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER) + @MethodSource("arguments") + @DisplayName("TesT") + record CustomNamePatternTestCase(int number, String name) { + + static Stream arguments() { + return Stream.of(argumentSet("set", 1, "foo"), Arguments.of(2, "bar")); + } + + @Test + void test() { + assertTrue(number > 0); + assertFalse(name.isBlank()); + } + } + + @ParameterizedClass + @ArgumentsSource(AutoCloseableArgumentProvider.class) + record AutoCloseableArgumentTestCase(AutoCloseableArgument argument) { + @Test + void test() { + assertNotNull(argument); + assertEquals(0, AutoCloseableArgument.closeCounter); + } + } + + @ParameterizedClass(autoCloseArguments = false) + @ArgumentsSource(AutoCloseableArgumentProvider.class) + record AutoCloseableArgumentWithDisabledCleanupTestCase(AutoCloseableArgument argument) { + @Test + void test() { + assertNotNull(argument); + assertEquals(0, AutoCloseableArgument.closeCounter); + } + } + + private static class AutoCloseableArgumentProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { + return Stream.of(arguments(new AutoCloseableArgument(), Named.of("unused", new AutoCloseableArgument()))); + } + } + + static class AutoCloseableArgument implements AutoCloseable { + + static int closeCounter = 0; + + @Override + public void close() { + closeCounter++; + } + } + + @ParameterizedClass(argumentCountValidation = STRICT) + @CsvSource("foo, unused") + record StrictArgumentCountValidationModeTestCase(String value) { + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass(argumentCountValidation = NONE) + @CsvSource("foo, unused") + record NoneArgumentCountValidationModeTestCase(String value) { + @Test + void test() { + assertEquals("foo", value); + } + } + + @ParameterizedClass + @CsvSource("foo, unused") + record DefaultArgumentCountValidationModeTestCase(String value) { + @Test + void test() { + assertEquals("foo", value); + } + } + + @ParameterizedClass + @MethodSource("org.junit.jupiter.params.ParameterizedClassIntegrationTests#zeroArguments") + record ForbiddenZeroInvocationsTestCase(String value) { + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass(allowZeroInvocations = true) + @MethodSource("org.junit.jupiter.params.ParameterizedClassIntegrationTests#zeroArguments") + record AllowedZeroInvocationsTestCase(String value) { + @Test + void test() { + fail("should not be called"); + } + } + + static Stream zeroArguments() { + return Stream.empty(); + } + + @ParameterizedClass + record NoArgumentSourceTestCase(String value) { + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = { 1, 2 }) + static class NestedFieldInjectionTestCase extends LifecycleCallbacks { + + @Parameter + int number; + + @Nested + @ParameterizedClass + @ValueSource(strings = { "foo", "bar" }) + class InnerTestCase extends LifecycleCallbacks { + + @Parameter + String text; + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + void test(boolean flag, TestReporter reporter) { + reporter.publishEntry("test(" + number + ", " + text + ", " + flag + ")"); + assertTrue(number > 0); + assertTrue(List.of("foo", "bar").contains(text)); + } + } + } + + @ParameterizedClass + @ValueSource(ints = { 1, 2 }) + static class NestedConstructorInjectionTestCase extends LifecycleCallbacks { + + final int number; + + NestedConstructorInjectionTestCase(int number) { + this.number = number; + } + + @Nested + @ParameterizedClass + @ValueSource(strings = { "foo", "bar" }) + class InnerTestCase extends LifecycleCallbacks { + + final String text; + + InnerTestCase(String text) { + this.text = text; + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + void test(boolean flag, TestReporter reporter) { + reporter.publishEntry("test(" + number + ", " + text + ", " + flag + ")"); + assertTrue(number > 0); + assertTrue(List.of("foo", "bar").contains(text)); + } + } + } + + static class LifecycleCallbacks { + + @BeforeAll + static void beforeAll(TestReporter reporter, TestInfo testInfo) { + reporter.publishEntry("beforeAll: " + testInfo.getTestClass().orElseThrow().getSimpleName()); + } + + @BeforeParameterizedClassInvocation(injectArguments = false) + static void beforeParameterizedClassInvocation(TestReporter reporter, TestInfo testInfo) { + reporter.publishEntry( + "beforeParameterizedClassInvocation: " + testInfo.getTestClass().orElseThrow().getSimpleName()); + } + + @BeforeEach + void beforeEach(TestReporter reporter, TestInfo testInfo) { + reporter.publishEntry( + "beforeEach: " + testInfo.getDisplayName() + " [" + this.getClass().getSimpleName() + "]"); + } + + @AfterEach + void afterEach(TestReporter reporter, TestInfo testInfo) { + reporter.publishEntry( + "afterEach: " + testInfo.getDisplayName() + " [" + this.getClass().getSimpleName() + "]"); + } + + @AfterParameterizedClassInvocation(injectArguments = false) + static void afterParameterizedClassInvocation(TestReporter reporter, TestInfo testInfo) { + reporter.publishEntry( + "afterParameterizedClassInvocation: " + testInfo.getTestClass().orElseThrow().getSimpleName()); + } + + @AfterAll + static void afterAll(TestReporter reporter, TestInfo testInfo) { + reporter.publishEntry("afterAll: " + testInfo.getTestClass().orElseThrow().getSimpleName()); + } + } + + @ParameterizedClass + @ValueSource(ints = { 1, 2 }) + record ConstructorInjectionWithRegularNestedTestCase(int number) { + + @Nested + @TestInstance(PER_CLASS) + class InnerTestCase { + + InnerTestCase(TestInfo testInfo) { + assertThat(testInfo.getTestClass()).contains(InnerTestCase.class); + assertThat(testInfo.getTestMethod()).isEmpty(); + } + + @Test + void test() { + assertTrue(number >= 0); + } + } + } + + @ParameterizedClass + @ValueSource(ints = { 1, 2 }) + static class FieldInjectionWithRegularNestedTestCase { + + @Parameter + int number; + + @Nested + @TestInstance(PER_CLASS) + class InnerTestCase { + + InnerTestCase(TestInfo testInfo) { + assertThat(testInfo.getTestClass()).contains(InnerTestCase.class); + assertThat(testInfo.getTestMethod()).isEmpty(); + } + + @Test + void test() { + assertTrue(number >= 0); + } + } + } + + @ParameterizedClass + @CsvSource({ "1, foo", "2, bar" }) + static class MultiAggregatorFieldInjectionTestCase { + + @Parameter + ArgumentsAccessor accessor; + + @TimesTwo + int numberTimesTwo; + + @Parameter(0) + int number; + + @Parameter(1) + String text; + + @Test + void test() { + assertEquals(2, accessor.size()); + assertEquals(number, accessor.getInteger(0)); + assertEquals(number * 2, numberTimesTwo); + assertEquals(text, accessor.getString(1)); + } + + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD, ElementType.PARAMETER }) + @Parameter + @AggregateWith(TimesTwoAggregator.class) + @interface TimesTwo { + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ParameterizedClass + @MethodSource("methodSource") + @FieldSource("fieldSource") + @TestInstance(PER_CLASS) + static class FieldInjectionWithPerClassTestInstanceLifecycleTestCase { + + List methodSource() { + return List.of("foo"); + } + + final List fieldSource = List.of("bar"); + + @BeforeParameterizedClassInvocation(injectArguments = false) + void beforeParameterizedClassInvocation1(TestReporter reporter) { + reporter.publishEntry("beforeParameterizedClassInvocation1"); + } + + @BeforeParameterizedClassInvocation(injectArguments = false) + void beforeParameterizedClassInvocation2(TestReporter reporter) { + reporter.publishEntry("beforeParameterizedClassInvocation2"); + } + + @AfterParameterizedClassInvocation(injectArguments = false) + void afterParameterizedClassInvocation1(TestReporter reporter) { + reporter.publishEntry("afterParameterizedClassInvocation1"); + } + + @AfterParameterizedClassInvocation(injectArguments = false) + void afterParameterizedClassInvocation2(TestReporter reporter) { + reporter.publishEntry("afterParameterizedClassInvocation2"); + } + + @Parameter + private String value; + + @Test + void test1(TestReporter reporter, TestInfo testInfo) { + publishReportEntry(reporter, testInfo); + } + + @Test + void test2(TestReporter reporter, TestInfo testInfo) { + publishReportEntry(reporter, testInfo); + } + + private void publishReportEntry(TestReporter reporter, TestInfo testInfo) { + assertNotNull(value); + reporter.publishEntry(testInfo.getTestMethod().orElseThrow().getName()); + reporter.publishEntry(Map.of( // + "instanceHashCode", Integer.toHexString(hashCode()), // + "value", value // + )); + } + } + + abstract static class BaseTestCase { + @Parameter(0) + String value; + } + + @ParameterizedClass + @CsvSource({ "foo, 1", "bar, 2" }) + static class InheritedHiddenParameterFieldTestCase extends BaseTestCase { + @Parameter(1) + String value; + + @Test + void test(TestReporter reporter) { + reporter.publishEntry(Map.of( // + "super.value", super.value, // + "this.value", this.value // + )); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class InvalidFinalFieldTestCase { + + @Parameter + final int i = -1; + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class InvalidAggregatorFieldWithIndexTestCase { + + @Parameter(0) + ArgumentsAccessor accessor; + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class InvalidParameterIndexTestCase { + + @Parameter(-42) + int i; + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class InvalidDuplicateParameterDeclarationTestCase { + + @Parameter(0) + int i; + + @Parameter(0) + long l; + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class NotEnoughArgumentsForFieldsTestCase { + + @Parameter(0) + int i; + + @Parameter(1) + String s; + + @org.junit.jupiter.api.Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @CsvSource({ "unused1, foo, unused2, bar", "unused4, baz, unused5, qux" }) + static class InvalidUnusedParameterIndexesTestCase { + + @Parameter(1) + String second; + + @Parameter(3) + String fourth; + + @Test + void test(TestReporter reporter) { + reporter.publishEntry(Map.of( // + "second", second, // + "fourth", fourth // + )); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record ArgumentConversionPerInvocationConstructorInjectionTestCase( + @ConvertWith(Wrapper.Converter.class) Wrapper wrapper) { + + static Wrapper instance; + + @BeforeAll + @AfterAll + static void clearWrapper() { + instance = null; + } + + @Test + void test1() { + setOrCheckWrapper(); + } + + @Test + void test2() { + setOrCheckWrapper(); + } + + private void setOrCheckWrapper() { + if (instance == null) { + instance = wrapper; + } + else { + assertSame(instance, wrapper); + } + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class ArgumentConversionPerInvocationFieldInjectionTestCase { + + static Wrapper instance; + + @BeforeAll + @AfterAll + static void clearWrapper() { + instance = null; + } + + @Parameter + @ConvertWith(Wrapper.Converter.class) + Wrapper wrapper; + + @Test + void test1() { + setOrCheckWrapper(); + } + + @Test + void test2() { + setOrCheckWrapper(); + } + + private void setOrCheckWrapper() { + if (instance == null) { + instance = wrapper; + } + else { + assertSame(instance, wrapper); + } + } + } + + record Wrapper(int value) { + static class Converter extends SimpleArgumentConverter { + @Override + protected Object convert(Object source, Class targetType) { + return new Wrapper((Integer) source); + } + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record NonStaticBeforeLifecycleMethodTestCase() { + + @BeforeParameterizedClassInvocation + void beforeParameterizedClassInvocation() { + fail("should not be called"); + } + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record NonStaticAfterLifecycleMethodTestCase() { + + @AfterParameterizedClassInvocation + void afterParameterizedClassInvocation() { + fail("should not be called"); + } + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record PrivateLifecycleMethodTestCase() { + + @BeforeParameterizedClassInvocation + private static void beforeParameterizedClassInvocation() { + fail("should not be called"); + } + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record NonVoidLifecycleMethodTestCase() { + + @BeforeParameterizedClassInvocation + static int beforeParameterizedClassInvocation() { + return fail("should not be called"); + } + + @Test + void test() { + fail("should not be called"); + } + } + + static abstract class AbstractBaseLifecycleTestCase { + + @BeforeParameterizedClassInvocation + static void zzz_before(TestReporter reporter) { + reporter.publishEntry("zzz_before"); + } + + @AfterParameterizedClassInvocation + static void zzz_after(TestReporter reporter) { + reporter.publishEntry("zzz_after"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class LifecycleMethodsFromSuperclassTestCase extends AbstractBaseLifecycleTestCase { + + @BeforeParameterizedClassInvocation + static void aaa_before(TestReporter reporter) { + reporter.publishEntry("aaa_before"); + } + + @AfterParameterizedClassInvocation + static void aaa_after(TestReporter reporter) { + reporter.publishEntry("aaa_after"); + } + + @Test + void test(TestReporter reporter) { + reporter.publishEntry("test"); + } + } + + static abstract class AbstractBaseLifecycleWithErrorsTestCase { + + @BeforeParameterizedClassInvocation + static void zzz_before(TestReporter reporter) { + reporter.publishEntry("zzz_before"); + fail("zzz_before"); + } + + @AfterParameterizedClassInvocation + static void zzz_after(TestReporter reporter) { + reporter.publishEntry("zzz_after"); + fail("zzz_after"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class LifecycleMethodsErrorHandlingTestCase extends AbstractBaseLifecycleWithErrorsTestCase { + + @BeforeParameterizedClassInvocation + static void aaa_before(TestReporter reporter) { + fail("should not be called"); + } + + @AfterParameterizedClassInvocation + static void aaa_after(TestReporter reporter) { + reporter.publishEntry("aaa_after"); + fail("aaa_after"); + } + + @Test + void test(TestReporter reporter) { + reporter.publishEntry("test"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record LifecycleMethodArgumentInjectionWithConstructorInjectionTestCase( + @ConvertWith(AtomicIntegerConverter.class) AtomicInteger counter) { + + @BeforeParameterizedClassInvocation + static void before(AtomicInteger counter) { + assertEquals(2, counter.incrementAndGet()); + } + + @AfterParameterizedClassInvocation + static void after(AtomicInteger counter) { + assertEquals(4, counter.get()); + } + + @Test + void test1() { + this.counter.incrementAndGet(); + } + + @Test + void test2() { + this.counter.incrementAndGet(); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class LifecycleMethodArgumentInjectionWithFieldInjectionTestCase { + + @Parameter + @ConvertWith(AtomicIntegerConverter.class) + AtomicInteger counter; + + @BeforeParameterizedClassInvocation + static void before(AtomicInteger counter) { + assertEquals(2, counter.incrementAndGet()); + } + + @AfterParameterizedClassInvocation + static void after(AtomicInteger counter) { + assertEquals(4, counter.get()); + } + + @Test + void test1() { + this.counter.incrementAndGet(); + } + + @Test + void test2() { + this.counter.incrementAndGet(); + } + } + + static class AtomicIntegerConverter extends SimpleArgumentConverter { + @Override + protected Object convert(Object source, Class targetType) { + return new AtomicInteger((Integer) source); + } + } + + @ParameterizedClass + @ValueSource(strings = "foo") + record CustomConverterAnnotationsWithLifecycleMethodsAndConstructorInjectionTestCase( + @CustomConversion String value) { + + @BeforeParameterizedClassInvocation + static void before(String value) { + assertEquals("foo", value); + } + + @Test + void test() { + assertEquals("foo", this.value); + } + } + + @ParameterizedClass + @ValueSource(strings = "foo") + static class CustomConverterAnnotationsWithLifecycleMethodsAndFieldInjectionTestCase { + + @Parameter + @CustomConversion + String value; + + @BeforeParameterizedClassInvocation + static void before(String value) { + assertEquals("foo", value); + } + + @Test + void test() { + assertEquals("foo", this.value); + } + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.PARAMETER, ElementType.FIELD }) + @ConvertWith(CustomConversion.Converter.class) + @interface CustomConversion { + + class Converter implements ArgumentConverter { + @Override + public Object convert(Object source, ParameterContext context) throws ArgumentConversionException { + assertNotNull(context.getParameter().getAnnotation(CustomConversion.class)); + return source; + } + + @Override + public Object convert(Object source, FieldContext context) throws ArgumentConversionException { + assertNotNull(context.getField().getAnnotation(CustomConversion.class)); + return source; + } + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class ValidLifecycleMethodInjectionWithConstructorInjectionTestCase + extends AbstractValidLifecycleMethodInjectionTestCase { + + private final AtomicInteger value; + + ValidLifecycleMethodInjectionWithConstructorInjectionTestCase( + @ConvertWith(AtomicIntegerConverter.class) AtomicInteger value) { + this.value = value; + } + + @Test + void test() { + assertEquals(5, this.value.getAndIncrement()); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + static class ValidLifecycleMethodInjectionWithFieldInjectionTestCase + extends AbstractValidLifecycleMethodInjectionTestCase { + + @Parameter + @ConvertWith(AtomicIntegerConverter.class) + AtomicInteger value; + + @Test + void test() { + assertEquals(5, this.value.getAndIncrement()); + } + } + + abstract static class AbstractValidLifecycleMethodInjectionTestCase { + + @BeforeParameterizedClassInvocation + static void before0() { + } + + @BeforeParameterizedClassInvocation + static void before1(AtomicInteger value) { + value.incrementAndGet(); + } + + @BeforeParameterizedClassInvocation + static void before2(ArgumentsAccessor accessor) { + assertEquals(1, accessor.getInteger(0)); + } + + @BeforeParameterizedClassInvocation + static void before3(AtomicInteger value, TestInfo testInfo) { + assertEquals("[1] value=1", testInfo.getDisplayName()); + value.incrementAndGet(); + } + + @BeforeParameterizedClassInvocation + static void before4(ArgumentsAccessor accessor, TestInfo testInfo) { + assertEquals(1, accessor.getInteger(0)); + assertEquals("[1] value=1", testInfo.getDisplayName()); + } + + @BeforeParameterizedClassInvocation + static void before4(AtomicInteger value, ArgumentsAccessor accessor) { + assertEquals(1, accessor.getInteger(0)); + value.incrementAndGet(); + } + + @BeforeParameterizedClassInvocation + static void before5(AtomicInteger value, ArgumentsAccessor accessor, TestInfo testInfo) { + assertEquals(1, accessor.getInteger(0)); + assertEquals("[1] value=1", testInfo.getDisplayName()); + value.incrementAndGet(); + } + + @BeforeParameterizedClassInvocation + static void before6(@TimesTwo int valueTimesTwo) { + assertEquals(2, valueTimesTwo); + } + + @AfterParameterizedClassInvocation + static void after(AtomicInteger value, ArgumentsAccessor accessor, TestInfo testInfo) { + assertEquals(6, value.get()); + assertEquals(1, accessor.getInteger(0)); + assertEquals("[1] value=1", testInfo.getDisplayName()); + } + } + + @ParameterizedClass + @CsvSource("1, 2") + record LifecycleMethodWithInvalidParametersTestCase(int value, int anotherValue) { + + @BeforeParameterizedClassInvocation + static void before(long value, @ConvertWith(CustomIntegerToStringConverter.class) int anotherValue) { + fail("should not be called"); + } + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record LifecycleMethodWithInvalidParameterOrderTestCase(int value) { + + @BeforeParameterizedClassInvocation + static void before(ArgumentsAccessor accessor1, int value, ArgumentsAccessor accessor2) { + fail("should not be called"); + } + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass + @ValueSource(ints = 1) + record LifecycleMethodWithParameterAfterAggregatorTestCase(int value) { + + @BeforeParameterizedClassInvocation + static void before(@TimesTwo int valueTimesTwo, int value) { + fail("should not be called"); + } + + @Test + void test() { + fail("should not be called"); + } + } + + @ParameterizedClass // argument sets: 13 = 2 + 4 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + @ArgumentsSource(CustomArgumentsProvider.class) // 2 + @CsvFileSource(resources = "two-column.csv") // 4 + @CsvSource("csv") // 1 + @EmptySource // 1 + @EnumSource(EnumOne.class) // 1 + @FieldSource("field") // 1 + @MethodSource("method") // 1 + @NullSource // 1 + @ValueSource(strings = "value") // 1 + abstract static class BaseInheritanceTestCase { + + static final List field = List.of("field"); + + static List method() { + return List.of("method"); + } + + @Parameter + @ConvertWith(ToStringConverter.class) // For @EnumSource + String value; + + @Test + void test() { + } + + @Nested + @ParameterizedClass + @ValueSource(ints = 1) + class Inner { + @Test + void test() { + } + } + + static class ToStringConverter extends SimpleArgumentConverter { + @Override + protected Object convert(Object source, Class targetType) throws ArgumentConversionException { + return source == null ? null : String.valueOf(source); + } + } + } + + static class ConcreteInheritanceTestCase extends BaseInheritanceTestCase { + } + + static class RegularClassWithLifecycleMethodsTestCase { + + @BeforeParameterizedClassInvocation + static void before() { + } + + @AfterParameterizedClassInvocation + static void after() { + } + + @Test + void test() { + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,396 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENTS_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENTS_WITH_NAMES_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.ARGUMENT_SET_NAME_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.DEFAULT_DISPLAY_NAME; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.DISPLAY_NAME_PLACEHOLDER; +import static org.junit.jupiter.params.ParameterizedInvocationConstants.INDEX_PLACEHOLDER; +import static org.junit.jupiter.params.provider.Arguments.argumentSet; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.sql.Date; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.Locale; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.AnnotatedElementContext; +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.params.aggregator.AggregateWith; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.aggregator.SimpleArgumentsAggregator; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.support.ReflectionSupport; + +/** + * @since 5.0 + */ +@SuppressWarnings("ALL") +class ParameterizedInvocationNameFormatterTests { + + private final Locale originalLocale = Locale.getDefault(); + + @AfterEach + void restoreLocale() { + Locale.setDefault(originalLocale); + } + + @Test + void formatsDisplayName() { + var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, "enigma"); + + assertEquals("enigma", format(formatter, 1, arguments())); + assertEquals("enigma", format(formatter, 2, arguments())); + } + + @Test + void formatsDisplayNameContainingApostrophe() { + String displayName = "display'Zero"; + var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, "display'Zero"); + + assertEquals(displayName, format(formatter, 1, arguments())); + assertEquals(displayName, format(formatter, 2, arguments())); + } + + @Test + void formatsDisplayNameContainingFormatElements() { + String displayName = "{enigma} {0} '{1}'"; + var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, displayName); + + assertEquals(displayName, format(formatter, 1, arguments())); + assertEquals(displayName, format(formatter, 2, arguments())); + } + + @Test + void formatsInvocationIndex() { + var formatter = formatter(INDEX_PLACEHOLDER, "enigma"); + + assertEquals("1", format(formatter, 1, arguments())); + assertEquals("2", format(formatter, 2, arguments())); + } + + @Test + void defaultDisplayName() { + var formatter = formatter(DEFAULT_DISPLAY_NAME, "IGNORED"); + + var formattedName = format(formatter, 1, arguments("apple", "banana")); + + assertThat(formattedName).isEqualTo("[1] apple, banana"); + } + + @Test + void formatsIndividualArguments() { + var formatter = formatter("{0} -> {1}", "enigma"); + + assertEquals("foo -> 42", format(formatter, 1, arguments("foo", 42))); + } + + @Test + void formatsCompleteArgumentsList() { + var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); + + // @formatter:off + Arguments args = arguments( + 42, + 99, + "enigma", + null, + new int[] { 1, 2, 3 }, + new String[] { "foo", "bar" }, + new Integer[][] { { 2, 4 }, { 3, 9 } } + ); + // @formatter:on + + assertEquals("42, 99, enigma, null, [1, 2, 3], [foo, bar], [[2, 4], [3, 9]]", format(formatter, 1, args)); + } + + @Test + void formatsCompleteArgumentsListWithNames() { + var testMethod = ParameterizedTestCases.getMethod("parameterizedTest", int.class, String.class, Object[].class); + var formatter = formatter(ARGUMENTS_WITH_NAMES_PLACEHOLDER, "enigma", testMethod); + + var formattedName = format(formatter, 1, arguments(42, "enigma", new Object[] { "foo", 1 })); + assertEquals("someNumber=42, someString=enigma, someArray=[foo, 1]", formattedName); + } + + @Test + void formatsCompleteArgumentsListWithoutNamesForAggregators() { + var testMethod = ParameterizedTestCases.getMethod("parameterizedTestWithAggregator", int.class, String.class); + var formatter = formatter(ARGUMENTS_WITH_NAMES_PLACEHOLDER, "enigma", testMethod); + + var formattedName = format(formatter, 1, arguments(42, "foo", "bar")); + assertEquals("someNumber=42, foo, bar", formattedName); + } + + @Test + void formatsCompleteArgumentsListWithArrays() { + var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); + + // Explicit test for https://github.com/junit-team/junit-framework/issues/814 + assertEquals("[foo, bar]", format(formatter, 1, arguments((Object) new String[] { "foo", "bar" }))); + + assertEquals("[foo, bar], 42, true", format(formatter, 1, arguments(new String[] { "foo", "bar" }, 42, true))); + } + + @Test + void formatsEverythingUsingCustomPattern() { + var pattern = DISPLAY_NAME_PLACEHOLDER + " " + INDEX_PLACEHOLDER + " :: " + ARGUMENTS_PLACEHOLDER + " :: {1}"; + var formatter = formatter(pattern, "enigma"); + + assertEquals("enigma 1 :: foo, bar :: bar", format(formatter, 1, arguments("foo", "bar"))); + assertEquals("enigma 2 :: foo, 42 :: 42", format(formatter, 2, arguments("foo", 42))); + } + + @Test + void formatDoesNotAlterArgumentsArray() { + Object[] actual = { 1, "two", Byte.valueOf("-128"), new Integer[][] { { 2, 4 }, { 3, 9 } } }; + var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); + var expected = Arrays.copyOf(actual, actual.length); + assertEquals("1, two, -128, [[2, 4], [3, 9]]", format(formatter, 1, arguments(actual))); + assertArrayEquals(expected, actual); + } + + @Test + void formatDoesNotRaiseAnArrayStoreException() { + var formatter = formatter("{0} -> {1}", "enigma"); + + Object[] arguments = new Number[] { 1, 2 }; + assertEquals("1 -> 2", format(formatter, 1, arguments(arguments))); + } + + @Test + void throwsReadableExceptionForInvalidPattern() { + var exception = assertThrows(JUnitException.class, () -> formatter("{index", "enigma")); + assertNotNull(exception.getCause()); + assertEquals(IllegalArgumentException.class, exception.getCause().getClass()); + } + + @Test + void formattingDoesNotFailIfArgumentToStringImplementationReturnsNull() { + var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); + + var formattedName = format(formatter, 1, arguments(new ToStringReturnsNull(), "foo")); + + assertThat(formattedName).isEqualTo("null, foo"); + } + + @Test + void formattingDoesNotFailIfArgumentToStringImplementationThrowsAnException() { + var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); + + var formattedName = format(formatter, 1, arguments(new ToStringThrowsException(), "foo")); + + assertThat(formattedName).startsWith(ToStringThrowsException.class.getName() + "@"); + assertThat(formattedName).endsWith("foo"); + } + + @ParameterizedTest(name = "{0}") + @CsvSource(delimiter = '|', textBlock = """ + US | 42.23 is positive on 2019 Jan 13 at 12:34:56 + DE | 42,23 is positive on 13.01.2019 at 12:34:56 + """) + void customFormattingExpressionsAreSupported(Locale locale, String expectedValue) { + var pattern = "[{index}] {1,number,#.##} is {1,choice,0 format(formatter, 1, arguments())) + .havingCause() + .isExactlyInstanceOf(ExtensionConfigurationException.class) + .withMessage("When the display name pattern for a @ParameterizedTest contains %s, " + + "the arguments must be supplied as an ArgumentSet.", ARGUMENT_SET_NAME_PLACEHOLDER); + // @formatter:on + } + + @Test + void defaultDisplayName() { + var formatter = formatter(DEFAULT_DISPLAY_NAME, "IGNORED"); + + var formattedName = format(formatter, 42, argumentSet("Fruits", "apple", "banana")); + + assertThat(formattedName).isEqualTo("[42] Fruits"); + } + + @Test + void argumentSetNameAndArgumentsPlaceholders() { + var pattern = ARGUMENT_SET_NAME_PLACEHOLDER + " :: " + ARGUMENTS_PLACEHOLDER; + var formatter = formatter(pattern, "IGNORED"); + + var formattedName = format(formatter, -1, argumentSet("Fruits", "apple", "banana")); + + assertThat(formattedName).isEqualTo("Fruits :: apple, banana"); + } + + @Test + void mixedTypesOfArgumentsImplementationsAndCustomDisplayNamePattern() { + var pattern = "[%s] %s :: %s".formatted(INDEX_PLACEHOLDER, DISPLAY_NAME_PLACEHOLDER, + ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER); + var testMethod = ParameterizedTestCases.getMethod("processFruits", String.class, String.class); + var formatter = formatter(pattern, "Mixed Arguments Types", testMethod); + + var name1 = format(formatter, 1, argumentSet("Fruits", "apple", "banana")); + var name2 = format(formatter, 2, arguments("apple", "banana")); + + assertThat(name1).isEqualTo("[1] Mixed Arguments Types :: Fruits"); + assertThat(name2).isEqualTo("[2] Mixed Arguments Types :: fruit1=apple, fruit2=banana"); + } + + } + + // ------------------------------------------------------------------------- + + private static ParameterizedInvocationNameFormatter formatter(String pattern, String displayName) { + return formatter(pattern, displayName, 512); + } + + private static ParameterizedInvocationNameFormatter formatter(String pattern, String displayName, + int argumentMaxLength) { + ParameterizedDeclarationContext context = mock(); + when(context.getResolverFacade()).thenReturn(mock()); + when(context.getAnnotationName()).thenReturn(ParameterizedTest.class.getSimpleName()); + return new ParameterizedInvocationNameFormatter(pattern, displayName, context, argumentMaxLength); + } + + private static ParameterizedInvocationNameFormatter formatter(String pattern, String displayName, Method method) { + var context = new ParameterizedTestContext(method.getDeclaringClass(), method, + method.getAnnotation(ParameterizedTest.class)); + return new ParameterizedInvocationNameFormatter(pattern, displayName, context, 512); + } + + private static String format(ParameterizedInvocationNameFormatter formatter, int invocationIndex, + Arguments arguments) { + return formatter.format(invocationIndex, EvaluatedArgumentSet.allOf(arguments)); + } + + private static class ToStringReturnsNull { + + @Override + public String toString() { + return null; + } + } + + private static class ToStringThrowsException { + + @Override + public String toString() { + throw new RuntimeException("Boom!"); + } + } + + private static class ParameterizedTestCases { + + static Method getMethod(String methodName, Class... parameterTypes) { + return ReflectionSupport.findMethod(ParameterizedTestCases.class, methodName, parameterTypes).orElseThrow(); + } + + @SuppressWarnings("unused") + @ParameterizedTest + void parameterizedTest(int someNumber, String someString, Object[] someArray) { + } + + @SuppressWarnings("unused") + @ParameterizedTest + void parameterizedTestWithAggregator(int someNumber, + @AggregateWith(CustomAggregator.class) String someAggregatedString) { + } + + @SuppressWarnings("unused") + @ParameterizedTest + void processFruits(String fruit1, String fruit2) { + } + + private static class CustomAggregator extends SimpleArgumentsAggregator { + @Override + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) { + return accessor.get(0); + } + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestContextTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestContextTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestContextTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestContextTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.params.aggregator.AggregatorIntegrationTests.CsvToPerson; +import org.junit.jupiter.params.aggregator.AggregatorIntegrationTests.Person; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.ReflectionUtils; + +/** + * Unit tests for {@link ParameterizedTestContext}. + * + * @since 5.2 + */ +class ParameterizedTestContextTests { + + @ParameterizedTest + @ValueSource(strings = { "onePrimitive", "twoPrimitives", "twoAggregators", "twoAggregatorsWithTestInfoAtTheEnd", + "mixedMode" }) + void validSignatures(String methodName) { + assertDoesNotThrow(() -> createMethodContext(ValidTestCase.class, methodName)); + } + + @ParameterizedTest + @ValueSource(strings = { "twoAggregatorsWithPrimitiveInTheMiddle", "twoAggregatorsWithTestInfoInTheMiddle" }) + void invalidSignatures(String methodName) { + assertThrows(PreconditionViolationException.class, + () -> createMethodContext(InvalidTestCase.class, methodName)); + } + + private ParameterizedTestContext createMethodContext(Class testClass, String methodName) { + var method = ReflectionUtils.findMethods(testClass, m -> m.getName().equals(methodName)).getFirst(); + return new ParameterizedTestContext(testClass, method, method.getAnnotation(ParameterizedTest.class)); + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class ValidTestCase { + + @ParameterizedTest + void onePrimitive(int num) { + } + + @ParameterizedTest + void twoPrimitives(int num1, int num2) { + } + + @ParameterizedTest + void twoAggregators(@CsvToPerson Person person, ArgumentsAccessor arguments) { + } + + @ParameterizedTest + void twoAggregatorsWithTestInfoAtTheEnd(@CsvToPerson Person person1, @CsvToPerson Person person2, + TestInfo testInfo) { + } + + @ParameterizedTest + void mixedMode(int num1, int num2, ArgumentsAccessor arguments1, ArgumentsAccessor arguments2, + @CsvToPerson Person person1, @CsvToPerson Person person2, TestInfo testInfo1, TestInfo testInfo2) { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class InvalidTestCase { + + @ParameterizedTest + void twoAggregatorsWithPrimitiveInTheMiddle(@CsvToPerson Person person1, int num, @CsvToPerson Person person2) { + } + + @ParameterizedTest + void twoAggregatorsWithTestInfoInTheMiddle(@CsvToPerson Person person1, TestInfo testInfo, + @CsvToPerson Person person2) { + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,12 +15,15 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.params.ParameterizedTestExtension.arguments; +import static org.junit.jupiter.params.ParameterizedInvocationContextProvider.arguments; +import static org.junit.jupiter.params.ParameterizedTestExtension.DECLARATION_CONTEXT_KEY; import java.io.FileNotFoundException; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import java.util.Arrays; +import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -28,18 +31,23 @@ import java.util.function.Function; import java.util.stream.Stream; +import org.junit.jupiter.api.MediaType; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExecutableInvoker; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TemplateInvocationValidationException; import org.junit.jupiter.api.extension.TestInstances; +import org.junit.jupiter.api.function.ThrowingConsumer; import org.junit.jupiter.api.parallel.ExecutionMode; import org.junit.jupiter.engine.execution.NamespaceAwareStore; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; /** @@ -100,7 +108,7 @@ void defaultDisplayNameWithEmptyStringInConfigurationIsIllegal() { AtomicInteger invocations = new AtomicInteger(); Function> configurationSupplier = key -> { - if (key.equals(ParameterizedTestExtension.DISPLAY_NAME_PATTERN_KEY)) { + if (key.equals(ParameterizedInvocationNameFormatter.DISPLAY_NAME_PATTERN_KEY)) { invocations.incrementAndGet(); return Optional.of(""); } @@ -117,11 +125,15 @@ @Test void argumentsRethrowsOriginalExceptionFromProviderAsUncheckedException() { - ArgumentsProvider failingProvider = (context) -> { - throw new FileNotFoundException("a message"); + ArgumentsProvider failingProvider = new ArgumentsProvider() { + @Override + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) throws Exception { + throw new FileNotFoundException("a message"); + } }; - var exception = assertThrows(FileNotFoundException.class, () -> arguments(failingProvider, null)); + var exception = assertThrows(FileNotFoundException.class, () -> arguments(failingProvider, null, null)); assertEquals("a message", exception.getMessage()); } @@ -134,13 +146,32 @@ extensionContextWithAnnotatedTestMethod); // cause the stream to be evaluated stream.toArray(); - var exception = assertThrows(JUnitException.class, stream::close); + var exception = assertThrows(TemplateInvocationValidationException.class, stream::close); assertThat(exception).hasMessage( "Configuration error: You must configure at least one set of arguments for this @ParameterizedTest"); } @Test + void doesNotThrowExceptionWhenParametrizedTestDoesNotRequireArguments() { + var extensionContext = getExtensionContextReturningSingleMethod(new TestCaseAllowNoArgumentsMethod()); + + var stream = this.parameterizedTestExtension.provideTestTemplateInvocationContexts(extensionContext); + // cause the stream to be evaluated + stream.toArray(); + stream.close(); + } + + @Test + void throwsExceptionWhenParameterizedTestHasNoArgumentsSource() { + var extensionContext = getExtensionContextReturningSingleMethod(new TestCaseWithNoArgumentsSource()); + + assertThrows(PreconditionViolationException.class, + () -> this.parameterizedTestExtension.provideTestTemplateInvocationContexts(extensionContext), + "Configuration error: You must configure at least one arguments source for this @ParameterizedTest"); + } + + @Test void throwsExceptionWhenArgumentsProviderIsNotStatic() { var extensionContextWithAnnotatedTestMethod = getExtensionContextReturningSingleMethod( new NonStaticArgumentsProviderTestCase()); @@ -150,11 +181,14 @@ var exception = assertThrows(JUnitException.class, stream::toArray); - assertArgumentsProviderInstantiationException(exception, NonStaticArgumentsProvider.class); + assertThat(exception) // + .hasMessage(String.format( + "The ArgumentsProvider [%s] must be either a top-level class or a static nested class", + NonStaticArgumentsProvider.class.getName())); } @Test - void throwsExceptionWhenArgumentsProviderDoesNotContainNoArgumentConstructor() { + void throwsExceptionWhenArgumentsProviderDoesNotContainUnambiguousConstructor() { var extensionContextWithAnnotatedTestMethod = getExtensionContextReturningSingleMethod( new MissingNoArgumentsConstructorArgumentsProviderTestCase()); @@ -163,15 +197,11 @@ var exception = assertThrows(JUnitException.class, stream::toArray); - assertArgumentsProviderInstantiationException(exception, MissingNoArgumentsConstructorArgumentsProvider.class); - } - - private void assertArgumentsProviderInstantiationException(JUnitException exception, Class clazz) { - assertThat(exception).hasMessage( - String.format("Failed to find a no-argument constructor for ArgumentsProvider [%s]. " - + "Please ensure that a no-argument constructor exists and " - + "that the class is either a top-level class or a static nested class", - clazz.getName())); + String className = AmbiguousConstructorArgumentsProvider.class.getName(); + assertThat(exception) // + .hasMessage(String.format("Failed to find constructor for ArgumentsProvider [%s]. " + + "Please ensure that a no-argument or a single constructor exists.", + className)); } private ExtensionContext getExtensionContextReturningSingleMethod(Object testCase) { @@ -181,19 +211,17 @@ private ExtensionContext getExtensionContextReturningSingleMethod(Object testCase, Function> configurationSupplier) { - // @formatter:off - var optional = Arrays.stream(testCase.getClass().getDeclaredMethods()) - .filter(method -> method.getName().equals("method")) - .findFirst(); - // @formatter:on + Class testClass = testCase.getClass(); + var method = ReflectionUtils.findMethods(testClass, it -> "method".equals(it.getName())).stream().findFirst(); return new ExtensionContext() { - private final NamespacedHierarchicalStore store = new NamespacedHierarchicalStore<>(null); + private final NamespacedHierarchicalStore store = new NamespacedHierarchicalStore<>( + null); @Override public Optional getTestMethod() { - return optional; + return method; } @Override @@ -228,7 +256,12 @@ @Override public Optional> getTestClass() { - return Optional.empty(); + return Optional.of(testClass); + } + + @Override + public List> getEnclosingTestClasses() { + return List.of(); } @Override @@ -237,7 +270,7 @@ } @Override - public java.util.Optional getTestInstance() { + public Optional getTestInstance() { return Optional.empty(); } @@ -266,8 +299,27 @@ } @Override + public void publishFile(String fileName, MediaType mediaType, ThrowingConsumer action) { + } + + @Override + public void publishDirectory(String name, ThrowingConsumer action) { + } + + @Override public Store getStore(Namespace namespace) { - return new NamespaceAwareStore(store, namespace); + var store = new NamespaceAwareStore(this.store, + org.junit.platform.engine.support.store.Namespace.create(namespace.getParts())); + method // + .map(it -> new ParameterizedTestContext(testClass, it, + it.getAnnotation(ParameterizedTest.class))) // + .ifPresent(ctx -> store.put(DECLARATION_CONTEXT_KEY, ctx)); + return store; + } + + @Override + public Store getStore(StoreScope scope, Namespace namespace) { + return getStore(namespace); } @Override @@ -277,7 +329,17 @@ @Override public ExecutableInvoker getExecutableInvoker() { - return null; + return new ExecutableInvoker() { + @Override + public Object invoke(Method method, Object target) { + return null; + } + + @Override + public T invoke(Constructor constructor, Object outerInstance) { + return ReflectionUtils.newInstance(constructor); + } + }; } }; } @@ -294,10 +356,36 @@ static class TestCaseWithAnnotatedMethod { @ParameterizedTest + @ArgumentsSource(ZeroArgumentsProvider.class) + void method() { + } + } + + static class TestCaseAllowNoArgumentsMethod { + + @ParameterizedTest(allowZeroInvocations = true) + @ArgumentsSource(ZeroArgumentsProvider.class) void method() { } } + static class TestCaseWithNoArgumentsSource { + + @ParameterizedTest(allowZeroInvocations = true) + @SuppressWarnings("JUnitMalformedDeclaration") + void method() { + } + } + + static class ZeroArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { + return Stream.empty(); + } + } + static class ArgumentsProviderWithCloseHandlerTestCase { @ParameterizedTest @@ -309,7 +397,8 @@ static class ArgumentsProviderWithCloseHandler implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext context) { + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { var argumentsStream = Stream.of("foo", "bar").map(Arguments::of); return argumentsStream.onClose(() -> streamWasClosed = true); } @@ -326,7 +415,8 @@ class NonStaticArgumentsProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext context) { + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { return null; } } @@ -334,7 +424,7 @@ static class MissingNoArgumentsConstructorArgumentsProviderTestCase { @ParameterizedTest - @ArgumentsSource(MissingNoArgumentsConstructorArgumentsProvider.class) + @ArgumentsSource(AmbiguousConstructorArgumentsProvider.class) void method() { } } @@ -342,7 +432,7 @@ static class EmptyDisplayNameProviderTestCase { @ParameterizedTest(name = "") - @ArgumentsSource(MissingNoArgumentsConstructorArgumentsProvider.class) + @ArgumentsSource(AmbiguousConstructorArgumentsProvider.class) void method() { } } @@ -350,18 +440,22 @@ static class DefaultDisplayNameProviderTestCase { @ParameterizedTest - @ArgumentsSource(MissingNoArgumentsConstructorArgumentsProvider.class) + @ArgumentsSource(AmbiguousConstructorArgumentsProvider.class) void method() { } } - static class MissingNoArgumentsConstructorArgumentsProvider implements ArgumentsProvider { + static class AmbiguousConstructorArgumentsProvider implements ArgumentsProvider { + + AmbiguousConstructorArgumentsProvider(String parameter) { + } - MissingNoArgumentsConstructorArgumentsProvider(String parameter) { + AmbiguousConstructorArgumentsProvider(int parameter) { } @Override - public Stream provideArguments(ExtensionContext context) { + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { return null; } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,7 +14,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.within; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -23,8 +22,8 @@ import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.appendTestTemplateInvocationSegment; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForTestTemplateMethod; +import static org.junit.jupiter.params.converter.DefaultArgumentConverter.DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME; import static org.junit.jupiter.params.provider.Arguments.arguments; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectIteration; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; @@ -42,6 +41,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -81,15 +81,20 @@ import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.extension.AnnotatedElementContext; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.extension.TemplateInvocationValidationException; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.jupiter.engine.JupiterTestEngine; import org.junit.jupiter.params.ParameterizedTestIntegrationTests.RepeatableSourcesTestCase.Action; import org.junit.jupiter.params.aggregator.AggregateWith; import org.junit.jupiter.params.aggregator.ArgumentsAccessor; import org.junit.jupiter.params.aggregator.ArgumentsAggregationException; -import org.junit.jupiter.params.aggregator.ArgumentsAggregator; +import org.junit.jupiter.params.aggregator.SimpleArgumentsAggregator; import org.junit.jupiter.params.converter.ArgumentConversionException; import org.junit.jupiter.params.converter.ArgumentConverter; import org.junit.jupiter.params.converter.ConvertWith; @@ -105,25 +110,28 @@ import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.ClassUtils; -import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.testkit.engine.EngineExecutionResults; import org.junit.platform.testkit.engine.EngineTestKit; import org.junit.platform.testkit.engine.Event; +import org.junit.platform.testkit.engine.EventConditions; import org.opentest4j.TestAbortedException; /** * @since 5.0 */ -class ParameterizedTestIntegrationTests { +class ParameterizedTestIntegrationTests extends AbstractJupiterTestEngineTests { private final Locale originalLocale = Locale.getDefault(Locale.Category.FORMAT); @AfterEach - void restoreLocale() { + void reset() { Locale.setDefault(Locale.Category.FORMAT, originalLocale); + AutoCloseableArgument.closeCounter = 0; } @ParameterizedTest @@ -388,7 +396,7 @@ LifecycleTestCase.lifecycleEvents.clear(); LifecycleTestCase.testMethods.clear(); - var results = execute(selectClass(LifecycleTestCase.class)); + var results = executeTestsForClass(LifecycleTestCase.class); results.allEvents().assertThatEvents() // .haveExactly(1, event(test("test1"), displayName("[1] argument=foo"), finishedWithFailure(message("foo")))) // @@ -401,20 +409,20 @@ assertThat(LifecycleTestCase.lifecycleEvents).containsExactly( "beforeAll:ParameterizedTestIntegrationTests$LifecycleTestCase", "providerMethod", - "constructor:ParameterizedTestIntegrationTests$LifecycleTestCase", + "constructor:[1] argument=foo", "beforeEach:[1] argument=foo", testMethods.get(0) + ":[1] argument=foo", "afterEach:[1] argument=foo", - "constructor:ParameterizedTestIntegrationTests$LifecycleTestCase", + "constructor:[2] argument=bar", "beforeEach:[2] argument=bar", testMethods.get(0) + ":[2] argument=bar", "afterEach:[2] argument=bar", "providerMethod", - "constructor:ParameterizedTestIntegrationTests$LifecycleTestCase", + "constructor:[1] argument=foo", "beforeEach:[1] argument=foo", testMethods.get(1) + ":[1] argument=foo", "afterEach:[1] argument=foo", - "constructor:ParameterizedTestIntegrationTests$LifecycleTestCase", + "constructor:[2] argument=bar", "beforeEach:[2] argument=bar", testMethods.get(1) + ":[2] argument=bar", "afterEach:[2] argument=bar", @@ -425,7 +433,7 @@ @Test void truncatesArgumentsThatExceedMaxLength() { var results = EngineTestKit.engine(new JupiterTestEngine()) // - .configurationParameter(ParameterizedTestExtension.ARGUMENT_MAX_LENGTH_KEY, "2") // + .configurationParameter(ParameterizedInvocationNameFormatter.ARGUMENT_MAX_LENGTH_KEY, "2") // .selectors(selectMethod(TestCase.class, "testWithCsvSource", String.class.getName())) // .execute(); results.testEvents().assertThatEvents() // @@ -436,7 +444,7 @@ @Test void displayNamePatternFromConfiguration() { var results = EngineTestKit.engine(new JupiterTestEngine()) // - .configurationParameter(ParameterizedTestExtension.DISPLAY_NAME_PATTERN_KEY, "{index}") // + .configurationParameter(ParameterizedInvocationNameFormatter.DISPLAY_NAME_PATTERN_KEY, "{index}") // .selectors(selectMethod(TestCase.class, "testWithCsvSource", String.class.getName())) // .execute(); results.testEvents().assertThatEvents() // @@ -444,18 +452,88 @@ .haveExactly(1, event(displayName("2"), started())); } - private EngineExecutionResults execute(DiscoverySelector... selectors) { - return EngineTestKit.engine(new JupiterTestEngine()).selectors(selectors).execute(); + @Test + void failsWhenInvocationIsRequiredButNoArgumentSetsAreProvided() { + var results = execute(ZeroInvocationsTestCase.class, "testThatRequiresInvocations", String.class); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, + event(finishedWithFailure(instanceOf(TemplateInvocationValidationException.class), message( + "Configuration error: You must configure at least one set of arguments for this @ParameterizedTest")))); } - private EngineExecutionResults execute(Class testClass, String methodName, Class... methodParameterTypes) { - return execute(selectMethod(testClass, methodName, ClassUtils.nullSafeToString(methodParameterTypes))); + @Test + void doesNotFailWhenInvocationIsNotRequiredAndNoArgumentSetsAreProvided() { + var results = execute(ZeroInvocationsTestCase.class, "testThatDoesNotRequireInvocations", String.class); + + results.allEvents().assertStatistics(stats -> stats.started(3).succeeded(3)); + } + + @Test + void failsWhenNoArgumentsSourceIsDeclared() { + var results = execute(ZeroInvocationsTestCase.class, "testThatHasNoArgumentsSource", String.class); + + results.containerEvents().assertThatEvents() // + .haveExactly(1, // + event(displayName("testThatHasNoArgumentsSource(String)"), finishedWithFailure(message( + "Configuration error: You must configure at least one arguments source for this @ParameterizedTest")))); + } + + @Test + void executesWithDefaultLocaleConversionFormat() { + var results = execute(LocaleConversionTestCase.class, "testWithBcp47", Locale.class); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + @Test + void executesWithBcp47LocaleConversionFormat() { + var results = execute(Map.of(DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME, "bcp_47"), + LocaleConversionTestCase.class, "testWithBcp47", Locale.class); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + @Test + void executesWithIso639LocaleConversionFormat() { + var results = execute(Map.of(DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME, "iso_639"), + LocaleConversionTestCase.class, "testWithIso639", Locale.class); + + results.allEvents().assertStatistics(stats -> stats.started(4).succeeded(4)); + } + + @Test + void reportsExceptionInStaticInitializersWithoutInvocationCountValidation() { + var results = executeTestsForClass(ExceptionInStaticInitializerTestCase.class); + + var failure = results.containerEvents().stream() // + .filter(finishedWithFailure()::matches) // + .findAny() // + .orElseThrow(); + + var throwable = failure.getRequiredPayload(TestExecutionResult.class).getThrowable().orElseThrow(); + + assertThat(throwable) // + .isInstanceOf(ExceptionInInitializerError.class) // + .hasNoSuppressedExceptions(); + } + + private EngineExecutionResults execute(Map configurationParameters, Class testClass, + String methodName, Class... methodParameterTypes) { + return EngineTestKit.engine(new JupiterTestEngine()) // + .selectors(selectMethod(testClass, methodName, ClassUtils.nullSafeToString(methodParameterTypes))) // + .configurationParameters(configurationParameters) // + .execute(); } private EngineExecutionResults execute(String methodName, Class... methodParameterTypes) { return execute(TestCase.class, methodName, methodParameterTypes); } + private EngineExecutionResults execute(Class testClass, String methodName, Class... methodParameterTypes) { + return executeTests(selectMethod(testClass, methodName, ClassUtils.nullSafeToString(methodParameterTypes))); + } + /** * @since 5.4 */ @@ -491,7 +569,7 @@ finishedWithFailure(// instanceOf(PreconditionViolationException.class), // message(msg -> msg.matches( - "@NullSource cannot provide a null argument to method .+: the method does not declare any formal parameters."))))); + "@NullSource cannot provide a null argument to method .+: no formal parameters declared."))))); } @Test @@ -631,7 +709,7 @@ finishedWithFailure(// instanceOf(PreconditionViolationException.class), // message(msg -> msg.matches( - "@EmptySource cannot provide an empty argument to method .+: the method does not declare any formal parameters."))))); + "@EmptySource cannot provide an empty argument to method .+: no formal parameters declared."))))); } @ParameterizedTest(name = "{1}") @@ -874,7 +952,7 @@ /** * @since 5.9.1 - * @see https://github.com/junit-team/junit5/issues/3001 + * @see https://github.com/junit-team/junit-framework/issues/3001 */ @Test void duplicateMethodNames() { @@ -883,7 +961,7 @@ // other words, we're not really testing the support for @RepeatedTest // and @TestFactory, but their presence also contributes to the bug // reported in #3001. - ParameterizedTestIntegrationTests.this.execute(selectClass(DuplicateMethodNamesMethodSourceTestCase.class))// + executeTestsForClass(DuplicateMethodNamesMethodSourceTestCase.class)// .testEvents()// .assertStatistics(stats -> stats.started(8).failed(0).finished(8)); } @@ -1091,6 +1169,85 @@ } @Nested + class UnusedArgumentsWithStrictArgumentsCountIntegrationTests { + @Test + void failsWithArgumentsSourceProvidingUnusedArguments() { + var results = execute(ArgumentCountValidationMode.STRICT, UnusedArgumentsTestCase.class, + "testWithTwoUnusedStringArgumentsProvider", String.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message(String.format( + "Configuration error: @ParameterizedTest consumes 1 parameter but there were 2 arguments provided.%nNote: the provided arguments were [foo, unused1]"))))); + } + + @Test + void failsWithMethodSourceProvidingUnusedArguments() { + var results = execute(ArgumentCountValidationMode.STRICT, UnusedArgumentsTestCase.class, + "testWithMethodSourceProvidingUnusedArguments", String.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message(String.format( + "Configuration error: @ParameterizedTest consumes 1 parameter but there were 2 arguments provided.%nNote: the provided arguments were [foo, unused1]"))))); + } + + @Test + void failsWithCsvSourceUnusedArgumentsAndStrictArgumentCountValidationAnnotationAttribute() { + var results = execute(ArgumentCountValidationMode.NONE, UnusedArgumentsTestCase.class, + "testWithStrictArgumentCountValidation", String.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message(String.format( + "Configuration error: @ParameterizedTest consumes 1 parameter but there were 2 arguments provided.%nNote: the provided arguments were [foo, unused1]"))))); + } + + @Test + void failsWithCsvSourceUnusedArgumentsButExecutesRemainingArgumentsWhereThereIsNoUnusedArgument() { + var results = execute(ArgumentCountValidationMode.STRICT, UnusedArgumentsTestCase.class, + "testWithCsvSourceContainingDifferentNumbersOfArguments", String.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message(String.format( + "Configuration error: @ParameterizedTest consumes 1 parameter but there were 2 arguments provided.%nNote: the provided arguments were [foo, unused1]"))))) // + .haveExactly(1, + event(test(), displayName("[2] argument=bar"), finishedWithFailure(message("bar")))); + } + + @Test + void executesWithCsvSourceUnusedArgumentsAndArgumentCountValidationAnnotationAttribute() { + var results = execute(ArgumentCountValidationMode.NONE, UnusedArgumentsTestCase.class, + "testWithNoneArgumentCountValidation", String.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, + event(test(), displayName("[1] argument=foo"), finishedWithFailure(message("foo")))); + } + + @Test + void executesWithMethodSourceProvidingUnusedArguments() { + var results = execute(ArgumentCountValidationMode.STRICT, RepeatableSourcesTestCase.class, + "testWithRepeatableCsvSource", String.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(test(), displayName("[1] argument=a"), finishedWithFailure(message("a")))) // + .haveExactly(1, event(test(), displayName("[2] argument=b"), finishedWithFailure(message("b")))); + } + + @Test + void evaluatesArgumentsAtMostOnce() { + var results = execute(ArgumentCountValidationMode.STRICT, UnusedArgumentsTestCase.class, + "testWithEvaluationReportingArgumentsProvider", String.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(finishedWithFailure(message(String.format( + "Configuration error: @ParameterizedTest consumes 1 parameter but there were 2 arguments provided.%nNote: the provided arguments were [foo, unused]"))))); + results.allEvents().reportingEntryPublished().assertThatEvents() // + .haveExactly(1, event(EventConditions.reportEntry(Map.of("evaluated", "true")))); + } + + private EngineExecutionResults execute(ArgumentCountValidationMode configurationValue, Class javaClass, + String methodName, Class... methodParameterTypes) { + return EngineTestKit.engine(new JupiterTestEngine()) // + .selectors(selectMethod(javaClass, methodName, methodParameterTypes)) // + .configurationParameter(ArgumentCountValidator.ARGUMENT_COUNT_VALIDATION_KEY, + configurationValue.name().toLowerCase()) // + .execute(); + } + } + + @Nested class RepeatableSourcesIntegrationTests { @ParameterizedTest @@ -1199,13 +1356,31 @@ results.allEvents().assertThatEvents() // .haveExactly(1, event(test(), finishedSuccessfully())); - assertTrue(AutoCloseableArgument.isClosed); + assertEquals(2, AutoCloseableArgument.closeCounter); + } + + @Test + void doNotCloseAutoCloseableArgumentsAfterTestWhenDisabled() { + var results = execute("testWithAutoCloseableArgumentButDisabledCleanup", AutoCloseableArgument.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(test(), finishedSuccessfully())); + + assertEquals(0, AutoCloseableArgument.closeCounter); + } + + @Test + void closeAutoCloseableArgumentsAfterTestDespiteEarlyFailure() { + var results = execute(FailureInBeforeEachTestCase.class, "test", AutoCloseableArgument.class); + results.allEvents().assertThatEvents() // + .haveExactly(1, event(test(), finishedWithFailure(message("beforeEach")))); + + assertEquals(2, AutoCloseableArgument.closeCounter); } @Test void executesTwoIterationsBasedOnIterationAndUniqueIdSelector() { var methodId = uniqueIdForTestTemplateMethod(TestCase.class, "testWithThreeIterations(int)"); - var results = execute(selectUniqueId(appendTestTemplateInvocationSegment(methodId, 3)), + var results = executeTests(selectUniqueId(appendTestTemplateInvocationSegment(methodId, 3)), selectIteration(selectMethod(TestCase.class, "testWithThreeIterations", "int"), 1)); results.allEvents().assertThatEvents() // @@ -1214,6 +1389,31 @@ .haveExactly(1, event(test(), displayName("[3] argument=5"), finishedWithFailure())); } + @Nested + class SpiParameterInjectionIntegrationTests { + + @Test + void injectsParametersIntoArgumentsProviderConstructor() { + execute(SpiParameterInjectionTestCase.class, "argumentsProviderWithConstructorParameter", String.class) // + .testEvents() // + .assertStatistics(it -> it.succeeded(1)); + } + + @Test + void injectsParametersIntoArgumentConverterConstructor() { + execute(SpiParameterInjectionTestCase.class, "argumentConverterWithConstructorParameter", String.class) // + .testEvents() // + .assertStatistics(it -> it.succeeded(1)); + } + + @Test + void injectsParametersIntoArgumentsAggregatorConstructor() { + execute(SpiParameterInjectionTestCase.class, "argumentsAggregatorWithConstructorParameter", String.class) // + .testEvents() // + .assertStatistics(it -> it.succeeded(1)); + } + } + // ------------------------------------------------------------------------- static class TestCase { @@ -1305,7 +1505,13 @@ @ParameterizedTest @ArgumentsSource(AutoCloseableArgumentProvider.class) void testWithAutoCloseableArgument(AutoCloseableArgument autoCloseable) { - assertFalse(AutoCloseableArgument.isClosed); + assertEquals(0, AutoCloseableArgument.closeCounter); + } + + @ParameterizedTest(autoCloseArguments = false) + @ArgumentsSource(AutoCloseableArgumentProvider.class) + void testWithAutoCloseableArgumentButDisabledCleanup(AutoCloseableArgument autoCloseable) { + assertEquals(0, AutoCloseableArgument.closeCounter); } @ParameterizedTest @@ -1315,6 +1521,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class NullSourceTestCase { @ParameterizedTest @@ -1350,6 +1557,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class EmptySourceTestCase { @ParameterizedTest @@ -1505,6 +1713,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class NullAndEmptySourceTestCase { @ParameterizedTest @@ -1546,6 +1755,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(OrderAnnotation.class) static class MethodSourceTestCase { @@ -1726,7 +1936,7 @@ /** * @since 5.9.1 - * @see https://github.com/junit-team/junit5/issues/3001 + * @see https://github.com/junit-team/junit-framework/issues/3001 */ static class DuplicateMethodNamesMethodSourceTestCase { @@ -1977,6 +2187,41 @@ static Supplier> unusedArgumentsProviderField = // () -> Stream.of(arguments("foo", "unused1"), arguments("bar", "unused2")); + @ParameterizedTest(argumentCountValidation = ArgumentCountValidationMode.STRICT) + @CsvSource({ "foo, unused1" }) + void testWithStrictArgumentCountValidation(String argument) { + fail(argument); + } + + @ParameterizedTest(argumentCountValidation = ArgumentCountValidationMode.NONE) + @CsvSource({ "foo, unused1" }) + void testWithNoneArgumentCountValidation(String argument) { + fail(argument); + } + + @ParameterizedTest + @CsvSource({ "foo, unused1", "bar" }) + void testWithCsvSourceContainingDifferentNumbersOfArguments(String argument) { + fail(argument); + } + + @ParameterizedTest + @ArgumentsSource(EvaluationReportingArgumentsProvider.class) + void testWithEvaluationReportingArgumentsProvider(String argument) { + fail(argument); + } + + private static class EvaluationReportingArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { + return Stream.of(() -> { + context.publishReportEntry("evaluated", "true"); + return List.of("foo", "unused").toArray(); + }); + } + } } static class LifecycleTestCase { @@ -2117,6 +2362,7 @@ @interface TwoMethodSources { } + @SuppressWarnings("JUnitMalformedDeclaration") @ParameterizedTest @TwoMethodSources void testWithRepeatableMethodSourceAsMetaAnnotation(String argument) { @@ -2211,10 +2457,126 @@ } } + static class SpiParameterInjectionTestCase { + + @RegisterExtension + static final ParameterResolver spiParameterResolver = new ParameterResolver() { + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return parameterContext.getDeclaringExecutable() instanceof Constructor // + && String.class.equals(parameterContext.getParameter().getType()); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return "resolved value"; + } + }; + + @ParameterizedTest + @ArgumentsSource(ArgumentsProviderWithConstructorParameter.class) + void argumentsProviderWithConstructorParameter(String argument) { + assertEquals("resolved value", argument); + } + + @ParameterizedTest + @ValueSource(strings = "value") + void argumentConverterWithConstructorParameter( + @ConvertWith(ArgumentConverterWithConstructorParameter.class) String argument) { + assertEquals("resolved value", argument); + } + + @ParameterizedTest + @ValueSource(strings = "value") + void argumentsAggregatorWithConstructorParameter( + @AggregateWith(ArgumentsAggregatorWithConstructorParameter.class) String argument) { + assertEquals("resolved value", argument); + } + + record ArgumentsProviderWithConstructorParameter(String value) implements ArgumentsProvider { + + @Override + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { + return Stream.of(arguments(value)); + } + } + + record ArgumentConverterWithConstructorParameter(String value) implements ArgumentConverter { + + @Override + public Object convert(Object source, ParameterContext context) throws ArgumentConversionException { + return value; + } + } + + static class ArgumentsAggregatorWithConstructorParameter extends SimpleArgumentsAggregator { + + private final String value; + + public ArgumentsAggregatorWithConstructorParameter(String value) { + this.value = value; + } + + @Override + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException { + return this.value; + } + } + } + + static class ZeroInvocationsTestCase { + + @ParameterizedTest + @MethodSource("zeroArgumentsProvider") + void testThatRequiresInvocations(String argument) { + fail("This test should not be executed, because no arguments are provided."); + } + + @ParameterizedTest(allowZeroInvocations = true) + @MethodSource("zeroArgumentsProvider") + void testThatDoesNotRequireInvocations(String argument) { + fail("This test should not be executed, because no arguments are provided."); + } + + @ParameterizedTest(allowZeroInvocations = true) + @SuppressWarnings("JUnitMalformedDeclaration") + void testThatHasNoArgumentsSource(String argument) { + fail("This test should not be executed, because no arguments source is declared."); + } + + public static Stream zeroArgumentsProvider() { + return Stream.empty(); + } + } + + static class LocaleConversionTestCase { + + @ParameterizedTest + @ValueSource(strings = "en-US") + void testWithBcp47(Locale locale) { + assertEquals("en", locale.getLanguage()); + assertEquals("US", locale.getCountry()); + } + + @ParameterizedTest + @ValueSource(strings = "en-US") + void testWithIso639(Locale locale) { + assertEquals("en-us", locale.getLanguage()); + assertEquals("", locale.getCountry()); + } + + } + private static class TwoSingleStringArgumentsProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext context) { + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { return Stream.of(arguments("foo"), arguments("bar")); } } @@ -2222,7 +2584,8 @@ private static class TwoUnusedStringArgumentsProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext context) { + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { return Stream.of(arguments("foo", "unused1"), arguments("bar", "unused2")); } } @@ -2235,11 +2598,11 @@ } } - private static class StringAggregator implements ArgumentsAggregator { + private static class StringAggregator extends SimpleArgumentsAggregator { @Override - public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) - throws ArgumentsAggregationException { + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException { return accessor.getString(0) + accessor.getString(1); } } @@ -2255,18 +2618,19 @@ private static class AutoCloseableArgumentProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of(arguments(new AutoCloseableArgument())); + public Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context) { + return Stream.of(arguments(new AutoCloseableArgument(), Named.of("unused", new AutoCloseableArgument()))); } } static class AutoCloseableArgument implements AutoCloseable { - static boolean isClosed = false; + static int closeCounter = 0; @Override public void close() { - isClosed = true; + closeCounter++; } } @@ -2283,4 +2647,39 @@ } } + static class FailureInBeforeEachTestCase { + + @BeforeEach + void beforeEach() { + fail("beforeEach"); + } + + @ParameterizedTest + @ArgumentsSource(AutoCloseableArgumentProvider.class) + void test(AutoCloseableArgument autoCloseable) { + assertNotNull(autoCloseable); + assertEquals(0, AutoCloseableArgument.closeCounter); + } + } + + static class ExceptionInStaticInitializerTestCase { + + static { + //noinspection ConstantValue + if (true) + throw new RuntimeException("boom"); + } + + private static Stream getArguments() { + return Stream.of("foo", "bar"); + } + + @ParameterizedTest + @MethodSource("getArguments") + void test(String value) { + fail("should not be called: " + value); + } + + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.lang.reflect.Method; -import java.util.Arrays; - -import org.junit.jupiter.api.TestInfo; -import org.junit.jupiter.params.aggregator.AggregatorIntegrationTests.CsvToPerson; -import org.junit.jupiter.params.aggregator.AggregatorIntegrationTests.Person; -import org.junit.jupiter.params.aggregator.ArgumentsAccessor; -import org.junit.jupiter.params.provider.ValueSource; - -/** - * Unit tests for {@link ParameterizedTestMethodContext}. - * - * @since 5.2 - */ -class ParameterizedTestMethodContextTests { - - @ParameterizedTest - @ValueSource(strings = { "onePrimitive", "twoPrimitives", "twoAggregators", "twoAggregatorsWithTestInfoAtTheEnd", - "mixedMode" }) - void validSignatures(String name) { - assertTrue(new ParameterizedTestMethodContext(method(name)).hasPotentiallyValidSignature()); - } - - @ParameterizedTest - @ValueSource(strings = { "twoAggregatorsWithPrimitiveInTheMiddle", "twoAggregatorsWithTestInfoInTheMiddle" }) - void invalidSignatures(String name) { - assertFalse(new ParameterizedTestMethodContext(method(name)).hasPotentiallyValidSignature()); - } - - private Method method(String name) { - return Arrays.stream(getClass().getDeclaredMethods()) // - .filter(m -> m.getName().equals(name)) // - .findFirst() // - .orElseThrow(); - } - - // --- VALID --------------------------------------------------------------- - - void onePrimitive(int num) { - } - - void twoPrimitives(int num1, int num2) { - } - - void twoAggregators(@CsvToPerson Person person, ArgumentsAccessor arguments) { - } - - void twoAggregatorsWithTestInfoAtTheEnd(@CsvToPerson Person person1, @CsvToPerson Person person2, - TestInfo testInfo) { - } - - void mixedMode(int num1, int num2, ArgumentsAccessor arguments1, ArgumentsAccessor arguments2, - @CsvToPerson Person person1, @CsvToPerson Person person2, TestInfo testInfo1, TestInfo testInfo2) { - } - - // --- INVALID ------------------------------------------------------------- - - void twoAggregatorsWithPrimitiveInTheMiddle(@CsvToPerson Person person1, int num, @CsvToPerson Person person2) { - } - - void twoAggregatorsWithTestInfoInTheMiddle(@CsvToPerson Person person1, TestInfo testInfo, - @CsvToPerson Person person2) { - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,384 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENTS_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENTS_WITH_NAMES_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.ARGUMENT_SET_NAME_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.DEFAULT_DISPLAY_NAME; -import static org.junit.jupiter.params.ParameterizedTest.DISPLAY_NAME_PLACEHOLDER; -import static org.junit.jupiter.params.ParameterizedTest.INDEX_PLACEHOLDER; -import static org.junit.jupiter.params.provider.Arguments.argumentSet; -import static org.junit.jupiter.params.provider.Arguments.arguments; -import static org.mockito.Mockito.mock; - -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.sql.Date; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.ZoneId; -import java.util.Arrays; -import java.util.Locale; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtensionConfigurationException; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.params.aggregator.AggregateWith; -import org.junit.jupiter.params.aggregator.ArgumentsAccessor; -import org.junit.jupiter.params.aggregator.ArgumentsAggregator; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.util.ReflectionUtils; - -/** - * @since 5.0 - */ -class ParameterizedTestNameFormatterTests { - - private final Locale originalLocale = Locale.getDefault(); - - @AfterEach - void restoreLocale() { - Locale.setDefault(originalLocale); - } - - @Test - void formatsDisplayName() { - var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, "enigma"); - - assertEquals("enigma", format(formatter, 1, arguments())); - assertEquals("enigma", format(formatter, 2, arguments())); - } - - @Test - void formatsDisplayNameContainingApostrophe() { - String displayName = "display'Zero"; - var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, "display'Zero"); - - assertEquals(displayName, format(formatter, 1, arguments())); - assertEquals(displayName, format(formatter, 2, arguments())); - } - - @Test - void formatsDisplayNameContainingFormatElements() { - String displayName = "{enigma} {0} '{1}'"; - var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, displayName); - - assertEquals(displayName, format(formatter, 1, arguments())); - assertEquals(displayName, format(formatter, 2, arguments())); - } - - @Test - void formatsInvocationIndex() { - var formatter = formatter(INDEX_PLACEHOLDER, "enigma"); - - assertEquals("1", format(formatter, 1, arguments())); - assertEquals("2", format(formatter, 2, arguments())); - } - - @Test - void defaultDisplayName() { - var formatter = formatter(DEFAULT_DISPLAY_NAME, "IGNORED"); - - var formattedName = format(formatter, 1, arguments("apple", "banana")); - - assertThat(formattedName).isEqualTo("[1] apple, banana"); - } - - @Test - void formatsIndividualArguments() { - var formatter = formatter("{0} -> {1}", "enigma"); - - assertEquals("foo -> 42", format(formatter, 1, arguments("foo", 42))); - } - - @Test - void formatsCompleteArgumentsList() { - var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); - - // @formatter:off - Arguments args = arguments( - 42, - 99, - "enigma", - null, - new int[] { 1, 2, 3 }, - new String[] { "foo", "bar" }, - new Integer[][] { { 2, 4 }, { 3, 9 } } - ); - // @formatter:on - - assertEquals("42, 99, enigma, null, [1, 2, 3], [foo, bar], [[2, 4], [3, 9]]", format(formatter, 1, args)); - } - - @Test - void formatsCompleteArgumentsListWithNames() { - var testMethod = ParameterizedTestCases.getMethod("parameterizedTest", int.class, String.class, Object[].class); - var formatter = formatter(ARGUMENTS_WITH_NAMES_PLACEHOLDER, "enigma", testMethod); - - var formattedName = format(formatter, 1, arguments(42, "enigma", new Object[] { "foo", 1 })); - assertEquals("someNumber=42, someString=enigma, someArray=[foo, 1]", formattedName); - } - - @Test - void formatsCompleteArgumentsListWithoutNamesForAggregators() { - var testMethod = ParameterizedTestCases.getMethod("parameterizedTestWithAggregator", int.class, String.class); - var formatter = formatter(ARGUMENTS_WITH_NAMES_PLACEHOLDER, "enigma", testMethod); - - var formattedName = format(formatter, 1, arguments(42, "foo", "bar")); - assertEquals("someNumber=42, foo, bar", formattedName); - } - - @Test - void formatsCompleteArgumentsListWithArrays() { - var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); - - // Explicit test for https://github.com/junit-team/junit5/issues/814 - assertEquals("[foo, bar]", format(formatter, 1, arguments((Object) new String[] { "foo", "bar" }))); - - assertEquals("[foo, bar], 42, true", format(formatter, 1, arguments(new String[] { "foo", "bar" }, 42, true))); - } - - @Test - void formatsEverythingUsingCustomPattern() { - var pattern = DISPLAY_NAME_PLACEHOLDER + " " + INDEX_PLACEHOLDER + " :: " + ARGUMENTS_PLACEHOLDER + " :: {1}"; - var formatter = formatter(pattern, "enigma"); - - assertEquals("enigma 1 :: foo, bar :: bar", format(formatter, 1, arguments("foo", "bar"))); - assertEquals("enigma 2 :: foo, 42 :: 42", format(formatter, 2, arguments("foo", 42))); - } - - @Test - void formatDoesNotAlterArgumentsArray() { - Object[] actual = { 1, "two", Byte.valueOf("-128"), new Integer[][] { { 2, 4 }, { 3, 9 } } }; - var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); - var expected = Arrays.copyOf(actual, actual.length); - assertEquals("1, two, -128, [[2, 4], [3, 9]]", format(formatter, 1, arguments(actual))); - assertArrayEquals(expected, actual); - } - - @Test - void formatDoesNotRaiseAnArrayStoreException() { - var formatter = formatter("{0} -> {1}", "enigma"); - - Object[] arguments = new Number[] { 1, 2 }; - assertEquals("1 -> 2", format(formatter, 1, arguments(arguments))); - } - - @Test - void throwsReadableExceptionForInvalidPattern() { - var exception = assertThrows(JUnitException.class, () -> formatter("{index", "enigma")); - assertNotNull(exception.getCause()); - assertEquals(IllegalArgumentException.class, exception.getCause().getClass()); - } - - @Test - void formattingDoesNotFailIfArgumentToStringImplementationReturnsNull() { - var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); - - var formattedName = format(formatter, 1, arguments(new ToStringReturnsNull(), "foo")); - - assertThat(formattedName).isEqualTo("null, foo"); - } - - @Test - void formattingDoesNotFailIfArgumentToStringImplementationThrowsAnException() { - var formatter = formatter(ARGUMENTS_PLACEHOLDER, "enigma"); - - var formattedName = format(formatter, 1, arguments(new ToStringThrowsException(), "foo")); - - assertThat(formattedName).startsWith(ToStringThrowsException.class.getName() + "@"); - assertThat(formattedName).endsWith("foo"); - } - - @ParameterizedTest(name = "{0}") - @CsvSource(delimiter = '|', textBlock = """ - US | 42.23 is positive on 2019 Jan 13 at 12:34:56 - DE | 42,23 is positive on 13.01.2019 at 12:34:56 - """) - void customFormattingExpressionsAreSupported(Locale locale, String expectedValue) { - var pattern = "[{index}] {1,number,#.##} is {1,choice,0 format(formatter, 1, arguments())) - .havingCause() - .isExactlyInstanceOf(ExtensionConfigurationException.class) - .withMessage("When the display name pattern for a @ParameterizedTest contains %s, " - + "the arguments must be supplied as an ArgumentSet.", ARGUMENT_SET_NAME_PLACEHOLDER); - // @formatter:on - } - - @Test - void defaultDisplayName() { - var formatter = formatter(DEFAULT_DISPLAY_NAME, "IGNORED"); - - var formattedName = format(formatter, 42, argumentSet("Fruits", "apple", "banana")); - - assertThat(formattedName).isEqualTo("[42] Fruits"); - } - - @Test - void argumentSetNameAndArgumentsPlaceholders() { - var pattern = ARGUMENT_SET_NAME_PLACEHOLDER + " :: " + ARGUMENTS_PLACEHOLDER; - var formatter = formatter(pattern, "IGNORED"); - - var formattedName = format(formatter, -1, argumentSet("Fruits", "apple", "banana")); - - assertThat(formattedName).isEqualTo("Fruits :: apple, banana"); - } - - @Test - void mixedTypesOfArgumentsImplementationsAndCustomDisplayNamePattern() { - var pattern = "[%s] %s :: %s".formatted(INDEX_PLACEHOLDER, DISPLAY_NAME_PLACEHOLDER, - ARGUMENT_SET_NAME_OR_ARGUMENTS_WITH_NAMES_PLACEHOLDER); - var testMethod = ParameterizedTestCases.getMethod("processFruits", String.class, String.class); - var formatter = formatter(pattern, "Mixed Arguments Types", testMethod); - - var name1 = format(formatter, 1, argumentSet("Fruits", "apple", "banana")); - var name2 = format(formatter, 2, arguments("apple", "banana")); - - assertThat(name1).isEqualTo("[1] Mixed Arguments Types :: Fruits"); - assertThat(name2).isEqualTo("[2] Mixed Arguments Types :: fruit1=apple, fruit2=banana"); - } - - } - - // ------------------------------------------------------------------------- - - private static ParameterizedTestNameFormatter formatter(String pattern, String displayName) { - return formatter(pattern, displayName, 512); - } - - private static ParameterizedTestNameFormatter formatter(String pattern, String displayName, int argumentMaxLength) { - return new ParameterizedTestNameFormatter(pattern, displayName, mock(), argumentMaxLength); - } - - private static ParameterizedTestNameFormatter formatter(String pattern, String displayName, Method method) { - return new ParameterizedTestNameFormatter(pattern, displayName, new ParameterizedTestMethodContext(method), - 512); - } - - private static String format(ParameterizedTestNameFormatter formatter, int invocationIndex, Arguments arguments) { - return formatter.format(invocationIndex, arguments, arguments.get()); - } - - private static class ToStringReturnsNull { - - @Override - public String toString() { - return null; - } - } - - private static class ToStringThrowsException { - - @Override - public String toString() { - throw new RuntimeException("Boom!"); - } - } - - private static class ParameterizedTestCases { - - static Method getMethod(String methodName, Class... parameterTypes) { - return ReflectionUtils.findMethod(ParameterizedTestCases.class, methodName, parameterTypes).orElseThrow(); - } - - @SuppressWarnings("unused") - void parameterizedTest(int someNumber, String someString, Object[] someArray) { - } - - @SuppressWarnings("unused") - void parameterizedTestWithAggregator(int someNumber, - @AggregateWith(CustomAggregator.class) String someAggregatedString) { - } - - @SuppressWarnings("unused") - void processFruits(String fruit1, String fruit2) { - } - - private static class CustomAggregator implements ArgumentsAggregator { - @Override - public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) { - return accessor.get(0); - } - } - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestSuite.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestSuite.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/AggregatorIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/AggregatorIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/AggregatorIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/AggregatorIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -37,6 +37,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.AnnotatedElementContext; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.parallel.ResourceLock; @@ -278,27 +279,29 @@ @interface CsvToAddress { } - static class PersonAggregator implements ArgumentsAggregator { + static class PersonAggregator extends SimpleArgumentsAggregator { @Override - public Person aggregateArguments(ArgumentsAccessor arguments, ParameterContext context) { + protected Person aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) { int startIndex = context.findAnnotation(StartIndex.class).map(StartIndex::value).orElse(0); // @formatter:off return new Person( - arguments.getString(startIndex + 0), - arguments.getString(startIndex + 1), - arguments.get(startIndex + 2, LocalDate.class), - arguments.get(startIndex + 3, Gender.class) + accessor.getString(startIndex + 0), + accessor.getString(startIndex + 1), + accessor.get(startIndex + 2, LocalDate.class), + accessor.get(startIndex + 3, Gender.class) ); // @formatter:on } } - static class AddressAggregator implements ArgumentsAggregator { + static class AddressAggregator extends SimpleArgumentsAggregator { @Override - public Address aggregateArguments(ArgumentsAccessor arguments, ParameterContext context) { + public Address aggregateArguments(ArgumentsAccessor arguments, Class targetType, + AnnotatedElementContext context, int parameterIndex) { int startIndex = context.findAnnotation(StartIndex.class).map(StartIndex::value).orElse(0); // @formatter:off @@ -314,10 +317,11 @@ /** * Maps from String to length of String. */ - static class MapAggregator implements ArgumentsAggregator { + static class MapAggregator extends SimpleArgumentsAggregator { @Override - public Map aggregateArguments(ArgumentsAccessor arguments, ParameterContext context) { + protected Map aggregateArguments(ArgumentsAccessor arguments, Class targetType, + AnnotatedElementContext context, int parameterIndex) { // @formatter:off return IntStream.range(0, arguments.size()) .mapToObj(arguments::getString) @@ -326,19 +330,19 @@ } } - static class NullAggregator implements ArgumentsAggregator { + static class NullAggregator extends SimpleArgumentsAggregator { @Override - public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) { - Preconditions.condition(!context.getParameter().getType().isPrimitive(), - () -> "only supports reference types"); + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) { + Preconditions.condition(!targetType.isPrimitive(), () -> "only supports reference types"); return null; } } - static class ErroneousAggregator implements ArgumentsAggregator { + static class ErroneousAggregator extends SimpleArgumentsAggregator { @Override - public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) - throws ArgumentsAggregationException { + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException { throw new ArgumentsAggregationException("something went horribly wrong"); } } @@ -392,7 +396,7 @@ } } - static class InstanceCountingAggregator implements ArgumentsAggregator { + static class InstanceCountingAggregator extends SimpleArgumentsAggregator { static int instanceCount; InstanceCountingAggregator() { @@ -400,8 +404,8 @@ } @Override - public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) - throws ArgumentsAggregationException { + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException { return "enigma"; } } @@ -410,6 +414,7 @@ static final List output = new ArrayList<>(); + @SuppressWarnings("JUnitMalformedDeclaration") @ParameterizedTest @ValueSource(ints = { 1, 2, 3 }) void testWithCountingConverterAggregator(@ConvertWith(InstanceCountingConverter.class) int i, diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessorTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessorTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,15 +17,12 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import java.lang.reflect.Method; import java.util.Arrays; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.util.ReflectionUtils; /** * Unit tests for {@link DefaultArgumentsAccessor}. @@ -169,14 +166,9 @@ } private static DefaultArgumentsAccessor defaultArgumentsAccessor(int invocationIndex, Object... arguments) { - return new DefaultArgumentsAccessor(parameterContext(), invocationIndex, arguments); - } - - private static ParameterContext parameterContext() { - Method declaringExecutable = ReflectionUtils.findMethod(DefaultArgumentsAccessorTests.class, "foo").get(); - ParameterContext parameterContext = mock(); - when(parameterContext.getDeclaringExecutable()).thenReturn(declaringExecutable); - return parameterContext; + var context = mock(ExtensionContext.class); + var classLoader = DefaultArgumentsAccessorTests.class.getClassLoader(); + return DefaultArgumentsAccessor.create(context, invocationIndex, classLoader, arguments); } @SuppressWarnings("unused") diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,45 +12,31 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.params.converter.DefaultArgumentConverter.DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME; +import static org.junit.jupiter.params.converter.DefaultArgumentConverter.LocaleConversionFormat.BCP_47; +import static org.junit.jupiter.params.converter.DefaultArgumentConverter.LocaleConversionFormat.ISO_639; +import static org.junit.platform.commons.util.ClassLoaderUtils.getClassLoader; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.io.File; -import java.lang.Thread.State; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.URI; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.MonthDay; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.Period; -import java.time.Year; -import java.time.YearMonth; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.Currency; import java.util.Locale; -import java.util.UUID; -import java.util.concurrent.TimeUnit; +import java.util.Optional; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.support.conversion.ConversionException; import org.junit.platform.commons.test.TestClassLoader; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.util.ClassLoaderUtils; /** * Unit tests for {@link DefaultArgumentConverter}. @@ -59,6 +45,9 @@ */ class DefaultArgumentConverterTests { + private final ExtensionContext context = mock(); + private final DefaultArgumentConverter underTest = spy(new DefaultArgumentConverter(context)); + @Test void isAwareOfNull() { assertConverts(null, Object.class, null); @@ -92,266 +81,98 @@ assertConverts(1.0f, double.class, 1.0f); } - @Test - void convertsStringsToPrimitiveTypes() { - assertConverts("true", boolean.class, true); - assertConverts("false", boolean.class, false); - assertConverts("o", char.class, 'o'); - assertConverts("1", byte.class, (byte) 1); - assertConverts("1_0", byte.class, (byte) 10); - assertConverts("1", short.class, (short) 1); - assertConverts("1_2", short.class, (short) 12); - assertConverts("42", int.class, 42); - assertConverts("700_050_000", int.class, 700_050_000); - assertConverts("42", long.class, 42L); - assertConverts("4_2", long.class, 42L); - assertConverts("42.23", float.class, 42.23f); - assertConverts("42.2_3", float.class, 42.23f); - assertConverts("42.23", double.class, 42.23); - assertConverts("42.2_3", double.class, 42.23); - } - - @Test - void convertsStringsToPrimitiveWrapperTypes() { - assertConverts("true", Boolean.class, true); - assertConverts("false", Boolean.class, false); - assertConverts("o", Character.class, 'o'); - assertConverts("1", Byte.class, (byte) 1); - assertConverts("1_0", Byte.class, (byte) 10); - assertConverts("1", Short.class, (short) 1); - assertConverts("1_2", Short.class, (short) 12); - assertConverts("42", Integer.class, 42); - assertConverts("700_050_000", Integer.class, 700_050_000); - assertConverts("42", Long.class, 42L); - assertConverts("4_2", Long.class, 42L); - assertConverts("42.23", Float.class, 42.23f); - assertConverts("42.2_3", Float.class, 42.23f); - assertConverts("42.23", Double.class, 42.23); - assertConverts("42.2_3", Double.class, 42.23); - } - @ParameterizedTest(name = "[{index}] {0}") @ValueSource(classes = { char.class, boolean.class, short.class, byte.class, int.class, long.class, float.class, - double.class }) + double.class, void.class }) void throwsExceptionForNullToPrimitiveTypeConversion(Class type) { assertThatExceptionOfType(ArgumentConversionException.class) // .isThrownBy(() -> convert(null, type)) // .withMessage("Cannot convert null to primitive value of type " + type.getCanonicalName()); - } - @ParameterizedTest(name = "[{index}] {0}") - @ValueSource(classes = { Boolean.class, Character.class, Short.class, Byte.class, Integer.class, Long.class, - Float.class, Double.class }) - void throwsExceptionWhenConvertingTheWordNullToPrimitiveWrapperType(Class type) { - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert("null", type)) // - .withMessage("Failed to convert String \"null\" to type " + type.getCanonicalName()); - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert("NULL", type)) // - .withMessage("Failed to convert String \"NULL\" to type " + type.getCanonicalName()); + verify(underTest, never()).convert(any(), any(), any(ClassLoader.class)); } @Test - void throwsExceptionOnInvalidStringForPrimitiveTypes() { + void throwsExceptionForNonStringsConversion() { assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert("ab", char.class)) // - .withMessage("Failed to convert String \"ab\" to type char") // - .havingCause() // - .havingCause() // - .withMessage("String must have length of 1: ab"); - - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert("tru", boolean.class)) // - .withMessage("Failed to convert String \"tru\" to type boolean") // - .havingCause() // - .havingCause() // - .withMessage("String must be 'true' or 'false' (ignoring case): tru"); - - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert("null", boolean.class)) // - .withMessage("Failed to convert String \"null\" to type boolean") // - .havingCause() // - .havingCause() // - .withMessage("String must be 'true' or 'false' (ignoring case): null"); + .isThrownBy(() -> convert(new Enigma(), String.class)) // + .withMessage("No built-in converter for source type %s and target type java.lang.String", + Enigma.class.getName()); - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert("NULL", boolean.class)) // - .withMessage("Failed to convert String \"NULL\" to type boolean") // - .havingCause() // - .havingCause() // - .withMessage("String must be 'true' or 'false' (ignoring case): NULL"); + verify(underTest, never()).convert(any(), any(), any(ClassLoader.class)); } @Test - void throwsExceptionWhenImplicitConverstionIsUnsupported() { - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert("foo", Enigma.class)) // - .withMessage("No built-in converter for source type java.lang.String and target type %s", - Enigma.class.getName()); + void delegatesStringsConversion() { + doReturn(null).when(underTest).convert(any(), any(), any(ClassLoader.class)); - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert(new Enigma(), int[].class)) // - .withMessage("No built-in converter for source type %s and target type int[]", Enigma.class.getName()); + convert("value", int.class); - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert(new long[] {}, int[].class)) // - .withMessage("No built-in converter for source type long[] and target type int[]"); + verify(underTest).convert("value", int.class, getClassLoader(DefaultArgumentConverterTests.class)); + } - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert(new String[] {}, boolean.class)) // - .withMessage("No built-in converter for source type java.lang.String[] and target type boolean"); + @Test + void convertsLocaleWithDefaultFormat() { + when(context.getConfigurationParameter(eq(DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME), any())) // + .thenReturn(Optional.empty()); - assertThatExceptionOfType(ArgumentConversionException.class) // - .isThrownBy(() -> convert(Class.class, int[].class)) // - .withMessage("No built-in converter for source type java.lang.Class and target type int[]"); + assertConverts("en", Locale.class, Locale.ENGLISH); + assertConverts("en-US", Locale.class, Locale.US); } - /** - * @since 5.4 - */ @Test - @SuppressWarnings("OctalInteger") // We test parsing octal integers here as well as hex. - void convertsEncodedStringsToIntegralTypes() { - assertConverts("0x1f", byte.class, (byte) 0x1F); - assertConverts("-0x1F", byte.class, (byte) -0x1F); - assertConverts("010", byte.class, (byte) 010); - - assertConverts("0x1f00", short.class, (short) 0x1F00); - assertConverts("-0x1F00", short.class, (short) -0x1F00); - assertConverts("01000", short.class, (short) 01000); - - assertConverts("0x1f000000", int.class, 0x1F000000); - assertConverts("-0x1F000000", int.class, -0x1F000000); - assertConverts("010000000", int.class, 010000000); - - assertConverts("0x1f000000000", long.class, 0x1F000000000L); - assertConverts("-0x1F000000000", long.class, -0x1F000000000L); - assertConverts("0100000000000", long.class, 0100000000000L); + void convertsLocaleWithExplicitBcp47Format() { + when(context.getConfigurationParameter(eq(DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME), any())) // + .thenReturn(Optional.of(BCP_47)); + + assertConverts("en", Locale.class, Locale.ENGLISH); + assertConverts("en-US", Locale.class, Locale.US); } @Test - void convertsStringsToEnumConstants() { - assertConverts("DAYS", TimeUnit.class, TimeUnit.DAYS); - } + void delegatesLocaleConversionWithExplicitIso639Format() { + when(context.getConfigurationParameter(eq(DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME), any())) // + .thenReturn(Optional.of(ISO_639)); - // --- java.io and java.nio ------------------------------------------------ + doReturn(null).when(underTest).convert(any(), any(), any(ClassLoader.class)); - @Test - void convertsStringToCharset() { - assertConverts("ISO-8859-1", Charset.class, StandardCharsets.ISO_8859_1); - assertConverts("UTF-8", Charset.class, StandardCharsets.UTF_8); - } + convert("en", Locale.class); - @Test - void convertsStringToFile() { - assertConverts("file", File.class, new File("file")); - assertConverts("/file", File.class, new File("/file")); - assertConverts("/some/file", File.class, new File("/some/file")); + verify(underTest).convert("en", Locale.class, getClassLoader(DefaultArgumentConverterTests.class)); } @Test - void convertsStringToPath() { - assertConverts("path", Path.class, Paths.get("path")); - assertConverts("/path", Path.class, Paths.get("/path")); - assertConverts("/some/path", Path.class, Paths.get("/some/path")); - } + void throwsExceptionForDelegatedConversionFailure() { + ConversionException exception = new ConversionException("fail"); + doThrow(exception).when(underTest).convert(any(), any(), any(ClassLoader.class)); - // --- java.lang ----------------------------------------------------------- + assertThatExceptionOfType(ArgumentConversionException.class) // + .isThrownBy(() -> convert("value", int.class)) // + .withCause(exception) // + .withMessage(exception.getMessage()); - @Test - void convertsStringToClass() { - assertConverts("java.lang.Integer", Class.class, Integer.class); - assertConverts("java.lang.Thread$State", Class.class, State.class); - assertConverts("byte", Class.class, byte.class); - assertConverts("char[]", Class.class, char[].class); - assertConverts("java.lang.Long[][]", Class.class, Long[][].class); - assertConverts("[[[I", Class.class, int[][][].class); - assertConverts("[[Ljava.lang.String;", Class.class, String[][].class); + verify(underTest).convert("value", int.class, getClassLoader(DefaultArgumentConverterTests.class)); } @Test - void convertsStringToClassWithCustomTypeFromDifferentClassLoader() throws Exception { + void delegatesStringToClassWithCustomTypeFromDifferentClassLoaderConversion() throws Exception { String customTypeName = Enigma.class.getName(); try (var testClassLoader = TestClassLoader.forClasses(Enigma.class)) { var customType = testClassLoader.loadClass(customTypeName); assertThat(customType.getClassLoader()).isSameAs(testClassLoader); - var declaringExecutable = ReflectionUtils.findMethod(customType, "foo").get(); + var declaringExecutable = ReflectionSupport.findMethod(customType, "foo").orElseThrow(); assertThat(declaringExecutable.getDeclaringClass().getClassLoader()).isSameAs(testClassLoader); - var clazz = (Class) convert(customTypeName, Class.class, parameterContext(declaringExecutable)); + doReturn(customType).when(underTest).convert(any(), any(), any(ClassLoader.class)); + + var clazz = (Class) convert(customTypeName, Class.class, testClassLoader); assertThat(clazz).isNotEqualTo(Enigma.class); assertThat(clazz).isEqualTo(customType); assertThat(clazz.getClassLoader()).isSameAs(testClassLoader); - } - } - - // --- java.math ----------------------------------------------------------- - - @Test - void convertsStringToBigDecimal() { - assertConverts("123.456e789", BigDecimal.class, new BigDecimal("123.456e789")); - } - - @Test - void convertsStringToBigInteger() { - assertConverts("1234567890123456789", BigInteger.class, new BigInteger("1234567890123456789")); - } - // --- java.net ------------------------------------------------------------ - - @Test - void convertsStringToURI() { - assertConverts("https://docs.oracle.com/en/java/javase/12/", URI.class, - URI.create("https://docs.oracle.com/en/java/javase/12/")); - } - - @Test - void convertsStringToURL() throws Exception { - assertConverts("https://junit.org/junit5", URL.class, URI.create("https://junit.org/junit5").toURL()); - } - - // --- java.time ----------------------------------------------------------- - - @Test - void convertsStringsToJavaTimeInstances() { - assertConverts("PT1234.5678S", Duration.class, Duration.ofSeconds(1234, 567800000)); - assertConverts("1970-01-01T00:00:00Z", Instant.class, Instant.ofEpochMilli(0)); - assertConverts("2017-03-14", LocalDate.class, LocalDate.of(2017, 3, 14)); - assertConverts("2017-03-14T12:34:56.789", LocalDateTime.class, - LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)); - assertConverts("12:34:56.789", LocalTime.class, LocalTime.of(12, 34, 56, 789_000_000)); - assertConverts("--03-14", MonthDay.class, MonthDay.of(3, 14)); - assertConverts("2017-03-14T12:34:56.789Z", OffsetDateTime.class, - OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)); - assertConverts("12:34:56.789Z", OffsetTime.class, OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)); - assertConverts("P2M6D", Period.class, Period.of(0, 2, 6)); - assertConverts("2017", Year.class, Year.of(2017)); - assertConverts("2017-03", YearMonth.class, YearMonth.of(2017, 3)); - assertConverts("2017-03-14T12:34:56.789Z", ZonedDateTime.class, - ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)); - assertConverts("Europe/Berlin", ZoneId.class, ZoneId.of("Europe/Berlin")); - assertConverts("+02:30", ZoneOffset.class, ZoneOffset.ofHoursMinutes(2, 30)); - } - - // --- java.util ----------------------------------------------------------- - - @Test - void convertsStringToCurrency() { - assertConverts("JPY", Currency.class, Currency.getInstance("JPY")); - } - - @Test - @SuppressWarnings("deprecation") - void convertsStringToLocale() { - assertConverts("en", Locale.class, Locale.ENGLISH); - assertConverts("en_us", Locale.class, new Locale(Locale.US.toString())); - } - - @Test - void convertsStringToUUID() { - var uuid = "d043e930-7b3b-48e3-bdbe-5a3ccfb833db"; - assertConverts(uuid, UUID.class, UUID.fromString(uuid)); + verify(underTest).convert(customTypeName, Class.class, testClassLoader); + } } // ------------------------------------------------------------------------- @@ -362,25 +183,16 @@ assertThat(result) // .describedAs(input + " --(" + targetClass.getName() + ")--> " + expectedOutput) // .isEqualTo(expectedOutput); - } - private Object convert(Object input, Class targetClass) { - return convert(input, targetClass, parameterContext()); - } - - private Object convert(Object input, Class targetClass, ParameterContext parameterContext) { - return DefaultArgumentConverter.INSTANCE.convert(input, targetClass, parameterContext); + verify(underTest, never()).convert(any(), any(), any(ClassLoader.class)); } - private static ParameterContext parameterContext() { - Method declaringExecutable = ReflectionUtils.findMethod(DefaultArgumentConverterTests.class, "foo").get(); - return parameterContext(declaringExecutable); + private Object convert(Object input, Class targetClass) { + return convert(input, targetClass, ClassLoaderUtils.getClassLoader(getClass())); } - private static ParameterContext parameterContext(Method declaringExecutable) { - ParameterContext parameterContext = mock(); - when(parameterContext.getDeclaringExecutable()).thenReturn(declaringExecutable); - return parameterContext; + private Object convert(Object input, Class targetClass, ClassLoader classLoader) { + return underTest.convert(input, targetClass, classLoader); } @SuppressWarnings("unused") diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -110,10 +110,35 @@ assertThat(exception).hasMessage("Cannot convert to java.lang.Integer: 2017"); } + /** + * @since 5.12 + */ + @Test + void throwsExceptionOnNullParameterWithoutNullable() { + var exception = assertThrows(ArgumentConversionException.class, + () -> convert(null, "dd.MM.yyyy", LocalDate.class)); + + assertThat(exception).hasMessage( + "Cannot convert null to java.time.LocalDate; consider setting 'nullable = true'"); + } + + /** + * @since 5.12 + */ + @Test + void convertsNullableParameter() { + assertThat(convert(null, "dd.MM.yyyy", true, LocalDate.class)).isNull(); + } + private Object convert(Object input, String pattern, Class targetClass) { + return convert(input, pattern, false, targetClass); + } + + private Object convert(Object input, String pattern, boolean nullable, Class targetClass) { var converter = new JavaTimeArgumentConverter(); var annotation = mock(JavaTimeConversionPattern.class); when(annotation.value()).thenReturn(pattern); + when(annotation.nullable()).thenReturn(nullable); return converter.convert(input, targetClass, annotation); } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -29,8 +30,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; -import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.support.ReflectionSupport; /** * Tests for {@link TypedArgumentConverter}. @@ -49,12 +49,10 @@ */ @Test void preconditions() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> new StringLengthArgumentConverter(null, Integer.class))// + assertPreconditionViolationFor(() -> new StringLengthArgumentConverter(null, Integer.class))// .withMessage("sourceType must not be null"); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> new StringLengthArgumentConverter(String.class, null))// + assertPreconditionViolationFor(() -> new StringLengthArgumentConverter(String.class, null))// .withMessage("targetType must not be null"); } @@ -82,6 +80,26 @@ } @Test + void sourceTypeMismatchForArrayType() { + Parameter parameter = findParameterOfMethod("stringToByteArray", Byte[].class); + ParameterContext parameterContext = parameterContext(parameter); + assertThatExceptionOfType(ArgumentConversionException.class)// + .isThrownBy(() -> this.converter.convert(new String[][] {}, parameterContext))// + .withMessage("StringLengthArgumentConverter cannot convert objects of type [java.lang.String[][]]. " + + "Only source objects of type [java.lang.String] are supported."); + } + + @Test + void sourceTypeMismatchForPrimitiveArrayType() { + Parameter parameter = findParameterOfMethod("stringToByteArray", Byte[].class); + ParameterContext parameterContext = parameterContext(parameter); + assertThatExceptionOfType(ArgumentConversionException.class)// + .isThrownBy(() -> this.converter.convert(new byte[0], parameterContext))// + .withMessage("StringLengthArgumentConverter cannot convert objects of type [byte[]]. " + + "Only source objects of type [java.lang.String] are supported."); + } + + @Test void targetTypeMismatch() { Parameter parameter = findParameterOfMethod("stringToBoolean", Boolean.class); ParameterContext parameterContext = parameterContext(parameter); @@ -91,6 +109,26 @@ + "Only target type [java.lang.Integer] is supported."); } + @Test + void targetTypeMismatchForArrayType() { + Parameter parameter = findParameterOfMethod("stringToByteArray", Byte[].class); + ParameterContext parameterContext = parameterContext(parameter); + assertThatExceptionOfType(ArgumentConversionException.class)// + .isThrownBy(() -> this.converter.convert("enigma", parameterContext))// + .withMessage("StringLengthArgumentConverter cannot convert to type [java.lang.Byte[]]. " + + "Only target type [java.lang.Integer] is supported."); + } + + @Test + void targetTypeMismatchForPrimitiveArrayType() { + Parameter parameter = findParameterOfMethod("stringToPrimitiveByteArray", byte[].class); + ParameterContext parameterContext = parameterContext(parameter); + assertThatExceptionOfType(ArgumentConversionException.class)// + .isThrownBy(() -> this.converter.convert("enigma", parameterContext))// + .withMessage("StringLengthArgumentConverter cannot convert to type [byte[]]. " + + "Only target type [java.lang.Integer] is supported."); + } + private ParameterContext parameterContext(Parameter parameter) { ParameterContext parameterContext = mock(); when(parameterContext.getParameter()).thenReturn(parameter); @@ -98,13 +136,19 @@ } private Parameter findParameterOfMethod(String methodName, Class... parameterTypes) { - Method method = ReflectionUtils.findMethod(getClass(), methodName, parameterTypes).get(); + Method method = ReflectionSupport.findMethod(getClass(), methodName, parameterTypes).get(); return method.getParameters()[0]; } void stringToBoolean(Boolean b) { } + void stringToByteArray(Byte[] array) { + } + + void stringToPrimitiveByteArray(byte[] array) { + } + } /** diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -24,13 +24,16 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.support.ParameterDeclarations; @DisplayName("AnnotationBasedArgumentsProvider") class AnnotationBasedArgumentsProviderTests { private final AnnotationBasedArgumentsProvider annotationBasedArgumentsProvider = new AnnotationBasedArgumentsProvider<>() { @Override - protected Stream provideArguments(ExtensionContext context, CsvSource annotation) { + protected Stream provideArguments( + org.junit.jupiter.params.support.ParameterDeclarations parameters, ExtensionContext context, + CsvSource annotation) { return Stream.of(Arguments.of(annotation)); } }; @@ -46,18 +49,20 @@ @DisplayName("should invoke the provideArguments template method with the accepted annotation") void shouldInvokeTemplateMethodWithTheAnnotationProvidedToAccept() { var spiedProvider = spy(annotationBasedArgumentsProvider); + var parameters = mock(org.junit.jupiter.params.support.ParameterDeclarations.class); var extensionContext = mock(ExtensionContext.class); var annotation = csvSource("0", "1", "2"); annotationBasedArgumentsProvider.accept(annotation); - annotationBasedArgumentsProvider.provideArguments(extensionContext); + annotationBasedArgumentsProvider.provideArguments(parameters, extensionContext); - verify(spiedProvider, atMostOnce()).provideArguments(eq(extensionContext), eq(annotation)); + verify(spiedProvider, atMostOnce()).provideArguments(eq(parameters), eq(extensionContext), eq(annotation)); } @Test @DisplayName("should invoke the provideArguments template method for every accepted annotation") void shouldInvokeTemplateMethodForEachAnnotationProvided() { + var parameters = mock(ParameterDeclarations.class); var extensionContext = mock(ExtensionContext.class); var foo = csvSource("foo"); var bar = csvSource("bar"); @@ -65,7 +70,7 @@ annotationBasedArgumentsProvider.accept(foo); annotationBasedArgumentsProvider.accept(bar); - var arguments = annotationBasedArgumentsProvider.provideArguments(extensionContext).toList(); + var arguments = annotationBasedArgumentsProvider.provideArguments(parameters, extensionContext).toList(); assertThat(arguments).hasSize(2); assertThat(arguments.getFirst().get()[0]).isEqualTo(foo); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ArgumentsTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ArgumentsTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ArgumentsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ArgumentsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,14 +13,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.params.provider.MockCsvAnnotationBuilder.csvSource; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import static org.mockito.Mockito.mock; import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.PreconditionViolationException; /** * @since 5.0 @@ -40,8 +41,7 @@ void throwsExceptionIfNeitherValueNorTextBlockIsDeclared() { var annotation = csvSource().build(); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> provideArguments(annotation).findAny())// + assertPreconditionViolationFor(() -> provideArguments(annotation).findAny())// .withMessage("@CsvSource must be declared with either `value` or `textBlock` but not both"); } @@ -52,8 +52,7 @@ baz """).build(); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> provideArguments(annotation).findAny())// + assertPreconditionViolationFor(() -> provideArguments(annotation).findAny())// .withMessage("@CsvSource must be declared with either `value` or `textBlock` but not both"); } @@ -184,7 +183,7 @@ } @Test - void understandsEscapeCharactersWithCutomQuoteCharacter() { + void understandsEscapeCharactersWithCustomQuoteCharacter() { var annotation = csvSource().quoteCharacter('~').lines("~foo or ~~bar~~~, baz").build(); var arguments = provideArguments(annotation); @@ -223,8 +222,7 @@ void throwsExceptionIfBothDelimitersAreSimultaneouslySet() { var annotation = csvSource().delimiter('|').delimiterString("~~~").build(); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> provideArguments(annotation).findAny())// + assertPreconditionViolationFor(() -> provideArguments(annotation).findAny())// .withMessageStartingWith("The delimiter and delimiterString attributes cannot be set simultaneously in")// .withMessageContaining("CsvSource"); } @@ -309,8 +307,7 @@ void throwsExceptionWhenMaxCharsPerColumnIsNotPositiveNumberOrMinusOne(int maxCharsPerColumn) { var annotation = csvSource().lines("41").maxCharsPerColumn(maxCharsPerColumn).build(); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> provideArguments(annotation).findAny())// + assertPreconditionViolationFor(() -> provideArguments(annotation).findAny())// .withMessageStartingWith("maxCharsPerColumn must be a positive number or -1: " + maxCharsPerColumn); } @@ -373,16 +370,14 @@ banana, 2, BOOM! """).build(); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> provideArguments(annotation).findAny())// - .withMessage( - "The number of columns (3) exceeds the number of supplied headers (2) in CSV record: [banana, 2, BOOM!]"); + assertPreconditionViolationFor(() -> provideArguments(annotation).findAny()).withMessage( + "The number of columns (3) exceeds the number of supplied headers (2) in CSV record: [banana, 2, BOOM!]"); } private Stream provideArguments(CsvSource annotation) { var provider = new CsvArgumentsProvider(); provider.accept(annotation); - return provider.provideArguments(mock()).map(Arguments::get); + return provider.provideArguments(mock(), mock(ExtensionContext.class)).map(Arguments::get); } @SuppressWarnings("unchecked") diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvFileArgumentsProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvFileArgumentsProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvFileArgumentsProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/CsvFileArgumentsProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -544,7 +544,7 @@ var context = mock(ExtensionContext.class); when(context.getTestClass()).thenReturn(Optional.of(CsvFileArgumentsProviderTests.class)); doCallRealMethod().when(context).getRequiredTestClass(); - return provider.provideArguments(context).map(Arguments::get); + return provider.provideArguments(mock(), context).map(Arguments::get); } @SuppressWarnings("unchecked") diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,17 +12,22 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithTwoConstants.BAR; -import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithTwoConstants.FOO; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.BAR; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.BAZ; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.FOO; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.QUX; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.Arrays; +import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.provider.EnumSource.Mode; +import org.junit.jupiter.params.support.ParameterDeclaration; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.PreconditionViolationException; /** @@ -30,93 +35,164 @@ */ class EnumArgumentsProviderTests { - private ExtensionContext extensionContext = mock(); + final ParameterDeclarations parameters = mock(); + final ExtensionContext extensionContext = mock(); @Test void providesAllEnumConstants() { - var arguments = provideArguments(EnumWithTwoConstants.class); + var arguments = provideArguments(EnumWithFourConstants.class); - assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }); + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }, new Object[] { BAZ }, + new Object[] { QUX }); } @Test void provideSingleEnumConstant() { - var arguments = provideArguments(EnumWithTwoConstants.class, "FOO"); + var arguments = provideArguments(EnumWithFourConstants.class, "FOO"); assertThat(arguments).containsExactly(new Object[] { FOO }); } @Test void provideAllEnumConstantsWithNamingAll() { - var arguments = provideArguments(EnumWithTwoConstants.class, "FOO", "BAR"); + var arguments = provideArguments(EnumWithFourConstants.class, "FOO", "BAR"); assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }); } @Test void duplicateConstantNameIsDetected() { - Exception exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments(EnumWithTwoConstants.class, "FOO", "BAR", "FOO").findAny()); + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithFourConstants.class, "FOO", "BAR", "FOO").findAny()); assertThat(exception).hasMessageContaining("Duplicate enum constant name(s) found"); } @Test void invalidConstantNameIsDetected() { - Exception exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments(EnumWithTwoConstants.class, "FO0", "B4R").findAny()); + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithFourConstants.class, "FO0", "B4R").findAny()); assertThat(exception).hasMessageContaining("Invalid enum constant name(s) in"); } @Test void invalidPatternIsDetected() { - Exception exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments(EnumWithTwoConstants.class, Mode.MATCH_ALL, "(", ")").findAny()); + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithFourConstants.class, Mode.MATCH_ALL, "(", ")").findAny()); assertThat(exception).hasMessageContaining("Pattern compilation failed"); } @Test - void providesEnumConstantsBasedOnTestMethod() throws Exception { - when(extensionContext.getRequiredTestMethod()).thenReturn( - TestCase.class.getDeclaredMethod("methodWithCorrectParameter", EnumWithTwoConstants.class)); + void providesEnumConstantsBasedOnTestMethod() { + org.junit.jupiter.params.support.ParameterDeclaration firstParameterDeclaration = mock(); + when(firstParameterDeclaration.getParameterType()).thenAnswer(__ -> EnumWithFourConstants.class); + when(parameters.getFirst()).thenReturn(Optional.of(firstParameterDeclaration)); var arguments = provideArguments(NullEnum.class); - assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }); + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }, new Object[] { BAZ }, + new Object[] { QUX }); } @Test - void incorrectParameterTypeIsDetected() throws Exception { - when(extensionContext.getRequiredTestMethod()).thenReturn( - TestCase.class.getDeclaredMethod("methodWithIncorrectParameter", Object.class)); + void incorrectParameterTypeIsDetected() { + ParameterDeclaration firstParameterDeclaration = mock(); + when(firstParameterDeclaration.getParameterType()).thenAnswer(__ -> Object.class); + when(parameters.getFirst()).thenReturn(Optional.of(firstParameterDeclaration)); - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(NullEnum.class).findAny()); assertThat(exception).hasMessageStartingWith("First parameter must reference an Enum type"); } @Test - void methodsWithoutParametersAreDetected() throws Exception { - when(extensionContext.getRequiredTestMethod()).thenReturn( - TestCase.class.getDeclaredMethod("methodWithoutParameters")); + void methodsWithoutParametersAreDetected() { + when(parameters.getSourceElementDescription()).thenReturn("method"); - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(NullEnum.class).findAny()); - assertThat(exception).hasMessageStartingWith("Test method must declare at least one parameter"); + assertThat(exception).hasMessageStartingWith("There must be at least one declared parameter for method"); } - static class TestCase { - void methodWithCorrectParameter(EnumWithTwoConstants parameter) { - } + @Test + void providesEnumConstantsStartingFromBar() { + var arguments = provideArguments(EnumWithFourConstants.class, "BAR", "", Mode.INCLUDE); - void methodWithIncorrectParameter(Object parameter) { - } + assertThat(arguments).containsExactly(new Object[] { BAR }, new Object[] { BAZ }, new Object[] { QUX }); + } + + @Test + void providesEnumConstantsEndingAtBaz() { + var arguments = provideArguments(EnumWithFourConstants.class, "", "BAZ", Mode.INCLUDE); + + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }, new Object[] { BAZ }); + } + + @Test + void providesEnumConstantsFromBarToBaz() { + var arguments = provideArguments(EnumWithFourConstants.class, "BAR", "BAZ", Mode.INCLUDE); + + assertThat(arguments).containsExactly(new Object[] { BAR }, new Object[] { BAZ }); + } + + @Test + void providesEnumConstantsFromFooToBazWhileExcludingBar() { + var arguments = provideArguments(EnumWithFourConstants.class, "FOO", "BAZ", Mode.EXCLUDE, "BAR"); + + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAZ }); + } + + @Test + void providesNoEnumConstant() { + var arguments = provideArguments(EnumWithNoConstant.class); + + assertThat(arguments).isEmpty(); + } + + @Test + void invalidConstantNameIsDetectedInRange() { + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithFourConstants.class, "FOO", "BAZ", Mode.EXCLUDE, "QUX").findAny()); + assertThat(exception).hasMessageContaining("Invalid enum constant name(s) in"); + } + + @Test + void invalidStartingRangeIsDetected() { + var exception = assertThrows(IllegalArgumentException.class, + () -> provideArguments(EnumWithFourConstants.class, "B4R", "", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("No enum constant"); + } + + @Test + void invalidEndingRangeIsDetected() { + var exception = assertThrows(IllegalArgumentException.class, + () -> provideArguments(EnumWithFourConstants.class, "", "B4R", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("No enum constant"); + } + @Test + void invalidRangeOrderIsDetected() { + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithFourConstants.class, "BAR", "FOO", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("Invalid enum range"); + } + + @Test + void invalidRangeIsDetectedWhenEnumWithNoConstantIsProvided() { + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithNoConstant.class, "BAR", "FOO", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("No enum constant"); + } + + static class TestCase { void methodWithoutParameters() { } } - enum EnumWithTwoConstants { - FOO, BAR + enum EnumWithFourConstants { + FOO, BAR, BAZ, QUX + } + + enum EnumWithNoConstant { } private > Stream provideArguments(Class enumClass, String... names) { @@ -124,16 +200,24 @@ } private > Stream provideArguments(Class enumClass, Mode mode, String... names) { + return provideArguments(enumClass, "", "", mode, names); + } + + private > Stream provideArguments(Class enumClass, String from, String to, Mode mode, + String... names) { var annotation = mock(EnumSource.class); - when(annotation.value()).thenAnswer(invocation -> enumClass); - when(annotation.mode()).thenAnswer(invocation -> mode); - when(annotation.names()).thenAnswer(invocation -> names); - when(annotation.toString()).thenReturn(String.format("@EnumSource(value=%s.class, mode=%s, names=%s)", - enumClass.getSimpleName(), mode, Arrays.toString(names))); + when(annotation.value()).thenAnswer(__ -> enumClass); + when(annotation.from()).thenReturn(from); + when(annotation.to()).thenReturn(to); + when(annotation.mode()).thenReturn(mode); + when(annotation.names()).thenReturn(names); + when(annotation.toString()).thenReturn( + String.format("@EnumSource(value=%s.class, from=%s, to=%s, mode=%s, names=%s)", enumClass.getSimpleName(), + from, to, mode, Arrays.toString(names))); var provider = new EnumArgumentsProvider(); provider.accept(annotation); - return provider.provideArguments(extensionContext).map(Arguments::get); + return provider.provideArguments(parameters, extensionContext).map(Arguments::get); } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumSourceTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumSourceTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/FieldArgumentsProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/FieldArgumentsProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/FieldArgumentsProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/FieldArgumentsProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.engine.extension.MutableExtensionRegistry.createRegistryWithDefaultExtensions; -import static org.junit.platform.commons.util.ReflectionUtils.findMethod; +import static org.junit.platform.commons.support.ReflectionSupport.findMethod; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -34,10 +34,11 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.support.ParameterDeclarations; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.test.TestClassLoader; -import org.junit.platform.commons.util.ReflectionUtils; /** * Unit tests for {@link FieldArgumentsProvider}. @@ -466,7 +467,7 @@ // Ensure we have a non-null test method, even if it's not a real test method. // If this throws an exception, make sure that the supplied test class defines a "void test()" method. - Method testMethod = ReflectionUtils.findMethod(testClass, "test").get(); + Method testMethod = ReflectionSupport.findMethod(testClass, "test").get(); return provideArguments(testClass, testMethod, allowNonStaticMethod, fieldNames); } @@ -478,6 +479,7 @@ when(fieldSource.value()).thenReturn(fieldNames); + var parameters = mock(ParameterDeclarations.class); var extensionContext = mock(ExtensionContext.class); when(extensionContext.getTestClass()).thenReturn(Optional.of(testClass)); when(extensionContext.getTestMethod()).thenReturn(Optional.of(testMethod)); @@ -487,7 +489,7 @@ doCallRealMethod().when(extensionContext).getRequiredTestMethod(); doCallRealMethod().when(extensionContext).getRequiredTestClass(); - var testInstance = allowNonStaticMethod ? ReflectionUtils.newInstance(testClass) : null; + var testInstance = allowNonStaticMethod ? ReflectionSupport.newInstance(testClass) : null; when(extensionContext.getTestInstance()).thenReturn(Optional.ofNullable(testInstance)); var lifeCycle = allowNonStaticMethod ? Lifecycle.PER_CLASS : Lifecycle.PER_METHOD; @@ -495,7 +497,7 @@ var provider = new FieldArgumentsProvider(); provider.accept(fieldSource); - return provider.provideArguments(extensionContext).map(Arguments::get); + return provider.provideArguments(parameters, extensionContext).map(Arguments::get); } // ------------------------------------------------------------------------- diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -250,8 +250,8 @@ var arguments = provideArguments(testClass, false, fullyQualifiedMethodName); assertThat(arguments).containsExactly(array("string1"), array("string2")); - var factoryMethod = MethodArgumentsProvider.findFactoryMethodByFullyQualifiedName(testClass, testMethod, - fullyQualifiedMethodName); + var factoryMethod = MethodArgumentsProvider.findFactoryMethodByFullyQualifiedName(testClass, + Optional.of(testMethod), fullyQualifiedMethodName); assertThat(factoryMethod).isNotNull(); assertThat(factoryMethod.getName()).isEqualTo("stringsProvider"); assertThat(factoryMethod.getParameterTypes()).isEmpty(); @@ -759,7 +759,6 @@ when(extensionContext.getExecutableInvoker()).thenReturn( new DefaultExecutableInvoker(extensionContext, extensionRegistry)); - doCallRealMethod().when(extensionContext).getRequiredTestMethod(); doCallRealMethod().when(extensionContext).getRequiredTestClass(); var testInstance = allowNonStaticMethod ? ReflectionUtils.newInstance(testClass) : null; @@ -770,7 +769,7 @@ var provider = new MethodArgumentsProvider(); provider.accept(methodSource); - return provider.provideArguments(extensionContext).map(Arguments::get); + return provider.provideArguments(mock(), extensionContext).map(Arguments::get); } // ------------------------------------------------------------------------- diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MockCsvAnnotationBuilder.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MockCsvAnnotationBuilder.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MockCsvAnnotationBuilder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/MockCsvAnnotationBuilder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ValueArgumentsProviderTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ValueArgumentsProviderTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ValueArgumentsProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/ValueArgumentsProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,6 +18,7 @@ import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.platform.commons.PreconditionViolationException; /** @@ -160,7 +161,7 @@ var provider = new ValueArgumentsProvider(); provider.accept(annotation); - return provider.provideArguments(mock()).map(Arguments::get); + return provider.provideArguments(mock(), mock(ExtensionContext.class)).map(Arguments::get); } private static Object[] array(Object... objects) { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -23,17 +23,21 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.converter.AnnotationBasedArgumentConverter; import org.junit.jupiter.params.converter.JavaTimeConversionPattern; import org.junit.jupiter.params.provider.AnnotationBasedArgumentsProvider; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.FieldSource; import org.junit.platform.commons.JUnitException; @DisplayName("AnnotationConsumerInitializer") @@ -51,14 +55,15 @@ source -> assertThat(source.value()).containsExactly("a", "b")); } - @Test + @ParameterizedTest + @FieldSource("argumentsProviders") @DisplayName("should initialize annotation-based ArgumentsProvider") - void shouldInitializeAnnotationBasedArgumentsProvider() throws NoSuchMethodException { - var instance = new SomeAnnotationBasedArgumentsProvider(); + void shouldInitializeAnnotationBasedArgumentsProvider(AbstractAnnotationBasedArgumentsProvider instance) + throws NoSuchMethodException { var method = SubjectClass.class.getDeclaredMethod("foo"); var initialisedAnnotationConsumer = initialize(method, instance); - initialisedAnnotationConsumer.provideArguments(mock()).findAny(); + initialisedAnnotationConsumer.provideArguments(mock(), mock(ExtensionContext.class)).findAny(); assertThat(initialisedAnnotationConsumer.annotations) // .hasSize(1) // @@ -101,9 +106,11 @@ assertThatThrownBy(() -> initialize(parameter, instance)).isInstanceOf(JUnitException.class); } - @Test - void shouldInitializeForEachAnnotations() throws NoSuchMethodException { - var instance = spy(new SomeAnnotationBasedArgumentsProvider()); + @ParameterizedTest + @FieldSource("argumentsProviders") + void shouldInitializeForEachAnnotations(AbstractAnnotationBasedArgumentsProvider provider) + throws NoSuchMethodException { + var instance = spy(provider); var method = SubjectClass.class.getDeclaredMethod("repeatableAnnotation", String.class); initialize(method, instance); @@ -111,11 +118,32 @@ verify(instance, times(2)).accept(any(CsvSource.class)); } - private static class SomeAnnotationBasedArgumentsProvider extends AnnotationBasedArgumentsProvider { + static Supplier>> argumentsProviders = () -> List.of( // + Named.of("current", new SomeAnnotationBasedArgumentsProvider()), // + Named.of("deprecated", new DeprecatedAnnotationBasedArgumentsProvider()) // + ); + + private static abstract class AbstractAnnotationBasedArgumentsProvider + extends AnnotationBasedArgumentsProvider { List annotations = new ArrayList<>(); + } + + private static class SomeAnnotationBasedArgumentsProvider extends AbstractAnnotationBasedArgumentsProvider { + + @Override + protected Stream provideArguments(ParameterDeclarations parameters, + ExtensionContext context, CsvSource annotation) { + annotations.add(annotation); + return Stream.empty(); + } + } + + private static class DeprecatedAnnotationBasedArgumentsProvider extends AbstractAnnotationBasedArgumentsProvider { + @Override + @SuppressWarnings("deprecation") protected Stream provideArguments(ExtensionContext context, CsvSource annotation) { annotations.add(annotation); return Stream.empty(); diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/DeprecatedParameterInfoIntegrationTests.java jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/DeprecatedParameterInfoIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/DeprecatedParameterInfoIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/java/org/junit/jupiter/params/support/DeprecatedParameterInfoIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,114 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.params.support; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; +import org.junit.jupiter.params.Parameter; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * @since 5.13 + */ +class DeprecatedParameterInfoIntegrationTests extends AbstractJupiterTestEngineTests { + + @Test + void storesParameterInfoInExtensionContextStoreOnDifferentLevels() { + var results = executeTestsForClass(TestCase.class); + + results.allEvents().debug().assertStatistics(stats -> stats.started(7).succeeded(7)); + } + + @ParameterizedClass + @ValueSource(ints = 1) + @ExtendWith(ParameterInfoConsumingExtension.class) + record TestCase(int i) { + + @Nested + @ParameterizedClass + @ValueSource(ints = 2) + class Inner { + + @Parameter + int j; + + @ParameterizedTest + @ValueSource(ints = 3) + void test(int k) { + assertEquals(1, i); + assertEquals(2, j); + assertEquals(3, k); + } + } + } + + @SuppressWarnings("deprecation") + private static class ParameterInfoConsumingExtension + implements BeforeClassTemplateInvocationCallback, BeforeEachCallback { + + @Override + public void beforeClassTemplateInvocation(ExtensionContext parameterizedClassInvocationContext) { + if (TestCase.Inner.class.equals(parameterizedClassInvocationContext.getRequiredTestClass())) { + assertParameterInfo(parameterizedClassInvocationContext, "j", 2); + + var nestedParameterizedClassContext = parameterizedClassInvocationContext.getParent().orElseThrow(); + assertParameterInfo(nestedParameterizedClassContext, "i", 1); + + parameterizedClassInvocationContext = nestedParameterizedClassContext.getParent().orElseThrow(); + } + + assertParameterInfo(parameterizedClassInvocationContext, "i", 1); + + var outerParameterizedClassContext = parameterizedClassInvocationContext.getParent().orElseThrow(); + assertNull(ParameterInfo.get(outerParameterizedClassContext)); + } + + @Override + public void beforeEach(ExtensionContext parameterizedTestInvocationContext) { + assertParameterInfo(parameterizedTestInvocationContext, "k", 3); + + var parameterizedTestContext = parameterizedTestInvocationContext.getParent().orElseThrow(); + assertParameterInfo(parameterizedTestContext, "j", 2); + + var nestedParameterizedClassInvocationContext = parameterizedTestContext.getParent().orElseThrow(); + assertParameterInfo(nestedParameterizedClassInvocationContext, "j", 2); + + var nestedParameterizedClassContext = nestedParameterizedClassInvocationContext.getParent().orElseThrow(); + assertParameterInfo(nestedParameterizedClassContext, "i", 1); + + var outerParameterizedClassInvocationContext = nestedParameterizedClassContext.getParent().orElseThrow(); + assertParameterInfo(outerParameterizedClassInvocationContext, "i", 1); + + var outerParameterizedClassContext = outerParameterizedClassInvocationContext.getParent().orElseThrow(); + assertNull(ParameterInfo.get(outerParameterizedClassContext)); + } + + private static void assertParameterInfo(ExtensionContext context, String parameterName, int argumentValue) { + var parameterInfo = ParameterInfo.get(context); + assertNotNull(parameterInfo); + var declaration = parameterInfo.getDeclarations().get(0).orElseThrow(); + assertEquals(parameterName, declaration.getParameterName().orElseThrow()); + assertEquals(int.class, declaration.getParameterType()); + assertEquals(argumentValue, parameterInfo.getArguments().getInteger(0)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertTimeoutAssertionsTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertTimeoutAssertionsTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertTimeoutAssertionsTests.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertTimeoutAssertionsTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.api import org.junit.jupiter.api.AssertionTestUtils.assertMessageEquals @@ -155,6 +157,43 @@ assertMessageStartsWith(error, "Tempus Fugit ==> execution exceeded timeout of 10 ms by") } + @Test + fun `assertTimeout with value initialization in lambda`() { + val value: Int + + assertTimeout(ofMillis(500)) { value = 10 } + + assertEquals(10, value) + } + + @Test + fun `assertTimeout with message and value initialization in lambda`() { + val value: Int + + assertTimeout(ofMillis(500), "message") { value = 10 } + + assertEquals(10, value) + } + + @Test + fun `assertTimeout with message supplier and value initialization in lambda`() { + val value: Int + + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + val valueInMessageSupplier: Int + + assertTimeout( + timeout = ofMillis(500), + message = { + valueInMessageSupplier = 20 // Val can be assigned in the message supplier lambda. + "message" + }, + executable = { value = 10 } + ) + + assertEquals(10, value) + } + // -- executable - preemptively --- @Test @@ -287,6 +326,21 @@ assertMessageEquals(error, "Tempus Fugit ==> execution timed out after 10 ms") } + @Test + fun `assertTimeoutPreemptively with message supplier and value initialization in lambda`() { + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + val valueInMessageSupplier: Int + + assertTimeoutPreemptively( + timeout = ofMillis(500), + message = { + valueInMessageSupplier = 20 // Val can be assigned in the message supplier lambda. + "message" + }, + executable = {} + ) + } + /** * Take a nap for 100 milliseconds. */ diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertionsTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertionsTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertionsTests.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinAssertionsTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.api import kotlinx.coroutines.runBlocking @@ -247,6 +249,91 @@ assertMessageStartsWith(result, "Should be a String") } + @Test + fun `assertInstanceOf with compiler smart cast`() { + val maybeString: Any = "string" + + assertInstanceOf(maybeString) + assertFalse(maybeString.isEmpty()) // A smart cast to a String object. + } + + @Test + fun `assertInstanceOf with compiler nullable smart cast`() { + val maybeString: Any? = "string" + + assertInstanceOf(maybeString) + assertFalse(maybeString.isEmpty()) // A smart cast to a non-nullable String object. + } + + @Test + fun `assertInstanceOf with a null value`() { + val error = + assertThrows { + assertInstanceOf(null) + } + + assertMessageStartsWith(error, "Unexpected null value") + } + + @Test + fun `assertInstanceOf with message and compiler smart cast`() { + val maybeString: Any = "string" + + assertInstanceOf(maybeString, "maybeString is not an instance of String") + assertFalse(maybeString.isEmpty()) // A smart cast to a String object. + } + + @Test + fun `assertInstanceOf with message supplier and compiler smart cast`() { + val maybeString: Any = "string" + + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + val valueInMessageSupplier: Int + + assertInstanceOf(maybeString) { + valueInMessageSupplier = 20 // Val can be assigned in the message supplier lambda. + + "maybeString is not an instance of String" + } + + assertFalse(maybeString.isEmpty()) // A smart cast to a String object. + } + + @Test + fun `assertNull with compiler smart cast`() { + val nullableString: String? = null + + assertNull(nullableString) + // Even safe call is not allowed because compiler knows that nullableString is always null. + // nullableString?.isEmpty() + } + + @Test + fun `assertNull with message and compiler smart cast`() { + val nullableString: String? = null + + assertNull(nullableString, "nullableString is not null") + // Even safe call is not allowed because compiler knows that nullableString is always null. + // nullableString?.isEmpty() + } + + @Test + fun `assertNull with message supplier and compiler smart cast`() { + val nullableString: String? = null + + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + val valueInMessageSupplier: Int + + assertNull(nullableString) { + valueInMessageSupplier = 20 // Val can be assigned in the message supplier lambda. + + "nullableString is not null" + } + + // Even safe call is not allowed because compiler knows that nullableString is always null. + // nullableString?.isEmpty() + } + companion object { fun assertExpectedExceptionTypes( multipleFailuresError: MultipleFailuresError, diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinDynamicTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinDynamicTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinDynamicTests.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinDynamicTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + +package org.junit.jupiter.api + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.DynamicTest.dynamicTest +import java.math.BigDecimal +import java.math.BigDecimal.ONE +import java.math.MathContext +import java.math.BigInteger as BigInt +import java.math.RoundingMode as Rounding + +/** + * Unit tests for JUnit Jupiter [TestFactory] use in kotlin classes. + * + * @since 5.12 + */ +class KotlinDynamicTests { + @Nested + inner class SequenceReturningTestFactoryTests { + @TestFactory + fun `Dynamic tests returned as Kotlin sequence`() = + generateSequence(0) { it + 2 } + .map { dynamicTest("$it should be even") { assertEquals(0, it % 2) } } + .take(10) + + @TestFactory + fun `Consecutive fibonacci nr ratios, should converge to golden ratio as n increases`(): Sequence { + val scale = 5 + val goldenRatio = + (ONE + 5.toBigDecimal().sqrt(MathContext(scale + 10, Rounding.HALF_UP))) + .divide(2.toBigDecimal(), scale, Rounding.HALF_UP) + + fun shouldApproximateGoldenRatio( + cur: BigDecimal, + next: BigDecimal + ) = next.divide(cur, scale, Rounding.HALF_UP).let { + dynamicTest("$cur / $next = $it should approximate the golden ratio in $scale decimals") { + assertEquals(goldenRatio, it) + } + } + return generateSequence(BigInt.ONE to BigInt.ONE) { (cur, next) -> next to cur + next } + .map { (cur) -> cur.toBigDecimal() } + .zipWithNext(::shouldApproximateGoldenRatio) + .drop(14) + .take(10) + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinFailAssertionsTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinFailAssertionsTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinFailAssertionsTests.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/api/KotlinFailAssertionsTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.api import org.junit.jupiter.api.AssertEquals.assertEquals diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/ArbitraryNamingKotlinTestCase.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/ArbitraryNamingKotlinTestCase.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/ArbitraryNamingKotlinTestCase.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/ArbitraryNamingKotlinTestCase.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.engine.kotlin import org.junit.jupiter.api.Test diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerClassKotlinTestCase.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerClassKotlinTestCase.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerClassKotlinTestCase.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerClassKotlinTestCase.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.engine.kotlin import org.junit.jupiter.api.AfterAll diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerMethodKotlinTestCase.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerMethodKotlinTestCase.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerMethodKotlinTestCase.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/InstancePerMethodKotlinTestCase.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.engine.kotlin import org.junit.jupiter.api.AfterAll diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinDefaultImplsTestCase.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinDefaultImplsTestCase.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinDefaultImplsTestCase.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinDefaultImplsTestCase.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + +package org.junit.jupiter.engine.kotlin + +import org.junit.jupiter.api.Test + +class KotlinDefaultImplsTestCase { + @Suppress("JUnitMalformedDeclaration") + class DefaultImpls { + @Test + fun test() { + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceImplementationTestCase.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceImplementationTestCase.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceImplementationTestCase.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceImplementationTestCase.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + +package org.junit.jupiter.engine.kotlin + +class KotlinInterfaceImplementationTestCase : KotlinInterfaceTestCase diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceTestCase.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceTestCase.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceTestCase.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/engine/kotlin/KotlinInterfaceTestCase.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,21 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + +package org.junit.jupiter.engine.kotlin + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInfo + +interface KotlinInterfaceTestCase { + @Test + fun test(testInfo: TestInfo) { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedClassKotlinIntegrationTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedClassKotlinIntegrationTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedClassKotlinIntegrationTests.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedClassKotlinIntegrationTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + +package org.junit.jupiter.params + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInfo +import org.junit.jupiter.params.provider.ValueSource +import org.junit.platform.engine.discovery.DiscoverySelectors.selectClass +import org.junit.platform.testkit.engine.EngineTestKit + +class ParameterizedClassKotlinIntegrationTests { + @Test + fun supportsDataClasses() { + val results = + EngineTestKit + .engine("junit-jupiter") + .selectors(selectClass(TestCase::class.java)) + .execute() + + results.containerEvents().assertStatistics { + it.started(4).succeeded(4) + } + results.testEvents().assertStatistics { + it.started(4).succeeded(2).failed(2) + } + } + + @Suppress("JUnitMalformedDeclaration") + @ParameterizedClass + @ValueSource(ints = [-1, 1]) + data class TestCase( + val value: Int, + val testInfo: TestInfo + ) { + @Test + fun test1() { + assertEquals("test1()", testInfo.displayName) + assertTrue(value < 0, "negative") + } + + @Test + fun test2() { + assertEquals("test2()", testInfo.displayName) + assertTrue(value < 0, "negative") + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedInvocationNameFormatterIntegrationTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedInvocationNameFormatterIntegrationTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedInvocationNameFormatterIntegrationTests.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedInvocationNameFormatterIntegrationTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + +package org.junit.jupiter.params + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.TestInfo +import org.junit.jupiter.params.provider.ValueSource + +class ParameterizedInvocationNameFormatterIntegrationTests { + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest + fun defaultDisplayName( + param: String, + info: TestInfo + ) { + if (param.equals("foo")) { + assertEquals("[1] param=foo", info.displayName) + } else { + assertEquals("[2] param=bar", info.displayName) + } + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{0}") + fun `1st argument`( + param: String, + info: TestInfo + ) { + if (param.equals("foo")) { + assertEquals("foo", info.displayName) + } else { + assertEquals("bar", info.displayName) + } + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{displayName}") + fun `it's an {enigma} '{0}'`( + @Suppress("UNUSED_PARAMETER") param: String, + info: TestInfo + ) { + assertEquals("it's an {enigma} '{0}'(String, TestInfo)", info.displayName) + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{displayName} - {0}") + fun `displayName and 1st 'argument'`( + param: String, + info: TestInfo + ) { + if (param.equals("foo")) { + assertEquals("displayName and 1st 'argument'(String, TestInfo) - foo", info.displayName) + } else { + assertEquals("displayName and 1st 'argument'(String, TestInfo) - bar", info.displayName) + } + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{0} - {displayName}") + fun `1st 'argument' and displayName`( + param: String, + info: TestInfo + ) { + if (param.equals("foo")) { + assertEquals("foo - 1st 'argument' and displayName(String, TestInfo)", info.displayName) + } else { + assertEquals("bar - 1st 'argument' and displayName(String, TestInfo)", info.displayName) + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestKotlinSequenceIntegrationTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestKotlinSequenceIntegrationTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestKotlinSequenceIntegrationTests.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestKotlinSequenceIntegrationTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + + +package org.junit.jupiter.params + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.params.provider.Arguments.arguments +import org.junit.jupiter.params.provider.FieldSource +import org.junit.jupiter.params.provider.MethodSource +import java.time.Month + +/** + * Tests for Kotlin compatibility of ParameterizedTest + */ +object ParameterizedTestKotlinSequenceIntegrationTests { + @ParameterizedTest + @MethodSource("dataProvidedByKotlinSequenceMethod") + fun `a method source can be supplied by a Sequence-returning method`( + value: Int, + month: Month + ) { + assertEquals(value, month.value) + } + + @JvmStatic + private fun dataProvidedByKotlinSequenceMethod() = dataProvidedByKotlinSequenceField + + @JvmStatic + val dataProvidedByKotlinSequenceField = + sequenceOf( + arguments(1, Month.JANUARY), + arguments(3, Month.MARCH), + arguments(8, Month.AUGUST), + arguments(5, Month.MAY), + arguments(12, Month.DECEMBER) + ) + + @ParameterizedTest + @FieldSource("dataProvidedByKotlinSequenceField") + fun `a field source can be supplied by a Sequence-typed field`( + value: Int, + month: Month + ) { + assertEquals(value, month.value) + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestNameFormatterIntegrationTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestNameFormatterIntegrationTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestNameFormatterIntegrationTests.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/ParameterizedTestNameFormatterIntegrationTests.kt 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ -package org.junit.jupiter.params - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.TestInfo -import org.junit.jupiter.params.provider.ValueSource - -class ParameterizedTestNameFormatterIntegrationTests { - @ValueSource(strings = ["foo", "bar"]) - @ParameterizedTest - fun defaultDisplayName( - param: String, - info: TestInfo - ) { - if (param.equals("foo")) { - assertEquals("[1] foo", info.displayName) - } else { - assertEquals("[2] bar", info.displayName) - } - } - - @ValueSource(strings = ["foo", "bar"]) - @ParameterizedTest(name = "{0}") - fun `1st argument`( - param: String, - info: TestInfo - ) { - if (param.equals("foo")) { - assertEquals("foo", info.displayName) - } else { - assertEquals("bar", info.displayName) - } - } - - @ValueSource(strings = ["foo", "bar"]) - @ParameterizedTest(name = "{displayName}") - fun `it's an {enigma} '{0}'`( - @Suppress("UNUSED_PARAMETER") param: String, - info: TestInfo - ) { - assertEquals("it's an {enigma} '{0}'(String, TestInfo)", info.displayName) - } - - @ValueSource(strings = ["foo", "bar"]) - @ParameterizedTest(name = "{displayName} - {0}") - fun `displayName and 1st 'argument'`( - param: String, - info: TestInfo - ) { - if (param.equals("foo")) { - assertEquals("displayName and 1st 'argument'(String, TestInfo) - foo", info.displayName) - } else { - assertEquals("displayName and 1st 'argument'(String, TestInfo) - bar", info.displayName) - } - } - - @ValueSource(strings = ["foo", "bar"]) - @ParameterizedTest(name = "{0} - {displayName}") - fun `1st 'argument' and displayName`( - param: String, - info: TestInfo - ) { - if (param.equals("foo")) { - assertEquals("foo - 1st 'argument' and displayName(String, TestInfo)", info.displayName) - } else { - assertEquals("bar - 1st 'argument' and displayName(String, TestInfo)", info.displayName) - } - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessorKotlinTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessorKotlinTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessorKotlinTests.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/ArgumentsAccessorKotlinTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,17 +7,16 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package org.junit.jupiter.params.aggregator import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.api.extension.ParameterContext -import org.junit.platform.commons.util.ReflectionUtils +import org.junit.jupiter.api.extension.ExtensionContext import org.mockito.Mockito.mock -import org.mockito.Mockito.`when` -import java.lang.reflect.Method /** * Unit tests for using [ArgumentsAccessor] from Kotlin. @@ -56,13 +55,10 @@ fun defaultArgumentsAccessor( invocationIndex: Int, vararg arguments: Any - ): DefaultArgumentsAccessor = DefaultArgumentsAccessor(parameterContext(), invocationIndex, *arguments) - - fun parameterContext(): ParameterContext { - val declaringExecutable: Method = ReflectionUtils.findMethod(DefaultArgumentsAccessorTests::class.java, "foo").get() - val parameterContext: ParameterContext = mock() - `when`(parameterContext.declaringExecutable).thenReturn(declaringExecutable) - return parameterContext + ): DefaultArgumentsAccessor { + val context = mock(ExtensionContext::class.java) + val classLoader = ArgumentsAccessorKotlinTests::class.java.classLoader + return DefaultArgumentsAccessor.create(context, invocationIndex, classLoader, arguments) } fun foo() { diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/DisplayNameTests.kt jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/DisplayNameTests.kt --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/DisplayNameTests.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/kotlin/org/junit/jupiter/params/aggregator/DisplayNameTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + @file:Suppress("unused") package org.junit.jupiter.params.aggregator @@ -16,7 +18,7 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource -// https://github.com/junit-team/junit5/issues/1836 +// https://github.com/junit-team/junit-framework/issues/1836 object DisplayNameTests { @JvmStatic fun data() = @@ -35,6 +37,6 @@ number: Int, info: TestInfo ) { - assertEquals("[$number] $char, $number", info.displayName) + assertEquals("[$number] char=$char, number=$number", info.displayName) } } diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension 2026-06-21 20:26:05.000000000 +0000 @@ -1 +1,2 @@ org.junit.jupiter.engine.extension.ServiceLoaderExtension +org.junit.jupiter.engine.extension.ConfigLoaderExtension diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/resources/junit-platform.properties jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/junit-platform.properties --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/resources/junit-platform.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/junit-platform.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,4 @@ +junit.jupiter.extensions.autodetection.enabled=true + +junit.platform.output.capture.stdout=true +junit.platform.output.capture.stderr=true diff -Nru jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/resources/log4j2-test.xml jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/log4j2-test.xml --- jtreg8-8.1+1+ds1/junit5/jupiter-tests/src/test/resources/log4j2-test.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/jupiter-tests/src/test/resources/log4j2-test.xml 2026-06-21 20:26:05.000000000 +0000 @@ -9,10 +9,12 @@ + + - \ No newline at end of file + diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/platform-tests.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tests/platform-tests.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tests/platform-tests.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/platform-tests.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,4 +1,5 @@ -import org.gradle.api.tasks.PathSensitivity.NONE +import junitbuild.extensions.capitalized +import junitbuild.extensions.dependencyProject import org.gradle.api.tasks.PathSensitivity.RELATIVE import org.gradle.internal.os.OperatingSystem @@ -9,6 +10,18 @@ id("junitbuild.jmh-conventions") } +val processStarter by sourceSets.creating { + java { + srcDir("src/processStarter/java") + } +} + +java { + registerFeature(processStarter.name) { + usingSourceSet(processStarter) + } +} + val woodstox = configurations.dependencyScope("woodstox") val woodstoxRuntimeClasspath = configurations.resolvable("woodstoxRuntimeClasspath") { extendsFrom(configurations.testRuntimeClasspath.get()) @@ -33,26 +46,49 @@ testImplementation(testFixtures(projects.junitPlatformLauncher)) testImplementation(projects.junitJupiterEngine) testImplementation(testFixtures(projects.junitJupiterEngine)) + testImplementation(testFixtures(projects.junitJupiterParams)) testImplementation(libs.apiguardian) + testImplementation(libs.classgraph) testImplementation(libs.jfrunit) { exclude(group = "org.junit.vintage") } testImplementation(libs.joox) - testImplementation(libs.openTestReporting.tooling) + testImplementation(libs.openTestReporting.tooling.core) testImplementation(libs.picocli) testImplementation(libs.bundles.xmlunit) testImplementation(testFixtures(projects.junitJupiterApi)) + testImplementation(testFixtures(projects.junitPlatformReporting)) + testImplementation(projects.platformTests) { + capabilities { + requireFeature("process-starter") + } + } // --- Test run-time dependencies --------------------------------------------- - testRuntimeOnly(projects.junitVintageEngine) + val mavenizedProjects: List by rootProject + mavenizedProjects.filter { it.path != projects.junitPlatformConsoleStandalone.path }.forEach { + // Add all projects to the classpath for tests using classpath scanning + testRuntimeOnly(it) + } testRuntimeOnly(libs.groovy4) { because("`ReflectionUtilsTests.findNestedClassesWithInvalidNestedClassFile` needs it") } woodstox(libs.woodstox) - // --- https://openjdk.java.net/projects/code-tools/jmh/ ----------------------- + // --- https://openjdk.java.net/projects/code-tools/jmh/ ---------------------- jmh(projects.junitJupiterApi) jmh(libs.junit4) + + // --- ProcessStarter dependencies -------------------------------------------- + processStarter.implementationConfigurationName(libs.groovy4) { + because("it provides convenience methods to handle process output") + } + processStarter.implementationConfigurationName(libs.commons.io) { + because("it uses TeeOutputStream") + } + processStarter.implementationConfigurationName(libs.opentest4j) { + because("it throws TestAbortedException") + } } jmh { @@ -79,7 +115,6 @@ test { // Additional inputs for remote execution with Test Distribution inputs.dir("src/test/resources").withPathSensitivity(RELATIVE) - inputs.file(buildFile).withPathSensitivity(NONE) // for UniqueIdTrackingListenerIntegrationTests } test_4_12 { useJUnitPlatform { @@ -96,16 +131,22 @@ check { dependsOn(testWoodstox) } + named(processStarter.compileJavaTaskName).configure { + options.release = javaLibrary.testJavaVersion.majorVersion.toInt() + } + named("checkstyle${processStarter.name.capitalized()}").configure { + config = resources.text.fromFile(checkstyle.configDirectory.file("checkstyleMain.xml")) + } } eclipse { classpath { - plusConfigurations.add(projects.junitPlatformConsole.dependencyProject.configurations["shadowedClasspath"]) + plusConfigurations.add(dependencyProject(projects.junitPlatformConsole).configurations["shadowedClasspath"]) } } idea { module { - scopes["PROVIDED"]!!["plus"]!!.add(projects.junitPlatformConsole.dependencyProject.configurations["shadowedClasspath"]) + scopes["PROVIDED"]!!["plus"]!!.add(dependencyProject(projects.junitPlatformConsole).configurations["shadowedClasspath"]) } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/jmh/java/org/junit/jupiter/jmh/AssertionBenchmarks.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/jmh/java/org/junit/jupiter/jmh/AssertionBenchmarks.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/jmh/java/org/junit/jupiter/jmh/AssertionBenchmarks.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/jmh/java/org/junit/jupiter/jmh/AssertionBenchmarks.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/OutputFiles.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/OutputFiles.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/OutputFiles.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/OutputFiles.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.tests.process; + +import java.nio.file.Path; + +public record OutputFiles(Path stdOut, Path stdErr) { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessResult.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessResult.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessResult.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.tests.process; + +import java.util.List; + +public record ProcessResult(int exitCode, String stdOut, String stdErr) { + + public List stdOutLines() { + return stdOut.lines().toList(); + } + + public List stdErrLines() { + return stdErr.lines().toList(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessStarter.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessStarter.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessStarter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/ProcessStarter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,120 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.tests.process; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.stream.Stream; + +import org.apache.commons.io.output.TeeOutputStream; +import org.codehaus.groovy.runtime.ProcessGroovyMethods; + +public class ProcessStarter { + + public static final Charset OUTPUT_ENCODING = Charset.forName(System.getProperty("native.encoding")); + + private Path executable; + private Path workingDir; + private final List arguments = new ArrayList<>(); + private final Map environment = new LinkedHashMap<>(); + private Optional outputFiles = Optional.empty(); + + public ProcessStarter executable(Path executable) { + this.executable = executable; + return this; + } + + public ProcessStarter workingDir(Path workingDir) { + this.workingDir = workingDir; + return this; + } + + public ProcessStarter addArguments(String... arguments) { + this.arguments.addAll(List.of(arguments)); + return this; + } + + public ProcessStarter putEnvironment(String key, Path value) { + return putEnvironment(key, value.toAbsolutePath().toString()); + } + + public ProcessStarter putEnvironment(String key, String value) { + environment.put(key, value); + return this; + } + + public ProcessStarter putEnvironment(Map values) { + environment.putAll(values); + return this; + } + + public ProcessStarter redirectOutput(OutputFiles outputFiles) { + this.outputFiles = Optional.of(outputFiles); + return this; + } + + public ProcessResult startAndWait() throws InterruptedException { + return start().waitFor(); + } + + public WatchedProcess start() { + var command = Stream.concat(Stream.of(executable.toString()), arguments.stream()).toList(); + try { + var builder = new ProcessBuilder().command(command); + if (workingDir != null) { + builder.directory(workingDir.toFile()); + } + builder.environment().putAll(environment); + var process = builder.start(); + var out = forwardAndCaptureOutput(process, System.out, outputFiles.map(OutputFiles::stdOut), + ProcessGroovyMethods::consumeProcessOutputStream); + var err = forwardAndCaptureOutput(process, System.err, outputFiles.map(OutputFiles::stdErr), + ProcessGroovyMethods::consumeProcessErrorStream); + return new WatchedProcess(process, out, err); + } + catch (IOException e) { + throw new UncheckedIOException("Failed to start process: " + command, e); + } + } + + private static WatchedOutput forwardAndCaptureOutput(Process process, PrintStream delegate, + Optional outputFile, BiFunction captureAction) { + var capturingStream = new ByteArrayOutputStream(); + Optional fileStream = outputFile.map(path -> { + try { + return Files.newOutputStream(path); + } + catch (IOException e) { + throw new UncheckedIOException("Failed to open output file: " + path, e); + } + }); + var attachedStream = tee(delegate, fileStream.map(it -> tee(capturingStream, it)).orElse(capturingStream)); + var thread = captureAction.apply(process, attachedStream); + return new WatchedOutput(thread, capturingStream, fileStream); + } + + private static OutputStream tee(OutputStream out, OutputStream branch) { + return new TeeOutputStream(out, branch); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedOutput.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedOutput.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.tests.process; + +import static org.junit.platform.tests.process.ProcessStarter.OUTPUT_ENCODING; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.Optional; + +record WatchedOutput(Thread thread, ByteArrayOutputStream stream, Optional fileStream) { + + String streamAsString() { + return stream.toString(OUTPUT_ENCODING); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedProcess.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedProcess.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedProcess.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/WatchedProcess.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.tests.process; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Optional; + +public class WatchedProcess { + + private final Process process; + private final WatchedOutput out; + private final WatchedOutput err; + + WatchedProcess(Process process, WatchedOutput out, WatchedOutput err) { + this.process = process; + this.out = out; + this.err = err; + } + + ProcessResult waitFor() throws InterruptedException { + try { + int exitCode; + try { + try { + exitCode = process.waitFor(); + } + catch (InterruptedException e) { + process.destroyForcibly(); + throw e; + } + } + finally { + try { + out.thread().join(); + } + finally { + err.thread().join(); + } + } + return new ProcessResult(exitCode, out.streamAsString(), err.streamAsString()); + } + finally { + process.destroyForcibly(); + closeQuietly(out.fileStream()); + closeQuietly(err.fileStream()); + } + } + + private static void closeQuietly(Optional fileStream) { + if (fileStream.isEmpty()) { + return; + } + try { + fileStream.get().close(); + } + catch (IOException ignore) { + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/package-info.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/package-info.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/processStarter/java/org/junit/platform/tests/process/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,7 @@ +/** + * Utilities for working with processes. + * + * @since 1.12 + */ + +package org.junit.platform.tests.process; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/DefaultPackageTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/DefaultPackageTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/DefaultPackageTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/DefaultPackageTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,5 @@ - /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +7,7 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/api/condition/OSTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/api/condition/OSTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/api/condition/OSTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/api/condition/OSTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/Heavyweight.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/Heavyweight.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/Heavyweight.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/Heavyweight.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,7 +18,6 @@ import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolver; @@ -52,12 +51,12 @@ /** * Demo resource class. * - *

    The class implements interface {@link CloseableResource} + *

    The class implements interface {@link AutoCloseable} * and interface {@link AutoCloseable} to show and ensure that a single * {@link ResourceValue#close()} method implementation is needed to comply * with both interfaces. */ - static class ResourceValue implements Resource, CloseableResource, AutoCloseable { + static class ResourceValue implements Resource, AutoCloseable { static final AtomicInteger creations = new AtomicInteger(); private final AtomicInteger usages = new AtomicInteger(); @@ -80,7 +79,7 @@ } } - private static class CloseableOnlyOnceResource implements CloseableResource { + private static class CloseableOnlyOnceResource implements AutoCloseable { private final AtomicBoolean closed = new AtomicBoolean(); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/HeavyweightTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/HeavyweightTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/HeavyweightTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/jupiter/extensions/HeavyweightTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/AbstractEqualsAndHashCodeTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/AbstractEqualsAndHashCodeTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/AbstractEqualsAndHashCodeTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/AbstractEqualsAndHashCodeTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Abstract base class for unit tests that wish to test - * {@link Object#equals(Object)} and {@link Object#hashCode()}. - * - * @since 1.3 - */ -public abstract class AbstractEqualsAndHashCodeTests { - - protected final void assertEqualsAndHashCode(T equal1, T equal2, T different) { - assertThat(equal1).isNotNull(); - assertThat(equal2).isNotNull(); - assertThat(different).isNotNull(); - - assertThat(equal1).isNotSameAs(equal2); - assertThat(equal1).isNotNull(); - assertThat(equal1).isNotEqualTo(new Object()); - assertThat(equal1).isNotEqualTo(different); - assertThat(different).isNotEqualTo(equal1); - assertThat(different).isNotEqualTo(equal2); - assertThat(equal1.hashCode()).isNotEqualTo(different.hashCode()); - - assertThat(equal1).isEqualTo(equal1); - assertThat(equal1).isEqualTo(equal2); - assertThat(equal2).isEqualTo(equal1); - assertThat(equal1.hashCode()).isEqualTo(equal2.hashCode()); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/JUnitPlatformTestSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/JUnitPlatformTestSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/JUnitPlatformTestSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/JUnitPlatformTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -174,7 +174,7 @@ } private static Throwable getThrowable(EngineExecutionResults results) { - var failedTestEvent = results.testEvents().failed().list().get(0); + var failedTestEvent = results.testEvents().failed().list().getFirst(); var testResult = failedTestEvent.getRequiredPayload(TestExecutionResult.class); return testResult.getThrowable().orElseThrow(); } @@ -195,6 +195,7 @@ // ------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class FailingTestTestCase { @Test @@ -216,6 +217,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") static class FailingBeforeEachTestCase { @BeforeEach diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/TestEngineTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/TestEngineTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/TestEngineTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/TestEngineTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/annotation/TestableAnnotationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/annotation/TestableAnnotationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/annotation/TestableAnnotationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/annotation/TestableAnnotationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/function/TryTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/function/TryTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/function/TryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/function/TryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/AnnotationSupportTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/AnnotationSupportTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/AnnotationSupportTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/AnnotationSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,12 +14,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.platform.commons.support.PreconditionAssertions.assertPreconditionViolationException; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.List; import java.util.Optional; import org.junit.jupiter.api.Tag; @@ -36,8 +37,8 @@ @Test void isAnnotatedPreconditions() { var optional = Optional.of(Probe.class); - assertPreconditionViolationException("annotationType", () -> AnnotationSupport.isAnnotated(optional, null)); - assertPreconditionViolationException("annotationType", () -> AnnotationSupport.isAnnotated(Probe.class, null)); + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.isAnnotated(optional, null)); + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.isAnnotated(Probe.class, null)); } @Test @@ -59,8 +60,8 @@ @Test void findAnnotationOnElementPreconditions() { var optional = Optional.of(Probe.class); - assertPreconditionViolationException("annotationType", () -> AnnotationSupport.findAnnotation(optional, null)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotation(optional, null)); + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotation(Probe.class, null)); } @@ -80,16 +81,24 @@ AnnotationSupport.findAnnotation(element, Override.class)); } + @SuppressWarnings("deprecation") @Test - void findAnnotationOnClassPreconditions() { - assertPreconditionViolationException("annotationType", + void findAnnotationOnClassWithSearchModePreconditions() { + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotation(Probe.class, null, SearchOption.INCLUDE_ENCLOSING_CLASSES)); - assertPreconditionViolationException("SearchOption", - () -> AnnotationSupport.findAnnotation(Probe.class, Override.class, null)); + assertPreconditionViolationNotNullFor("SearchOption", + () -> AnnotationSupport.findAnnotation(Probe.class, Override.class, (SearchOption) null)); } @Test - void findAnnotationOnClassDelegates() { + void findAnnotationOnClassWithEnclosingInstanceTypesPreconditions() { + assertPreconditionViolationNotNullFor("enclosingInstanceTypes", + () -> AnnotationSupport.findAnnotation(Probe.class, Override.class, (List>) null)); + } + + @SuppressWarnings("deprecation") + @Test + void findAnnotationOnClassWithSearchModeDelegates() { Class clazz = Probe.class; assertEquals(AnnotationUtils.findAnnotation(clazz, Tag.class, false), AnnotationSupport.findAnnotation(clazz, Tag.class, SearchOption.DEFAULT)); @@ -112,12 +121,22 @@ } @Test + void findAnnotationOnClassWithEnclosingInstanceTypes() { + assertThat(AnnotationSupport.findAnnotation(Probe.class, Tag.class, List.of())) // + .contains(Probe.class.getDeclaredAnnotation(Tag.class)); + assertThat(AnnotationSupport.findAnnotation(Probe.InnerClass.class, Tag.class, List.of())) // + .isEmpty(); + assertThat(AnnotationSupport.findAnnotation(Probe.InnerClass.class, Tag.class, List.of(Probe.class))) // + .contains(Probe.class.getDeclaredAnnotation(Tag.class)); + } + + @Test void findPublicAnnotatedFieldsPreconditions() { - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> AnnotationSupport.findPublicAnnotatedFields(null, String.class, FieldMarker.class)); - assertPreconditionViolationException("fieldType", + assertPreconditionViolationNotNullFor("fieldType", () -> AnnotationSupport.findPublicAnnotatedFields(Probe.class, null, FieldMarker.class)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findPublicAnnotatedFields(Probe.class, String.class, null)); } @@ -131,11 +150,11 @@ @Test void findAnnotatedMethodsPreconditions() { - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> AnnotationSupport.findAnnotatedMethods(null, Tag.class, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotatedMethods(Probe.class, null, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("HierarchyTraversalMode", + assertPreconditionViolationNotNullFor("HierarchyTraversalMode", () -> AnnotationSupport.findAnnotatedMethods(Probe.class, Tag.class, null)); } @@ -175,7 +194,7 @@ @Test void findRepeatableAnnotationsPreconditions() { - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findRepeatableAnnotations(Probe.class, null)); } @@ -200,16 +219,16 @@ @Test void findAnnotatedFieldsPreconditions() { - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> AnnotationSupport.findAnnotatedFields(null, FieldMarker.class)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotatedFields(Probe.class, null)); - assertPreconditionViolationException("Class", () -> AnnotationSupport.findAnnotatedFields(null, Override.class, + assertPreconditionViolationNotNullFor("Class", () -> AnnotationSupport.findAnnotatedFields(null, Override.class, f -> true, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotatedFields(Probe.class, null, f -> true, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("HierarchyTraversalMode", + assertPreconditionViolationNotNullFor("HierarchyTraversalMode", () -> AnnotationSupport.findAnnotatedFields(Probe.class, Override.class, f -> true, null)); } @@ -251,28 +270,28 @@ @Test void findAnnotatedFieldValuesPreconditions() { - assertPreconditionViolationException("instance", + assertPreconditionViolationNotNullFor("instance", () -> AnnotationSupport.findAnnotatedFieldValues((Object) null, FieldMarker.class)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotatedFieldValues(this, null)); - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> AnnotationSupport.findAnnotatedFieldValues(null, FieldMarker.class)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotatedFieldValues(Probe.class, null)); - assertPreconditionViolationException("instance", + assertPreconditionViolationNotNullFor("instance", () -> AnnotationSupport.findAnnotatedFieldValues((Object) null, FieldMarker.class, Number.class)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotatedFieldValues(this, null, Number.class)); - assertPreconditionViolationException("fieldType", + assertPreconditionViolationNotNullFor("fieldType", () -> AnnotationSupport.findAnnotatedFieldValues(this, FieldMarker.class, null)); - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> AnnotationSupport.findAnnotatedFieldValues(null, FieldMarker.class, Number.class)); - assertPreconditionViolationException("annotationType", + assertPreconditionViolationNotNullFor("annotationType", () -> AnnotationSupport.findAnnotatedFieldValues(Probe.class, null, Number.class)); - assertPreconditionViolationException("fieldType", + assertPreconditionViolationNotNullFor("fieldType", () -> AnnotationSupport.findAnnotatedFieldValues(Probe.class, FieldMarker.class, null)); } @@ -301,6 +320,7 @@ void bMethod() { } + @SuppressWarnings("InnerClassMayBeStatic") class InnerClass { } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ClassSupportTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ClassSupportTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ClassSupportTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ClassSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.platform.commons.support; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.platform.commons.support.PreconditionAssertions.assertPreconditionViolationException; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; import java.util.List; import java.util.function.Function; @@ -27,7 +27,7 @@ @Test void nullSafeToStringPreconditions() { Function, ? extends String> mapper = null; - assertPreconditionViolationException("Mapping function", + assertPreconditionViolationNotNullFor("Mapping function", () -> ClassSupport.nullSafeToString(mapper, String.class, List.class)); } @@ -40,4 +40,5 @@ assertEquals(ClassUtils.nullSafeToString(classToStringMapper, String.class, List.class), ClassSupport.nullSafeToString(classToStringMapper, String.class, List.class)); } + } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ModifierSupportTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ModifierSupportTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ModifierSupportTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ModifierSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.platform.commons.support; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.platform.commons.support.PreconditionAssertions.assertPreconditionViolationException; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -36,8 +36,8 @@ @Test void isPublicPreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isPublic((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isPublic((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isPublic((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isPublic((Member) null)); } @Classes @@ -45,6 +45,7 @@ assertEquals(ReflectionUtils.isPublic(clazz), ModifierSupport.isPublic(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isPublicDelegates(Method method) { assertEquals(ReflectionUtils.isPublic(method), ModifierSupport.isPublic(method)); @@ -52,8 +53,8 @@ @Test void isPrivatePreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isPrivate((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isPrivate((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isPrivate((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isPrivate((Member) null)); } @Classes @@ -61,6 +62,7 @@ assertEquals(ReflectionUtils.isPrivate(clazz), ModifierSupport.isPrivate(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isPrivateDelegates(Method method) { assertEquals(ReflectionUtils.isPrivate(method), ModifierSupport.isPrivate(method)); @@ -68,8 +70,8 @@ @Test void isNotPrivatePreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isNotPrivate((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isNotPrivate((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isNotPrivate((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isNotPrivate((Member) null)); } @Classes @@ -77,6 +79,7 @@ assertEquals(ReflectionUtils.isNotPrivate(clazz), ModifierSupport.isNotPrivate(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isNotPrivateDelegates(Method method) { assertEquals(ReflectionUtils.isNotPrivate(method), ModifierSupport.isNotPrivate(method)); @@ -84,8 +87,8 @@ @Test void isAbstractPreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isAbstract((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isAbstract((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isAbstract((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isAbstract((Member) null)); } @Classes @@ -93,15 +96,33 @@ assertEquals(ReflectionUtils.isAbstract(clazz), ModifierSupport.isAbstract(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isAbstractDelegates(Method method) { assertEquals(ReflectionUtils.isAbstract(method), ModifierSupport.isAbstract(method)); } @Test + void isNotAbstractPreconditions() { + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isNotAbstract((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isNotAbstract((Member) null)); + } + + @Classes + void isNotAbstractDelegates(Class clazz) { + assertEquals(ReflectionUtils.isNotAbstract(clazz), ModifierSupport.isNotAbstract(clazz)); + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @Methods + void isNotAbstractDelegates(Method method) { + assertEquals(ReflectionUtils.isNotAbstract(method), ModifierSupport.isNotAbstract(method)); + } + + @Test void isStaticPreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isStatic((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isStatic((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isStatic((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isStatic((Member) null)); } @Classes @@ -109,6 +130,7 @@ assertEquals(ReflectionUtils.isStatic(clazz), ModifierSupport.isStatic(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isStaticDelegates(Method method) { assertEquals(ReflectionUtils.isStatic(method), ModifierSupport.isStatic(method)); @@ -116,8 +138,8 @@ @Test void isNotStaticPreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isNotStatic((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isNotStatic((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isNotStatic((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isNotStatic((Member) null)); } @Classes @@ -125,6 +147,7 @@ assertEquals(ReflectionUtils.isNotStatic(clazz), ModifierSupport.isNotStatic(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isNotStaticDelegates(Method method) { assertEquals(ReflectionUtils.isNotStatic(method), ModifierSupport.isNotStatic(method)); @@ -132,8 +155,8 @@ @Test void isFinalPreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isFinal((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isFinal((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isFinal((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isFinal((Member) null)); } @Classes @@ -141,6 +164,7 @@ assertEquals(ReflectionUtils.isFinal(clazz), ModifierSupport.isFinal(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isFinalDelegates(Method method) { assertEquals(ReflectionUtils.isFinal(method), ModifierSupport.isFinal(method)); @@ -148,8 +172,8 @@ @Test void isNotFinalPreconditions() { - assertPreconditionViolationException("Class", () -> ModifierSupport.isNotFinal((Class) null)); - assertPreconditionViolationException("Member", () -> ModifierSupport.isNotFinal((Member) null)); + assertPreconditionViolationNotNullFor("Class", () -> ModifierSupport.isNotFinal((Class) null)); + assertPreconditionViolationNotNullFor("Member", () -> ModifierSupport.isNotFinal((Member) null)); } @Classes @@ -157,6 +181,7 @@ assertEquals(ReflectionUtils.isNotFinal(clazz), ModifierSupport.isNotFinal(clazz)); } + @SuppressWarnings("JUnitMalformedDeclaration") @Methods void isNotFinalDelegates(Method method) { assertEquals(ReflectionUtils.isNotFinal(method), ModifierSupport.isNotFinal(method)); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/PreconditionAssertions.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/PreconditionAssertions.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/PreconditionAssertions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/PreconditionAssertions.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.support; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.function.Executable; -import org.junit.platform.commons.PreconditionViolationException; - -/** - * @since 1.4 - */ -class PreconditionAssertions { - - static void assertPreconditionViolationException(String name, Executable executable) { - var exception = assertThrows(PreconditionViolationException.class, executable); - assertEquals(name + " must not be null", exception.getMessage()); - } - - static void assertPreconditionViolationExceptionForString(String name, Executable executable) { - var exception = assertThrows(PreconditionViolationException.class, executable); - assertEquals(name + " must not be null or blank", exception.getMessage()); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,8 +14,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.platform.commons.support.PreconditionAssertions.assertPreconditionViolationException; -import static org.junit.platform.commons.support.PreconditionAssertions.assertPreconditionViolationExceptionForString; +import static org.junit.platform.commons.support.ReflectionSupport.toSupportResourcesList; +import static org.junit.platform.commons.support.ReflectionSupport.toSupportResourcesStream; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullOrBlankFor; +import static org.junit.platform.commons.util.ClassLoaderUtils.getDefaultClassLoader; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -29,6 +32,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.io.ResourceFilter; import org.junit.platform.commons.util.ReflectionUtils; /** @@ -37,7 +41,8 @@ class ReflectionSupportTests { private static final Predicate> allTypes = type -> true; - private static final Predicate allResources = type -> true; + @SuppressWarnings("deprecation") + private static final Predicate allResources = __ -> true; private static final Predicate allNames = name -> true; private static final Predicate allMethods = name -> true; private static final Predicate allFields = name -> true; @@ -56,8 +61,8 @@ @Test @SuppressWarnings("deprecation") void loadClassPreconditions() { - assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.loadClass(null)); - assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.loadClass("")); + assertPreconditionViolationNotNullOrBlankFor("Class name", () -> ReflectionSupport.loadClass(null)); + assertPreconditionViolationNotNullOrBlankFor("Class name", () -> ReflectionSupport.loadClass("")); } @Test @@ -72,8 +77,8 @@ @Test void tryToLoadClassPreconditions() { - assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.tryToLoadClass(null)); - assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.tryToLoadClass("")); + assertPreconditionViolationNotNullOrBlankFor("Class name", () -> ReflectionSupport.tryToLoadClass(null)); + assertPreconditionViolationNotNullOrBlankFor("Class name", () -> ReflectionSupport.tryToLoadClass("")); } /** @@ -98,10 +103,10 @@ void tryToLoadClassWithExplicitClassLoaderPreconditions() { var cl = getClass().getClassLoader(); - assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.tryToLoadClass(null, cl)); - assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.tryToLoadClass("", cl)); + assertPreconditionViolationNotNullOrBlankFor("Class name", () -> ReflectionSupport.tryToLoadClass(null, cl)); + assertPreconditionViolationNotNullOrBlankFor("Class name", () -> ReflectionSupport.tryToLoadClass("", cl)); - assertPreconditionViolationException("ClassLoader", () -> ReflectionSupport.tryToLoadClass("int", null)); + assertPreconditionViolationNotNullFor("ClassLoader", () -> ReflectionSupport.tryToLoadClass("int", null)); } @TestFactory @@ -119,20 +124,51 @@ return tests; } + /** + * @since 1.12 + */ + @SuppressWarnings("deprecation") + @Test + void tryToGetResourcesPreconditions() { + assertPreconditionViolationNotNullOrBlankFor("Resource name", () -> ReflectionSupport.tryToGetResources(null)); + assertPreconditionViolationNotNullOrBlankFor("Resource name", () -> ReflectionSupport.tryToGetResources("")); + assertPreconditionViolationNotNullFor("Class loader", + () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); + assertPreconditionViolationNotNullFor("Class loader", + () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); + } + + /** + * @since 1.12 + */ + @SuppressWarnings("deprecation") + @Test + void tryToGetResources() { + assertEquals( + ReflectionUtils.tryToGetResources("default-package.resource").toOptional().map( + ReflectionSupport::toSupportResourcesSet), + ReflectionSupport.tryToGetResources("default-package.resource").toOptional()); + assertEquals( + ReflectionUtils.tryToGetResources("default-package.resource", getDefaultClassLoader()).toOptional().map( + ReflectionSupport::toSupportResourcesSet), // + ReflectionSupport.tryToGetResources("default-package.resource", getDefaultClassLoader()).toOptional()); + } + @Test void findAllClassesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); - assertPreconditionViolationException("root", + assertPreconditionViolationNotNullFor("root", () -> ReflectionSupport.findAllClassesInClasspathRoot(null, allTypes, allNames)); - assertPreconditionViolationException("class predicate", + assertPreconditionViolationNotNullFor("class predicate", () -> ReflectionSupport.findAllClassesInClasspathRoot(path, null, allNames)); - assertPreconditionViolationException("name predicate", + assertPreconditionViolationNotNullFor("name predicate", () -> ReflectionSupport.findAllClassesInClasspathRoot(path, allTypes, null)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @TestFactory List findAllResourcesInClasspathRootDelegates() throws Throwable { List tests = new ArrayList<>(); @@ -141,9 +177,10 @@ paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); for (var path : paths) { var root = path.toUri(); - tests.add(DynamicTest.dynamicTest(createDisplayName(root), - () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources), - ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources)))); + tests.add(DynamicTest.dynamicTest(createDisplayName(root), () -> assertThat(toSupportResourcesList( + ReflectionUtils.findAllResourcesInClasspathRoot(root, ResourceFilter.of(__ -> true)))) // + .containsExactlyElementsOf( + ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources)))); } return tests; } @@ -151,18 +188,20 @@ /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); - assertPreconditionViolationException("root", + assertPreconditionViolationNotNullFor("root", () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); - assertPreconditionViolationException("resourceFilter", + assertPreconditionViolationNotNullFor("resourceFilter", () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @TestFactory List streamAllResourcesInClasspathRootDelegates() throws Throwable { List tests = new ArrayList<>(); @@ -171,9 +210,10 @@ paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); for (var path : paths) { var root = path.toUri(); - tests.add(DynamicTest.dynamicTest(createDisplayName(root), - () -> assertEquals(ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources).toList(), - ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources).toList()))); + tests.add(DynamicTest.dynamicTest(createDisplayName(root), () -> assertThat(toSupportResourcesStream( + ReflectionUtils.streamAllResourcesInClasspathRoot(root, ResourceFilter.of(__ -> true)))) // + .containsExactlyElementsOf( + ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources).toList()))); } return tests; } @@ -181,12 +221,13 @@ /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void streamAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); - assertPreconditionViolationException("root", + assertPreconditionViolationNotNullFor("root", () -> ReflectionSupport.streamAllResourcesInClasspathRoot(null, allResources)); - assertPreconditionViolationException("resourceFilter", + assertPreconditionViolationNotNullFor("resourceFilter", () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, null)); } @@ -199,55 +240,63 @@ @Test void findAllClassesInPackagePreconditions() { - assertPreconditionViolationExceptionForString("basePackageName", + assertPreconditionViolationNotNullOrBlankFor("basePackageName", () -> ReflectionSupport.findAllClassesInPackage(null, allTypes, allNames)); - assertPreconditionViolationException("class predicate", + assertPreconditionViolationNotNullFor("class predicate", () -> ReflectionSupport.findAllClassesInPackage("org.junit", null, allNames)); - assertPreconditionViolationException("name predicate", + assertPreconditionViolationNotNullFor("name predicate", () -> ReflectionSupport.findAllClassesInPackage("org.junit", allTypes, null)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void findAllResourcesInPackageDelegates() { assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources).size()); - assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources), + assertEquals( + toSupportResourcesList( + ReflectionUtils.findAllResourcesInPackage("org.junit", ResourceFilter.of(__ -> true))), ReflectionSupport.findAllResourcesInPackage("org.junit", allResources)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void findAllResourcesInPackagePreconditions() { - assertPreconditionViolationExceptionForString("basePackageName", + assertPreconditionViolationNotNullOrBlankFor("basePackageName", () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); - assertPreconditionViolationException("resourceFilter", + assertPreconditionViolationNotNullFor("resourceFilter", () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void streamAllResourcesInPackageDelegates() { assertNotEquals(0, ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources).count()); - assertEquals(ReflectionUtils.streamAllResourcesInPackage("org.junit", allResources).toList(), + assertEquals( + toSupportResourcesStream( + ReflectionUtils.streamAllResourcesInPackage("org.junit", ResourceFilter.of(__ -> true))).toList(), ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources).toList()); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void streamAllResourcesInPackagePreconditions() { - assertPreconditionViolationExceptionForString("basePackageName", + assertPreconditionViolationNotNullOrBlankFor("basePackageName", () -> ReflectionSupport.streamAllResourcesInPackage(null, allResources)); - assertPreconditionViolationException("resourceFilter", + assertPreconditionViolationNotNullFor("resourceFilter", () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", null)); } @@ -262,51 +311,58 @@ var exception = assertThrows(PreconditionViolationException.class, () -> ReflectionSupport.findAllClassesInModule(null, allTypes, allNames)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("class predicate", + assertPreconditionViolationNotNullFor("class predicate", () -> ReflectionSupport.findAllClassesInModule("org.junit.platform.commons", null, allNames)); - assertPreconditionViolationException("name predicate", + assertPreconditionViolationNotNullFor("name predicate", () -> ReflectionSupport.findAllClassesInModule("org.junit.platform.commons", allTypes, null)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void findAllResourcesInModuleDelegates() { - assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources), + assertEquals( + ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", ResourceFilter.of(__ -> true)), ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("Resource filter", + assertPreconditionViolationNotNullFor("resourceFilter", () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void streamAllResourcesInModuleDelegates() { - assertEquals(ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList(), + assertEquals( + toSupportResourcesStream(ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", + ResourceFilter.of(__ -> true))).toList(), ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList()); } /** * @since 1.11 */ + @SuppressWarnings("deprecation") @Test void streamAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, () -> ReflectionSupport.streamAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("Resource filter", + assertPreconditionViolationNotNullFor("resourceFilter", () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", null)); } @@ -318,10 +374,10 @@ @Test void newInstancePreconditions() { - assertPreconditionViolationException("Class", () -> ReflectionSupport.newInstance(null)); - assertPreconditionViolationException("Argument array", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.newInstance(null)); + assertPreconditionViolationNotNullFor("Argument array", () -> ReflectionSupport.newInstance(String.class, (Object[]) null)); - assertPreconditionViolationException("Individual arguments", + assertPreconditionViolationNotNullFor("Individual arguments", () -> ReflectionSupport.newInstance(String.class, new Object[] { null })); } @@ -334,7 +390,7 @@ @Test void invokeMethodPreconditions() throws Exception { - assertPreconditionViolationException("Method", () -> ReflectionSupport.invokeMethod(null, null, "true")); + assertPreconditionViolationNotNullFor("Method", () -> ReflectionSupport.invokeMethod(null, null, "true")); var method = Boolean.class.getMethod("toString"); var exception = assertThrows(PreconditionViolationException.class, @@ -357,15 +413,15 @@ @Test void findFieldsPreconditions() { - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.findFields(null, allFields, HierarchyTraversalMode.BOTTOM_UP)); - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.findFields(null, allFields, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("Predicate", + assertPreconditionViolationNotNullFor("Predicate", () -> ReflectionSupport.findFields(ReflectionSupportTests.class, null, HierarchyTraversalMode.BOTTOM_UP)); - assertPreconditionViolationException("Predicate", + assertPreconditionViolationNotNullFor("Predicate", () -> ReflectionSupport.findFields(ReflectionSupportTests.class, null, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("HierarchyTraversalMode", + assertPreconditionViolationNotNullFor("HierarchyTraversalMode", () -> ReflectionSupport.findFields(ReflectionSupportTests.class, allFields, null)); } @@ -382,7 +438,7 @@ @Test void tryToReadFieldValuePreconditions() throws Exception { - assertPreconditionViolationException("Field", () -> ReflectionSupport.tryToReadFieldValue(null, this)); + assertPreconditionViolationNotNullFor("Field", () -> ReflectionSupport.tryToReadFieldValue(null, this)); var instanceField = getClass().getDeclaredField("instanceField"); Exception exception = assertThrows(PreconditionViolationException.class, @@ -403,22 +459,22 @@ @Test void findMethodPreconditions() { - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.findMethod(null, "valueOf", String.class.getName())); - assertPreconditionViolationExceptionForString("Method name", + assertPreconditionViolationNotNullOrBlankFor("Method name", () -> ReflectionSupport.findMethod(Boolean.class, "", String.class.getName())); - assertPreconditionViolationExceptionForString("Method name", + assertPreconditionViolationNotNullOrBlankFor("Method name", () -> ReflectionSupport.findMethod(Boolean.class, " ", String.class.getName())); - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.findMethod(null, "valueOf", String.class)); - assertPreconditionViolationExceptionForString("Method name", + assertPreconditionViolationNotNullOrBlankFor("Method name", () -> ReflectionSupport.findMethod(Boolean.class, "", String.class)); - assertPreconditionViolationExceptionForString("Method name", + assertPreconditionViolationNotNullOrBlankFor("Method name", () -> ReflectionSupport.findMethod(Boolean.class, " ", String.class)); - assertPreconditionViolationException("Parameter types array", + assertPreconditionViolationNotNullFor("Parameter types array", () -> ReflectionSupport.findMethod(Boolean.class, "valueOf", (Class[]) null)); - assertPreconditionViolationException("Individual parameter types", + assertPreconditionViolationNotNullFor("Individual parameter types", () -> ReflectionSupport.findMethod(Boolean.class, "valueOf", new Class[] { null })); } @@ -436,15 +492,15 @@ @Test void findMethodsPreconditions() { - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.findMethods(null, allMethods, HierarchyTraversalMode.BOTTOM_UP)); - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.findMethods(null, allMethods, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("Predicate", + assertPreconditionViolationNotNullFor("Predicate", () -> ReflectionSupport.findMethods(ReflectionSupportTests.class, null, HierarchyTraversalMode.BOTTOM_UP)); - assertPreconditionViolationException("Predicate", + assertPreconditionViolationNotNullFor("Predicate", () -> ReflectionSupport.findMethods(ReflectionSupportTests.class, null, HierarchyTraversalMode.TOP_DOWN)); - assertPreconditionViolationException("HierarchyTraversalMode", + assertPreconditionViolationNotNullFor("HierarchyTraversalMode", () -> ReflectionSupport.findMethods(ReflectionSupportTests.class, allMethods, null)); } @@ -456,9 +512,9 @@ @Test void findNestedClassesPreconditions() { - assertPreconditionViolationException("Class", + assertPreconditionViolationNotNullFor("Class", () -> ReflectionSupport.findNestedClasses(null, ReflectionUtils::isStatic)); - assertPreconditionViolationException("Predicate", + assertPreconditionViolationNotNullFor("Predicate", () -> ReflectionSupport.findNestedClasses(ClassWithNestedClasses.class, null)); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceInteroperabilityTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceInteroperabilityTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceInteroperabilityTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceInteroperabilityTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support; + +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + +import java.net.URI; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.io.Resource; + +public class ResourceInteroperabilityTests { + + @Test + void newAndOldResourcesAreLogicallyEquivalent() { + var oldResource = new DefaultResource("foo", URI.create("foo")); + var newResource = Resource.of("foo", URI.create("foo")); + var differentResource = Resource.of("foo", URI.create("bar")); + + assertEqualsAndHashCode(oldResource, newResource, differentResource); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceSupportTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceSupportTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceSupportTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/ResourceSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,225 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullFor; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationNotNullOrBlankFor; +import static org.junit.platform.commons.util.ClassLoaderUtils.getDefaultClassLoader; + +import java.net.URI; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.io.ResourceFilter; +import org.junit.platform.commons.util.ReflectionUtils; + +class ResourceSupportTests { + + private static final ResourceFilter allResources = ResourceFilter.of(__ -> true); + + /** + * @since 1.12 + */ + @SuppressWarnings("DataFlowIssue") + @Test + void tryToGetResourcesPreconditions() { + assertPreconditionViolationNotNullOrBlankFor("Resource name", () -> ResourceSupport.tryToGetResources(null)); + assertPreconditionViolationNotNullOrBlankFor("Resource name", () -> ResourceSupport.tryToGetResources("")); + assertPreconditionViolationNotNullFor("Class loader", + () -> ResourceSupport.tryToGetResources("default-package.resource", null)); + assertPreconditionViolationNotNullFor("Class loader", + () -> ResourceSupport.tryToGetResources("default-package.resource", null)); + } + + /** + * @since 1.12 + */ + @Test + void tryToGetResources() { + assertEquals(ReflectionUtils.tryToGetResources("default-package.resource").toOptional(), + ResourceSupport.tryToGetResources("default-package.resource").toOptional()); + assertEquals( + ReflectionUtils.tryToGetResources("default-package.resource", getDefaultClassLoader()).toOptional(), // + ResourceSupport.tryToGetResources("default-package.resource", getDefaultClassLoader()).toOptional()); + } + + /** + * @since 1.11 + */ + @TestFactory + List findAllResourcesInClasspathRootDelegates() throws Throwable { + List tests = new ArrayList<>(); + List paths = new ArrayList<>(); + paths.add(Path.of(".").toRealPath()); + paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); + for (var path : paths) { + var root = path.toUri(); + tests.add(DynamicTest.dynamicTest(createDisplayName(root), + () -> assertThat(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources)) // + .containsExactlyElementsOf( + ResourceSupport.findAllResourcesInClasspathRoot(root, allResources)))); + } + return tests; + } + + /** + * @since 1.11 + */ + @SuppressWarnings("DataFlowIssue") + @Test + void findAllResourcesInClasspathRootPreconditions() { + var path = Path.of(".").toUri(); + assertPreconditionViolationNotNullFor("root", + () -> ResourceSupport.findAllResourcesInClasspathRoot(null, allResources)); + assertPreconditionViolationNotNullFor("resourceFilter", + () -> ResourceSupport.findAllResourcesInClasspathRoot(path, null)); + } + + /** + * @since 1.11 + */ + @TestFactory + List streamAllResourcesInClasspathRootDelegates() throws Throwable { + List tests = new ArrayList<>(); + List paths = new ArrayList<>(); + paths.add(Path.of(".").toRealPath()); + paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); + for (var path : paths) { + var root = path.toUri(); + tests.add(DynamicTest.dynamicTest(createDisplayName(root), + () -> assertThat(ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources)) // + .containsExactlyElementsOf( + ResourceSupport.streamAllResourcesInClasspathRoot(root, allResources).toList()))); + } + return tests; + } + + /** + * @since 1.11 + */ + @SuppressWarnings("DataFlowIssue") + @Test + void streamAllResourcesInClasspathRootPreconditions() { + var path = Path.of(".").toUri(); + assertPreconditionViolationNotNullFor("root", + () -> ResourceSupport.streamAllResourcesInClasspathRoot(null, allResources)); + assertPreconditionViolationNotNullFor("resourceFilter", + () -> ResourceSupport.streamAllResourcesInClasspathRoot(path, null)); + } + + /** + * @since 1.11 + */ + @Test + void findAllResourcesInPackageDelegates() { + assertNotEquals(0, ResourceSupport.findAllResourcesInPackage("org.junit", allResources).size()); + + assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources), + ResourceSupport.findAllResourcesInPackage("org.junit", allResources)); + } + + /** + * @since 1.11 + */ + @SuppressWarnings("DataFlowIssue") + @Test + void findAllResourcesInPackagePreconditions() { + assertPreconditionViolationNotNullOrBlankFor("basePackageName", + () -> ResourceSupport.findAllResourcesInPackage(null, allResources)); + assertPreconditionViolationNotNullFor("resourceFilter", + () -> ResourceSupport.findAllResourcesInPackage("org.junit", null)); + } + + /** + * @since 1.11 + */ + @Test + void streamAllResourcesInPackageDelegates() { + assertNotEquals(0, ResourceSupport.streamAllResourcesInPackage("org.junit", allResources).count()); + + assertEquals(ReflectionUtils.streamAllResourcesInPackage("org.junit", allResources).toList(), + ResourceSupport.streamAllResourcesInPackage("org.junit", allResources).toList()); + } + + /** + * @since 1.11 + */ + @SuppressWarnings("DataFlowIssue") + @Test + void streamAllResourcesInPackagePreconditions() { + assertPreconditionViolationNotNullOrBlankFor("basePackageName", + () -> ResourceSupport.streamAllResourcesInPackage(null, allResources)); + assertPreconditionViolationNotNullFor("resourceFilter", + () -> ResourceSupport.streamAllResourcesInPackage("org.junit", null)); + } + + /** + * @since 1.11 + */ + @Test + void findAllResourcesInModuleDelegates() { + assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources), + ResourceSupport.findAllResourcesInModule("org.junit.platform.commons", allResources)); + } + + /** + * @since 1.11 + */ + @SuppressWarnings("DataFlowIssue") + @Test + void findAllResourcesInModulePreconditions() { + var exception = assertThrows(PreconditionViolationException.class, + () -> ResourceSupport.findAllResourcesInModule(null, allResources)); + assertEquals("Module name must not be null or empty", exception.getMessage()); + assertPreconditionViolationNotNullFor("Resource filter", + () -> ResourceSupport.findAllResourcesInModule("org.junit.platform.commons", null)); + } + + /** + * @since 1.11 + */ + @Test + void streamAllResourcesInModuleDelegates() { + assertEquals(ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList(), + ResourceSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList()); + } + + /** + * @since 1.11 + */ + @SuppressWarnings("DataFlowIssue") + @Test + void streamAllResourcesInModulePreconditions() { + var exception = assertThrows(PreconditionViolationException.class, + () -> ResourceSupport.streamAllResourcesInModule(null, allResources)); + assertEquals("Module name must not be null or empty", exception.getMessage()); + assertPreconditionViolationNotNullFor("Resource filter", + () -> ResourceSupport.streamAllResourcesInModule("org.junit.platform.commons", null)); + } + + private static String createDisplayName(URI root) { + var displayName = root.getPath(); + if (displayName.length() > 42) { + displayName = "..." + displayName.substring(displayName.length() - 42); + } + return displayName; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/ConversionSupportTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/ConversionSupportTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/ConversionSupportTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/ConversionSupportTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,348 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.io.File; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Currency; +import java.util.Locale; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.test.TestClassLoader; +import org.junit.platform.commons.util.ClassLoaderUtils; + +/** + * Unit tests for {@link ConversionSupport}. + * + * @since 5.12 + */ +class ConversionSupportTests { + + @Test + void isAwareOfNull() { + assertConverts(null, Object.class, null); + assertConverts(null, String.class, null); + assertConverts(null, Boolean.class, null); + } + + @Test + void convertsStringsToPrimitiveTypes() { + assertConverts("true", boolean.class, true); + assertConverts("false", boolean.class, false); + assertConverts("o", char.class, 'o'); + assertConverts("1", byte.class, (byte) 1); + assertConverts("1_0", byte.class, (byte) 10); + assertConverts("1", short.class, (short) 1); + assertConverts("1_2", short.class, (short) 12); + assertConverts("42", int.class, 42); + assertConverts("700_050_000", int.class, 700_050_000); + assertConverts("42", long.class, 42L); + assertConverts("4_2", long.class, 42L); + assertConverts("42.23", float.class, 42.23f); + assertConverts("42.2_3", float.class, 42.23f); + assertConverts("42.23", double.class, 42.23); + assertConverts("42.2_3", double.class, 42.23); + } + + @Test + void convertsStringsToPrimitiveWrapperTypes() { + assertConverts("true", Boolean.class, true); + assertConverts("false", Boolean.class, false); + assertConverts("o", Character.class, 'o'); + assertConverts("1", Byte.class, (byte) 1); + assertConverts("1_0", Byte.class, (byte) 10); + assertConverts("1", Short.class, (short) 1); + assertConverts("1_2", Short.class, (short) 12); + assertConverts("42", Integer.class, 42); + assertConverts("700_050_000", Integer.class, 700_050_000); + assertConverts("42", Long.class, 42L); + assertConverts("4_2", Long.class, 42L); + assertConverts("42.23", Float.class, 42.23f); + assertConverts("42.2_3", Float.class, 42.23f); + assertConverts("42.23", Double.class, 42.23); + assertConverts("42.2_3", Double.class, 42.23); + } + + @ParameterizedTest(name = "[{index}] {0}") + @ValueSource(classes = { char.class, boolean.class, short.class, byte.class, int.class, long.class, float.class, + double.class, void.class }) + void throwsExceptionForNullToPrimitiveTypeConversion(Class type) { + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert(null, type)) // + .withMessage("Cannot convert null to primitive value of type " + type.getCanonicalName()); + } + + @ParameterizedTest(name = "[{index}] {0}") + @ValueSource(classes = { Boolean.class, Character.class, Short.class, Byte.class, Integer.class, Long.class, + Float.class, Double.class }) + void throwsExceptionWhenConvertingTheWordNullToPrimitiveWrapperType(Class type) { + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert("null", type)) // + .withMessage("Failed to convert String \"null\" to type " + type.getCanonicalName()); + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert("NULL", type)) // + .withMessage("Failed to convert String \"NULL\" to type " + type.getCanonicalName()); + } + + @Test + void throwsExceptionOnInvalidStringForPrimitiveTypes() { + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert("ab", char.class)) // + .withMessage("Failed to convert String \"ab\" to type char") // + .havingCause() // + .withMessage("String must have length of 1: ab"); + + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert("tru", boolean.class)) // + .withMessage("Failed to convert String \"tru\" to type boolean") // + .havingCause() // + .withMessage("String must be 'true' or 'false' (ignoring case): tru"); + + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert("null", boolean.class)) // + .withMessage("Failed to convert String \"null\" to type boolean") // + .havingCause() // + .withMessage("String must be 'true' or 'false' (ignoring case): null"); + + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert("NULL", boolean.class)) // + .withMessage("Failed to convert String \"NULL\" to type boolean") // + .havingCause() // + .withMessage("String must be 'true' or 'false' (ignoring case): NULL"); + } + + @Test + void throwsExceptionWhenImplicitConversionIsUnsupported() { + assertThatExceptionOfType(ConversionException.class) // + .isThrownBy(() -> convert("foo", Enigma.class)) // + .withMessage("No built-in converter for source type java.lang.String and target type %s", + Enigma.class.getName()); + } + + /** + * @since 5.4 + */ + @Test + @SuppressWarnings("OctalInteger") // We test parsing octal integers here as well as hex. + void convertsEncodedStringsToIntegralTypes() { + assertConverts("0x1f", byte.class, (byte) 0x1F); + assertConverts("-0x1F", byte.class, (byte) -0x1F); + assertConverts("010", byte.class, (byte) 010); + + assertConverts("0x1f00", short.class, (short) 0x1F00); + assertConverts("-0x1F00", short.class, (short) -0x1F00); + assertConverts("01000", short.class, (short) 01000); + + assertConverts("0x1f000000", int.class, 0x1F000000); + assertConverts("-0x1F000000", int.class, -0x1F000000); + assertConverts("010000000", int.class, 010000000); + + assertConverts("0x1f000000000", long.class, 0x1F000000000L); + assertConverts("-0x1F000000000", long.class, -0x1F000000000L); + assertConverts("0100000000000", long.class, 0100000000000L); + } + + @Test + void convertsStringsToEnumConstants() { + assertConverts("DAYS", TimeUnit.class, TimeUnit.DAYS); + } + + // --- java.io and java.nio ------------------------------------------------ + + @Test + void convertsStringToCharset() { + assertConverts("ISO-8859-1", Charset.class, StandardCharsets.ISO_8859_1); + assertConverts("UTF-8", Charset.class, StandardCharsets.UTF_8); + } + + @Test + void convertsStringToFile() { + assertConverts("file", File.class, new File("file")); + assertConverts("/file", File.class, new File("/file")); + assertConverts("/some/file", File.class, new File("/some/file")); + } + + @Test + void convertsStringToPath() { + assertConverts("path", Path.class, Paths.get("path")); + assertConverts("/path", Path.class, Paths.get("/path")); + assertConverts("/some/path", Path.class, Paths.get("/some/path")); + } + + // --- java.lang ----------------------------------------------------------- + + @Test + void convertsStringToClass() { + assertConverts("java.lang.Integer", Class.class, Integer.class); + assertConverts("java.lang.Void", Class.class, Void.class); + assertConverts("java.lang.Thread$State", Class.class, Thread.State.class); + assertConverts("byte", Class.class, byte.class); + assertConverts("void", Class.class, void.class); + assertConverts("char[]", Class.class, char[].class); + assertConverts("java.lang.Long[][]", Class.class, Long[][].class); + assertConverts("[[[I", Class.class, int[][][].class); + assertConverts("[[Ljava.lang.String;", Class.class, String[][].class); + } + + @Test + void convertsStringToClassWithCustomTypeFromDifferentClassLoader() throws Exception { + String customTypeName = Enigma.class.getName(); + try (var testClassLoader = TestClassLoader.forClasses(Enigma.class)) { + var customType = testClassLoader.loadClass(customTypeName); + assertThat(customType.getClassLoader()).isSameAs(testClassLoader); + + var declaringExecutable = ReflectionSupport.findMethod(customType, "foo").get(); + assertThat(declaringExecutable.getDeclaringClass().getClassLoader()).isSameAs(testClassLoader); + + var clazz = (Class) convert(customTypeName, Class.class, classLoader(declaringExecutable)); + assertThat(clazz).isNotEqualTo(Enigma.class); + assertThat(clazz).isEqualTo(customType); + assertThat(clazz.getClassLoader()).isSameAs(testClassLoader); + } + } + + // --- java.math ----------------------------------------------------------- + + @Test + void convertsStringToBigDecimal() { + assertConverts("123.456e789", BigDecimal.class, new BigDecimal("123.456e789")); + } + + @Test + void convertsStringToBigInteger() { + assertConverts("1234567890123456789", BigInteger.class, new BigInteger("1234567890123456789")); + } + + // --- java.net ------------------------------------------------------------ + + @Test + void convertsStringToURI() { + assertConverts("https://docs.oracle.com/en/java/javase/12/", URI.class, + URI.create("https://docs.oracle.com/en/java/javase/12/")); + } + + @Test + void convertsStringToURL() throws Exception { + assertConverts("https://junit.org", URL.class, URI.create("https://junit.org").toURL()); + } + + // --- java.time ----------------------------------------------------------- + + @Test + void convertsStringsToJavaTimeInstances() { + assertConverts("PT1234.5678S", Duration.class, Duration.ofSeconds(1234, 567800000)); + assertConverts("1970-01-01T00:00:00Z", Instant.class, Instant.ofEpochMilli(0)); + assertConverts("2017-03-14", LocalDate.class, LocalDate.of(2017, 3, 14)); + assertConverts("2017-03-14T12:34:56.789", LocalDateTime.class, + LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)); + assertConverts("12:34:56.789", LocalTime.class, LocalTime.of(12, 34, 56, 789_000_000)); + assertConverts("--03-14", MonthDay.class, MonthDay.of(3, 14)); + assertConverts("2017-03-14T12:34:56.789Z", OffsetDateTime.class, + OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)); + assertConverts("12:34:56.789Z", OffsetTime.class, OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)); + assertConverts("P2M6D", Period.class, Period.of(0, 2, 6)); + assertConverts("2017", Year.class, Year.of(2017)); + assertConverts("2017-03", YearMonth.class, YearMonth.of(2017, 3)); + assertConverts("2017-03-14T12:34:56.789Z", ZonedDateTime.class, + ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)); + assertConverts("Europe/Berlin", ZoneId.class, ZoneId.of("Europe/Berlin")); + assertConverts("+02:30", ZoneOffset.class, ZoneOffset.ofHoursMinutes(2, 30)); + } + + // --- java.util ----------------------------------------------------------- + + @Test + void convertsStringToCurrency() { + assertConverts("JPY", Currency.class, Currency.getInstance("JPY")); + } + + @Test + @SuppressWarnings("deprecation") + void convertsStringToLocale() { + assertConverts("en", Locale.class, Locale.ENGLISH); + assertConverts("en_us", Locale.class, new Locale(Locale.US.toString())); + } + + @Test + void convertsStringToUUID() { + var uuid = "d043e930-7b3b-48e3-bdbe-5a3ccfb833db"; + assertConverts(uuid, UUID.class, UUID.fromString(uuid)); + } + + // ------------------------------------------------------------------------- + + private void assertConverts(String input, Class targetClass, Object expectedOutput) { + var result = convert(input, targetClass); + + assertThat(result) // + .describedAs(input + " --(" + targetClass.getName() + ")--> " + expectedOutput) // + .isEqualTo(expectedOutput); + } + + private Object convert(String input, Class targetClass) { + return convert(input, targetClass, classLoader()); + } + + private Object convert(String input, Class targetClass, ClassLoader classLoader) { + return ConversionSupport.convert(input, targetClass, classLoader); + } + + private static ClassLoader classLoader() { + Method declaringExecutable = ReflectionSupport.findMethod(ConversionSupportTests.class, "foo").get(); + return classLoader(declaringExecutable); + } + + private static ClassLoader classLoader(Method declaringExecutable) { + return ClassLoaderUtils.getClassLoader(declaringExecutable.getDeclaringClass()); + } + + @SuppressWarnings("unused") + private static void foo() { + } + + private static class Enigma { + + @SuppressWarnings("unused") + void foo() { + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,7 @@ package org.junit.platform.commons.support.conversion; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.platform.commons.util.ReflectionUtils.findMethod; +import static org.junit.platform.commons.support.ReflectionSupport.findMethod; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -100,7 +100,7 @@ private static Constructor constructor(Class clazz) { return ReflectionUtils.findConstructors(clazz, - ctr -> ctr.getParameterCount() == 1 && ctr.getParameterTypes()[0] == String.class).get(0); + ctr -> ctr.getParameterCount() == 1 && ctr.getParameterTypes()[0] == String.class).getFirst(); } private static Method bookMethod(String methodName) { @@ -167,6 +167,11 @@ return Objects.equals(this.title, that.title); } + @Override + public int hashCode() { + return Objects.hash(title); + } + } static class Journal { @@ -188,6 +193,11 @@ return Objects.equals(this.title, that.title); } + @Override + public int hashCode() { + return Objects.hash(title); + } + } static class Newspaper { @@ -217,6 +227,11 @@ return Objects.equals(this.title, that.title); } + @Override + public int hashCode() { + return Objects.hash(title); + } + } static class Magazine { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.platform.commons.util; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -94,7 +93,7 @@ } /** - * Test for https://github.com/junit-team/junit5/issues/1133 + * Test for https://github.com/junit-team/junit-framework/issues/1133 */ @Test void findInheritedAnnotationMetaPresentOnNonInheritedComposedAnnotationPresentOnSuperclass() { @@ -273,8 +272,7 @@ } private void assertTagsFound(Class clazz, String... tags) { - assertEquals(List.of(tags), - findRepeatableAnnotations(clazz, Tag.class).stream().map(Tag::value).collect(toList()), + assertEquals(List.of(tags), findRepeatableAnnotations(clazz, Tag.class).stream().map(Tag::value).toList(), () -> "Tags found for class " + clazz.getName()); } @@ -332,7 +330,7 @@ private void assertExtensionsFound(Class clazz, String... tags) { assertEquals(List.of(tags), - findRepeatableAnnotations(clazz, ExtendWith.class).stream().map(ExtendWith::value).collect(toList()), + findRepeatableAnnotations(clazz, ExtendWith.class).stream().map(ExtendWith::value).toList(), () -> "Extensions found for class " + clazz.getName()); } @@ -385,12 +383,12 @@ var methods = findAnnotatedMethods(ClassWithAnnotatedMethods.class, Annotation1.class, TOP_DOWN); assertEquals(3, methods.size()); - assertEquals(superMethod, methods.get(0)); + assertEquals(superMethod, methods.getFirst()); assertThat(methods.subList(1, 3)).containsOnly(method1, method3); } - /** - * @see https://github.com/junit-team/junit5/issues/3553 + /* + * see https://github.com/junit-team/junit-framework/issues/3553 */ @Test void findAnnotatedMethodsDoesNotAllowInstanceMethodToHideStaticMethod() throws Exception { @@ -477,7 +475,7 @@ var fields = findAnnotatedFields(ClassWithAnnotatedFields.class, Annotation1.class, isStringField, TOP_DOWN); assertEquals(3, fields.size()); - assertEquals(superField, fields.get(0)); + assertEquals(superField, fields.getFirst()); assertThat(fields.subList(1, 3)).containsOnly(field1, field3); } @@ -523,8 +521,8 @@ return values.stream().map(String::valueOf).toList(); } - /** - * @see https://github.com/junit-team/junit5/issues/3553 + /* + * see https://github.com/junit-team/junit-framework/issues/3553 */ @Test void findAnnotatedFieldsDoesNotAllowInstanceFieldToHideStaticField() throws Exception { @@ -610,7 +608,7 @@ } private List asNames(List fields) { - return fields.stream().map(Field::getName).collect(toList()); + return fields.stream().map(Field::getName).toList(); } // ------------------------------------------------------------------------- diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassLoaderUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassLoaderUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassLoaderUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassLoaderUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,11 +11,11 @@ package org.junit.platform.commons.util; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import static org.mockito.Mockito.mock; import org.junit.jupiter.api.Test; @@ -31,8 +31,7 @@ @Test void getClassLoaderPreconditions() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> ClassLoaderUtils.getClassLoader(null))// + assertPreconditionViolationFor(() -> ClassLoaderUtils.getClassLoader(null))// .withMessage("Class must not be null"); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassNamePatternFilterUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassNamePatternFilterUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassNamePatternFilterUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassNamePatternFilterUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -169,4 +169,155 @@ .isEmpty(); } + //@formatter:off + @ValueSource(strings = { + "org.junit.jupiter.*", + "org.junit.platform.*.NonExistentClass", + "*.NonExistentClass*", + "*NonExistentClass*", + "AExecutionConditionClass, BExecutionConditionClass" + }) + //@formatter:on + @ParameterizedTest + void neverIncludedConditions(String pattern) { + List executionConditions = List.of(new AExecutionConditionClass(), + new BExecutionConditionClass()); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) // + .isEmpty(); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.platform.*", + "*.platform.*", + "*", + "*AExecutionConditionClass, *BExecutionConditionClass", + "*ExecutionConditionClass" + }) + //@formatter:on + @ParameterizedTest + void alwaysIncludedConditions(String pattern) { + List executionConditions = List.of(new AExecutionConditionClass(), + new BExecutionConditionClass()); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) // + .hasSize(2); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.jupiter.*", + "org.junit.platform.*.NonExistentClass", + "*.NonExistentClass*", + "*NonExistentClass*", + "ATestExecutionListenerClass, BTestExecutionListenerClass" + }) + //@formatter:on + @ParameterizedTest + void neverIncludedListeners(String pattern) { + List executionConditions = List.of(new ATestExecutionListenerClass(), + new BTestExecutionListenerClass()); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) // + .isEmpty(); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.platform.*", + "*.platform.*", + "*", + "*ATestExecutionListenerClass, *BTestExecutionListenerClass", + "*TestExecutionListenerClass" + }) + //@formatter:on + @ParameterizedTest + void alwaysIncludedListeners(String pattern) { + List executionConditions = List.of(new ATestExecutionListenerClass(), + new BTestExecutionListenerClass()); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) // + .hasSize(2); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.jupiter.*", + "org.junit.platform.*.NonExistentClass", + "*.NonExistentClass*", + "*NonExistentClass*", + "AVanillaEmpty, BVanillaEmpty" + }) + //@formatter:on + @ParameterizedTest + void neverIncludedClass(String pattern) { + var executionConditions = List.of(new AVanillaEmpty(), new BVanillaEmpty()); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) // + .isEmpty(); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.platform.*", + "*.platform.*", + "*", + "*AVanillaEmpty, *BVanillaEmpty", + "*VanillaEmpty" + }) + //@formatter:on + @ParameterizedTest + void alwaysIncludedClass(String pattern) { + var executionConditions = List.of(new AVanillaEmpty(), new BVanillaEmpty()); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClasses(pattern)) // + .hasSize(2); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.jupiter.*", + "org.junit.platform.*.NonExistentClass", + "*.NonExistentClass*", + "*NonExistentClass*", + "AVanillaEmpty, BVanillaEmpty" + }) + //@formatter:on + @ParameterizedTest + void neverIncludedClassName(String pattern) { + var executionConditions = List.of("org.junit.platform.commons.util.classes.AVanillaEmpty", + "org.junit.platform.commons.util.classes.BVanillaEmpty"); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClassNames(pattern)) // + .isEmpty(); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.platform.*", + "*.platform.*", + "*", + "*AVanillaEmpty, *BVanillaEmpty", + "*VanillaEmpty" + }) + //@formatter:on + @ParameterizedTest + void alwaysIncludedClassName(String pattern) { + var executionConditions = List.of("org.junit.platform.commons.util.classes.AVanillaEmpty", + "org.junit.platform.commons.util.classes.BVanillaEmpty"); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClassNames(pattern)) // + .hasSize(2); + } + + //@formatter:off + @ValueSource(strings = { + "org.junit.platform.*", + "*.platform.*", + "*", + "*AVanillaEmpty, *BVanillaEmpty", + "*VanillaEmpty" + }) + //@formatter:on + @ParameterizedTest + void includeAndExcludeSame(String pattern) { + var executionConditions = List.of("org.junit.platform.commons.util.classes.AVanillaEmpty", + "org.junit.platform.commons.util.classes.BVanillaEmpty"); + assertThat(executionConditions).filteredOn(ClassNamePatternFilterUtils.includeMatchingClassNames(pattern)) // + .hasSize(2); + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClassUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,625 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import static java.util.Objects.requireNonNull; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assumptions.assumeFalse; -import static org.junit.platform.commons.test.ConcurrencyTestingUtils.executeConcurrently; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.module.ModuleFinder; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.spi.ToolProvider; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.fixtures.TrackLogRecords; -import org.junit.jupiter.api.io.TempDir; -import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.function.Try; -import org.junit.platform.commons.logging.LogRecordListener; -import org.junit.platform.commons.support.Resource; - -/** - * Unit tests for {@link ClasspathScanner}. - * - * @since 1.0 - */ -@TrackLogRecords -class ClasspathScannerTests { - - private static final ClassFilter allClasses = ClassFilter.of(type -> true); - private static final Predicate allResources = type -> true; - - private final List> loadedClasses = new ArrayList<>(); - - private final BiFunction>> trackingClassLoader = (name, - classLoader) -> ReflectionUtils.tryToLoadClass(name, classLoader).ifSuccess(loadedClasses::add); - - private final ClasspathScanner classpathScanner = new ClasspathScanner(ClassLoaderUtils::getDefaultClassLoader, - trackingClassLoader); - - @Test - void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccursWithNullDetailedMessage( - LogRecordListener listener) throws Exception { - - Predicate> malformedClassNameSimulationFilter = clazz -> { - if (clazz.getSimpleName().equals(ClassForMalformedClassNameSimulation.class.getSimpleName())) { - throw new InternalError(); - } - return true; - }; - - assertClassesScannedWhenExceptionIsThrown(malformedClassNameSimulationFilter); - assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); - } - - @Test - void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccurs(LogRecordListener listener) - throws Exception { - - Predicate> malformedClassNameSimulationFilter = clazz -> { - if (clazz.getSimpleName().equals(ClassForMalformedClassNameSimulation.class.getSimpleName())) { - throw new InternalError("Malformed class name"); - } - return true; - }; - - assertClassesScannedWhenExceptionIsThrown(malformedClassNameSimulationFilter); - assertDebugMessageLogged(listener, "The java.lang.Class loaded from path .+ has a malformed class name .+"); - } - - @Test - void scanForClassesInClasspathRootWhenOtherInternalErrorOccurs(LogRecordListener listener) throws Exception { - Predicate> otherInternalErrorSimulationFilter = clazz -> { - if (clazz.getSimpleName().equals(ClassForOtherInternalErrorSimulation.class.getSimpleName())) { - throw new InternalError("other internal error"); - } - return true; - }; - - assertClassesScannedWhenExceptionIsThrown(otherInternalErrorSimulationFilter); - assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); - } - - @Test - void scanForClassesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordListener listener) throws Exception { - Predicate> runtimeExceptionSimulationFilter = clazz -> { - if (clazz.getSimpleName().equals(ClassForGenericRuntimeExceptionSimulation.class.getSimpleName())) { - throw new RuntimeException("a generic exception"); - } - return true; - }; - - assertClassesScannedWhenExceptionIsThrown(runtimeExceptionSimulationFilter); - assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); - } - - private void assertClassesScannedWhenExceptionIsThrown(Predicate> filter) throws Exception { - var classFilter = ClassFilter.of(filter); - var classes = this.classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), classFilter); - assertThat(classes).hasSizeGreaterThanOrEqualTo(150); - } - - @Test - void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordListener listener) throws Exception { - Predicate runtimeExceptionSimulationFilter = resource -> { - if (resource.getName().equals("org/junit/platform/commons/other-example.resource")) { - throw new RuntimeException("a generic exception"); - } - return true; - }; - - assertResourcesScannedWhenExceptionIsThrown(runtimeExceptionSimulationFilter); - assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); - } - - private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { - var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), filter); - assertThat(resources).hasSizeGreaterThanOrEqualTo(150); - } - - private void assertDebugMessageLogged(LogRecordListener listener, String regex) { - // @formatter:off - assertThat(listener.stream(ClasspathScanner.class, Level.FINE) - .map(LogRecord::getMessage) - .filter(m -> m.matches(regex)) - ).hasSize(1); - // @formatter:on - } - - @Test - void scanForClassesInClasspathRootWhenOutOfMemoryErrorOccurs() { - Predicate> outOfMemoryErrorSimulationFilter = clazz -> { - if (clazz.getSimpleName().equals(ClassForOutOfMemoryErrorSimulation.class.getSimpleName())) { - throw new OutOfMemoryError(); - } - return true; - }; - var classFilter = ClassFilter.of(outOfMemoryErrorSimulationFilter); - - assertThrows(OutOfMemoryError.class, - () -> this.classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), classFilter)); - } - - @Test - void scanForClassesInClasspathRootWithinJarFile() throws Exception { - scanForClassesInClasspathRootWithinJarFile("/jartest.jar"); - } - - @Test - void scanForClassesInClasspathRootWithinJarWithSpacesInPath() throws Exception { - scanForClassesInClasspathRootWithinJarFile("/folder with spaces/jar test with spaces.jar"); - } - - private void scanForClassesInClasspathRootWithinJarFile(String resourceName) throws Exception { - var jarfile = getClass().getResource(resourceName); - - try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); - - var classes = classpathScanner.scanForClassesInClasspathRoot(jarfile.toURI(), allClasses); - assertThat(classes).extracting(Class::getName) // - .containsExactlyInAnyOrder("org.junit.platform.jartest.notincluded.NotIncluded", - "org.junit.platform.jartest.included.recursive.RecursivelyIncluded", - "org.junit.platform.jartest.included.Included"); - } - } - - @Test - void scanForResourcesInClasspathRootWithinJarFile() throws Exception { - scanForResourcesInClasspathRootWithinJarFile("/jartest.jar"); - } - - @Test - void scanForResourcesInClasspathRootWithinJarWithSpacesInPath() throws Exception { - scanForResourcesInClasspathRootWithinJarFile("/folder with spaces/jar test with spaces.jar"); - } - - private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) throws Exception { - var jarfile = getClass().getResource(resourceName); - - try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); - - var resources = classpathScanner.scanForResourcesInClasspathRoot(jarfile.toURI(), allResources); - assertThat(resources).extracting(Resource::getName) // - .containsExactlyInAnyOrder("org/junit/platform/jartest/notincluded/not-included.resource", - "org/junit/platform/jartest/included/included.resource", - "org/junit/platform/jartest/included/recursive/recursively-included.resource", - "META-INF/MANIFEST.MF"); - } - } - - @Test - void scanForResourcesInShadowedClassPathRoot() throws Exception { - var jarFile = getClass().getResource("/jartest.jar"); - var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); - - try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); - - var resources = classpathScanner.scanForResourcesInClasspathRoot(shadowedJarFile.toURI(), allResources); - assertThat(resources).extracting(Resource::getName).containsExactlyInAnyOrder( - "org/junit/platform/jartest/included/unique.resource", // - "org/junit/platform/jartest/included/included.resource", // - "org/junit/platform/jartest/included/recursive/recursively-included.resource", // - "META-INF/MANIFEST.MF"); - - assertThat(resources).extracting(Resource::getUri) // - .map(ClasspathScannerTests::jarFileAndEntry) // - .containsExactlyInAnyOrder( - // This resource only exists in the shadowed jar file - "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", - // These resources exist in both the jar and shadowed jar file. - // They must be discovered in the shadowed jar as we're searching in that classpath root. - "jartest-shadowed.jar!/org/junit/platform/jartest/included/included.resource", - "jartest-shadowed.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", - "jartest-shadowed.jar!/META-INF/MANIFEST.MF"); - } - } - - @Test - void scanForResourcesInPackageWithDuplicateResources() throws Exception { - var jarFile = getClass().getResource("/jartest.jar"); - var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); - - try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); - - var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", - allResources); - - assertThat(resources).extracting(Resource::getUri) // - .map(ClasspathScannerTests::jarFileAndEntry) // - .containsExactlyInAnyOrder( - // This resource only exists in the shadowed jar file - "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", - // These resources exist in both the jar and shadowed jar file. - "jartest.jar!/org/junit/platform/jartest/included/included.resource", - "jartest-shadowed.jar!/org/junit/platform/jartest/included/included.resource", - "jartest.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", - "jartest-shadowed.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource"); - } - } - - private static String jarFileAndEntry(URI uri) { - var uriString = uri.toString(); - int lastJarUriSeparator = uriString.lastIndexOf("!/"); - var jarUri = uriString.substring(0, lastJarUriSeparator); - var jarEntry = uriString.substring(lastJarUriSeparator + 1); - var fileName = jarUri.substring(jarUri.lastIndexOf("/") + 1); - return fileName + "!" + jarEntry; - } - - @Test - void scanForClassesInPackage() { - var classes = classpathScanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); - assertThat(classes).hasSizeGreaterThanOrEqualTo(20); - assertTrue(classes.contains(NestedClassToBeFound.class)); - assertTrue(classes.contains(MemberClassToBeFound.class)); - } - - @Test - void scanForResourcesInPackage() { - var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); - assertThat(resources).extracting(Resource::getUri).containsExactlyInAnyOrder( - uriOf("/org/junit/platform/commons/example.resource"), - uriOf("/org/junit/platform/commons/other-example.resource")); - } - - @Test - // #2500 - void scanForClassesInPackageWithinModulesSharingNamePrefix(@TempDir Path temp) throws Exception { - var moduleSourcePath = Path.of(getClass().getResource("/modules-2500/").toURI()).toString(); - run("javac", "--module", "foo,foo.bar", "--module-source-path", moduleSourcePath, "-d", temp.toString()); - - checkModules2500(ModuleFinder.of(temp)); // exploded modules - - var foo = temp.resolve("foo.jar"); - var bar = temp.resolve("foo.bar.jar"); - run("jar", "--create", "--file", foo.toString(), "-C", temp.resolve("foo").toString(), "."); - run("jar", "--create", "--file", bar.toString(), "-C", temp.resolve("foo.bar").toString(), "."); - - checkModules2500(ModuleFinder.of(foo, bar)); // jarred modules - - System.gc(); // required on Windows in order to release JAR file handles - } - - private static int run(String tool, String... args) { - return ToolProvider.findFirst(tool).orElseThrow().run(System.out, System.err, args); - } - - private void checkModules2500(ModuleFinder finder) { - var root = "foo.bar"; - var before = ModuleFinder.of(); - var boot = ModuleLayer.boot(); - var configuration = boot.configuration().resolve(before, finder, Set.of(root)); - var parent = ClassLoader.getPlatformClassLoader(); - var layer = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(boot), parent).layer(); - - var classpathScanner = new ClasspathScanner(() -> layer.findLoader(root), ReflectionUtils::tryToLoadClass); - { - var classes = classpathScanner.scanForClassesInPackage("foo", allClasses); - var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); - assertThat(classNames).hasSize(2).contains("foo.Foo", "foo.bar.FooBar"); - } - { - var classes = classpathScanner.scanForClassesInPackage("foo.bar", allClasses); - var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); - assertThat(classNames).hasSize(1).contains("foo.bar.FooBar"); - } - } - - @Test - void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { - var jarFile = getClass().getResource("/jartest.jar"); - var jarUri = URI.create("jar:" + jarFile); - - try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); - - var results = executeConcurrently(10, - () -> classpathScanner.scanForClassesInPackage("org.junit.platform.jartest.included", allClasses)); - - assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), - "FileSystem should be closed"); - - results.forEach(classes -> assertThat(classes) // - .hasSize(2) // - .extracting(Class::getSimpleName) // - .containsExactlyInAnyOrder("Included", "RecursivelyIncluded")); - } - } - - @Test - void findAllResourcesInPackageWithinJarFileConcurrently() throws Exception { - var jarFile = getClass().getResource("/jartest.jar"); - var jarUri = URI.create("jar:" + jarFile); - - try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); - - var results = executeConcurrently(10, - () -> classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", allResources)); - - assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), - "FileSystem should be closed"); - - // @formatter:off - results.forEach(resources -> assertThat(resources) - .hasSize(2) - .extracting(Resource::getName).containsExactlyInAnyOrder( - "org/junit/platform/jartest/included/included.resource", - "org/junit/platform/jartest/included/recursive/recursively-included.resource" - )); - // @formatter:on - } - } - - @Test - void scanForClassesInDefaultPackage() { - var classFilter = ClassFilter.of(this::inDefaultPackage); - var classes = classpathScanner.scanForClassesInPackage("", classFilter); - - assertThat(classes).as("number of classes found in default package").isNotEmpty(); - assertTrue(classes.stream().allMatch(this::inDefaultPackage)); - assertTrue(classes.stream().anyMatch(clazz -> "DefaultPackageTestCase".equals(clazz.getName()))); - } - - @Test - void scanForResourcesInDefaultPackage() { - Predicate resourceFilter = this::inDefaultPackage; - var resources = classpathScanner.scanForResourcesInPackage("", resourceFilter); - - assertThat(resources).as("number of resources found in default package").isNotEmpty(); - assertTrue(resources.stream().allMatch(this::inDefaultPackage)); - assertTrue(resources.stream().anyMatch(resource -> "default-package.resource".equals(resource.getName()))); - } - - @Test - void scanForClassesInPackageWithFilter() { - var thisClassOnly = ClassFilter.of(clazz -> clazz == ClasspathScannerTests.class); - var classes = classpathScanner.scanForClassesInPackage("org.junit.platform.commons", thisClassOnly); - assertSame(ClasspathScannerTests.class, classes.get(0)); - } - - @Test - void scanForResourcesInPackageWithFilter() { - Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( - resource.getName()); - var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); - assertThat(resources).extracting(Resource::getName).containsExactly( - "org/junit/platform/commons/example.resource"); - } - - @Test - void resourcesCanBeRead() throws IOException { - Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( - resource.getName()); - var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); - Resource resource = resources.get(0); - - assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); - assertThat(resource.getUri()).isEqualTo(uriOf("/org/junit/platform/commons/example.resource")); - try (InputStream is = resource.getInputStream()) { - String contents = new String(is.readAllBytes(), StandardCharsets.UTF_8); - assertThat(contents).isEqualTo("This file was unintentionally left blank.\n"); - } - } - - @Test - void scanForClassesInPackageForNullBasePackage() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForClassesInPackage(null, allClasses)); - } - - @Test - void scanForResourcesInPackageForNullBasePackage() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForResourcesInPackage(null, allResources)); - } - - @Test - void scanForClassesInPackageForWhitespaceBasePackage() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForClassesInPackage(" ", allClasses)); - } - - @Test - void scanForResourcesInPackageForWhitespaceBasePackage() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForResourcesInPackage(" ", allResources)); - } - - @Test - void scanForClassesInPackageForNullClassFilter() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForClassesInPackage("org.junit.platform.commons", null)); - } - - @Test - void scanForClassesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); - var classes = scanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); - assertThat(classes).isEmpty(); - } - - @Test - void scanForResourcesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); - var classes = scanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); - assertThat(classes).isEmpty(); - } - - @Test - void scanForClassesInPackageOnlyLoadsClassesThatAreIncludedByTheClassNameFilter() { - Predicate classNameFilter = name -> ClasspathScannerTests.class.getName().equals(name); - var classFilter = ClassFilter.of(classNameFilter, type -> true); - - classpathScanner.scanForClassesInPackage("org.junit.platform.commons", classFilter); - - assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); - } - - @Test - void findAllClassesInClasspathRoot() throws Exception { - var thisClassOnly = ClassFilter.of(clazz -> clazz == ClasspathScannerTests.class); - var root = getTestClasspathRoot(); - var classes = classpathScanner.scanForClassesInClasspathRoot(root, thisClassOnly); - assertSame(ClasspathScannerTests.class, classes.get(0)); - } - - @Test - void findAllClassesInDefaultPackageInClasspathRoot() throws Exception { - var classFilter = ClassFilter.of(this::inDefaultPackage); - var classes = classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), classFilter); - - assertEquals(1, classes.size(), "number of classes found in default package"); - var testClass = classes.get(0); - assertTrue(inDefaultPackage(testClass)); - assertEquals("DefaultPackageTestCase", testClass.getName()); - } - - @Test - void doesNotLoopInfinitelyWithCircularSymlinks(@TempDir Path tempDir) throws Exception { - - // Abort if running on Microsoft Windows since we are testing symbolic links - assumeFalse(System.getProperty("os.name").toLowerCase().contains("win")); - - var directory = Files.createDirectory(tempDir.resolve("directory")); - var symlink1 = Files.createSymbolicLink(tempDir.resolve("symlink1"), directory); - Files.createSymbolicLink(directory.resolve("symlink2"), symlink1); - - var classes = classpathScanner.scanForClassesInClasspathRoot(symlink1.toUri(), allClasses); - - assertThat(classes).isEmpty(); - } - - private boolean inDefaultPackage(Class clazz) { - // OpenJDK returns NULL for the default package. - var pkg = clazz.getPackage(); - return pkg == null || "".equals(clazz.getPackage().getName()); - } - - private boolean inDefaultPackage(Resource resource) { - return !resource.getName().contains("/"); - } - - @Test - void findAllClassesInClasspathRootWithFilter() throws Exception { - var root = getTestClasspathRoot(); - var classes = classpathScanner.scanForClassesInClasspathRoot(root, allClasses); - - assertThat(classes).hasSizeGreaterThanOrEqualTo(20); - assertTrue(classes.contains(ClasspathScannerTests.class)); - } - - @Test - void findAllClassesInClasspathRootForNullRoot() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForClassesInClasspathRoot(null, allClasses)); - } - - @Test - void findAllClassesInClasspathRootForNonExistingRoot() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForClassesInClasspathRoot(Paths.get("does_not_exist").toUri(), allClasses)); - } - - @Test - void findAllClassesInClasspathRootForNullClassFilter() { - assertThrows(PreconditionViolationException.class, - () -> classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), null)); - } - - @Test - void onlyLoadsClassesInClasspathRootThatAreIncludedByTheClassNameFilter() throws Exception { - var classFilter = ClassFilter.of(name -> ClasspathScannerTests.class.getName().equals(name), type -> true); - var root = getTestClasspathRoot(); - - classpathScanner.scanForClassesInClasspathRoot(root, classFilter); - - assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); - } - - private static URI uriOf(String name) { - var resource = ClasspathScannerTests.class.getResource(name); - try { - return requireNonNull(resource).toURI(); - } - catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - - private URI getTestClasspathRoot() throws Exception { - var location = getClass().getProtectionDomain().getCodeSource().getLocation(); - return location.toURI(); - } - - private URI getTestClasspathResourceRoot() { - // Gradle puts classes and resources in different roots. - var defaultPackageResource = "/default-package.resource"; - var resourceUri = getClass().getResource(defaultPackageResource).toString(); - return URI.create(resourceUri.substring(0, resourceUri.length() - defaultPackageResource.length())); - } - - class MemberClassToBeFound { - } - - static class NestedClassToBeFound { - } - - static class ClassForMalformedClassNameSimulation { - } - - static class ClassForOtherInternalErrorSimulation { - } - - static class ClassForGenericRuntimeExceptionSimulation { - } - - static class ClassForOutOfMemoryErrorSimulation { - } - - private static class ThrowingClassLoader extends ClassLoader { - - @Override - public Enumeration getResources(String name) throws IOException { - throw new IOException("Demo I/O error"); - } - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,7 +12,6 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.platform.commons.test.ConcurrencyTestingUtils.executeConcurrently; import static org.junit.platform.commons.util.CloseablePath.JAR_URI_SCHEME; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -32,6 +31,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.platform.commons.test.ConcurrencyTestingUtils; import org.junit.platform.commons.util.CloseablePath.FileSystemProvider; import org.junit.platform.engine.support.hierarchical.OpenTest4JAwareThrowableCollector; @@ -92,7 +92,8 @@ when(fileSystemProvider.newFileSystem(any())) // .thenAnswer(invocation -> FileSystems.newFileSystem((URI) invocation.getArgument(0), Map.of())); - paths = executeConcurrently(numThreads, () -> CloseablePath.create(uri, fileSystemProvider)); + paths = ConcurrencyTestingUtils.executeConcurrently(numThreads, + () -> CloseablePath.create(uri, fileSystemProvider)); verify(fileSystemProvider, only()).newFileSystem(jarUri); // Close all but the first path @@ -100,7 +101,7 @@ assertDoesNotThrow(() -> FileSystems.getFileSystem(jarUri), "FileSystem should still be open"); // Close last remaining path - paths.get(0).close(); + paths.getFirst().close(); assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), "FileSystem should have been closed"); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CollectionUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CollectionUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CollectionUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/CollectionUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.platform.commons.util; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; @@ -26,6 +25,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.Spliterator; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.DoubleStream; import java.util.stream.IntStream; @@ -140,6 +140,7 @@ Collection.class, // Iterable.class, // Iterator.class, // + IteratorProvider.class, // Object[].class, // String[].class, // int[].class, // @@ -161,10 +162,11 @@ Stream.of("cat", "dog"), // DoubleStream.of(42.3), // IntStream.of(99), // - LongStream.of(100000000), // + LongStream.of(100_000_000), // Set.of(1, 2, 3), // Arguments.of((Object) new Object[] { 9, 8, 7 }), // - new int[] { 5, 10, 15 }// + new int[] { 5, 10, 15 }, // + new IteratorProvider(1, 2, 3, 4, 5)// ); } @@ -175,6 +177,8 @@ Object.class, // Integer.class, // String.class, // + UnusableIteratorProvider.class, // + Spliterator.class, // int.class, // boolean.class // }) @@ -243,16 +247,10 @@ } @Test - @SuppressWarnings({ "unchecked", "serial" }) + @SuppressWarnings({ "unchecked" }) void toStreamWithCollection() { var collectionStreamClosed = new AtomicBoolean(false); - Collection input = new ArrayList<>() { - - { - add("foo"); - add("bar"); - } - + var input = new ArrayList<>(List.of("foo", "bar")) { @Override public Stream stream() { return super.stream().onClose(() -> collectionStreamClosed.set(true)); @@ -260,7 +258,7 @@ }; try (var stream = (Stream) CollectionUtils.toStream(input)) { - var result = stream.collect(toList()); + var result = stream.toList(); assertThat(result).containsExactly("foo", "bar"); } @@ -290,6 +288,25 @@ @Test @SuppressWarnings("unchecked") + void toStreamWithIteratorProvider() { + var input = new IteratorProvider("foo", "bar"); + + var result = (Stream) CollectionUtils.toStream(input); + + assertThat(result).containsExactly("foo", "bar"); + } + + @Test + void throwWhenIteratorNamedMethodDoesNotReturnAnIterator() { + var o = new UnusableIteratorProvider("Test"); + var e = assertThrows(PreconditionViolationException.class, () -> CollectionUtils.toStream(o)); + + assertEquals("Cannot convert instance of %s into a Stream: %s".formatted( + UnusableIteratorProvider.class.getName(), o), e.getMessage()); + } + + @Test + @SuppressWarnings("unchecked") void toStreamWithArray() { var result = (Stream) CollectionUtils.toStream(new String[] { "foo", "bar" }); @@ -356,4 +373,26 @@ } } } + + /** + * An interface that has a method with name 'iterator', returning a java.util/Iterator as a return type + */ + private record IteratorProvider(Object... elements) { + + @SuppressWarnings("unused") + Iterator iterator() { + return Arrays.stream(elements).iterator(); + } + } + + /** + * An interface that has a method with name 'iterator', but does not return java.util/Iterator as a return type + */ + private record UnusableIteratorProvider(Object... elements) { + + @SuppressWarnings("unused") + Object iterator() { + return Arrays.stream(elements).iterator(); + } + } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/DefaultClasspathScannerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/DefaultClasspathScannerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/DefaultClasspathScannerTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/DefaultClasspathScannerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,631 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static java.util.Objects.requireNonNull; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.junit.platform.commons.test.ConcurrencyTestingUtils.executeConcurrently; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleFinder; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.DisabledInEclipse; +import org.junit.jupiter.api.fixtures.TrackLogRecords; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.io.Resource; +import org.junit.platform.commons.io.ResourceFilter; +import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.commons.support.scanning.ClassFilter; + +/** + * Unit tests for {@link DefaultClasspathScanner}. + * + * @since 1.0 + */ +@TrackLogRecords +class DefaultClasspathScannerTests { + + private static final ClassFilter allClasses = ClassFilter.of(__ -> true); + private static final ResourceFilter allResources = ResourceFilter.of(__ -> true); + + private final List> loadedClasses = new ArrayList<>(); + + private final BiFunction>> trackingClassLoader = (name, + classLoader) -> ReflectionUtils.tryToLoadClass(name, classLoader).ifSuccess(loadedClasses::add); + + private final DefaultClasspathScanner classpathScanner = new DefaultClasspathScanner( + ClassLoaderUtils::getDefaultClassLoader, trackingClassLoader); + + @Test + void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccursWithNullDetailedMessage( + LogRecordListener listener) throws Exception { + + Predicate> malformedClassNameSimulationFilter = clazz -> { + if (clazz.getSimpleName().equals(ClassForMalformedClassNameSimulation.class.getSimpleName())) { + throw new InternalError(); + } + return true; + }; + + assertClassesScannedWhenExceptionIsThrown(malformedClassNameSimulationFilter); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); + } + + @Test + void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccurs(LogRecordListener listener) + throws Exception { + + Predicate> malformedClassNameSimulationFilter = clazz -> { + if (clazz.getSimpleName().equals(ClassForMalformedClassNameSimulation.class.getSimpleName())) { + throw new InternalError("Malformed class name"); + } + return true; + }; + + assertClassesScannedWhenExceptionIsThrown(malformedClassNameSimulationFilter); + assertDebugMessageLogged(listener, "The java.lang.Class loaded from path .+ has a malformed class name .+"); + } + + @Test + void scanForClassesInClasspathRootWhenOtherInternalErrorOccurs(LogRecordListener listener) throws Exception { + Predicate> otherInternalErrorSimulationFilter = clazz -> { + if (clazz.getSimpleName().equals(ClassForOtherInternalErrorSimulation.class.getSimpleName())) { + throw new InternalError("other internal error"); + } + return true; + }; + + assertClassesScannedWhenExceptionIsThrown(otherInternalErrorSimulationFilter); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); + } + + @Test + void scanForClassesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordListener listener) throws Exception { + Predicate> runtimeExceptionSimulationFilter = clazz -> { + if (clazz.getSimpleName().equals(ClassForGenericRuntimeExceptionSimulation.class.getSimpleName())) { + throw new RuntimeException("a generic exception"); + } + return true; + }; + + assertClassesScannedWhenExceptionIsThrown(runtimeExceptionSimulationFilter); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); + } + + private void assertClassesScannedWhenExceptionIsThrown(Predicate> filter) throws Exception { + var classFilter = ClassFilter.of(filter); + var classes = this.classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), classFilter); + assertThat(classes).hasSizeGreaterThanOrEqualTo(150); + } + + @Test + void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordListener listener) throws Exception { + Predicate runtimeExceptionSimulationFilter = resource -> { + if (resource.getName().equals("org/junit/platform/commons/other-example.resource")) { + throw new RuntimeException("a generic exception"); + } + return true; + }; + + assertResourcesScannedWhenExceptionIsThrown(runtimeExceptionSimulationFilter); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); + } + + private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { + var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), + ResourceFilter.of(filter)); + assertThat(resources).hasSizeGreaterThanOrEqualTo(150); + } + + private void assertDebugMessageLogged(LogRecordListener listener, String regex) { + // @formatter:off + assertThat(listener.stream(DefaultClasspathScanner.class, Level.FINE) + .map(LogRecord::getMessage) + .filter(m -> m.matches(regex)) + ).hasSize(1); + // @formatter:on + } + + @Test + void scanForClassesInClasspathRootWhenOutOfMemoryErrorOccurs() { + Predicate> outOfMemoryErrorSimulationFilter = clazz -> { + if (clazz.getSimpleName().equals(ClassForOutOfMemoryErrorSimulation.class.getSimpleName())) { + throw new OutOfMemoryError(); + } + return true; + }; + var classFilter = ClassFilter.of(outOfMemoryErrorSimulationFilter); + + assertThrows(OutOfMemoryError.class, + () -> this.classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), classFilter)); + } + + @Test + void scanForClassesInClasspathRootWithinJarFile() throws Exception { + scanForClassesInClasspathRootWithinJarFile("/jartest.jar"); + } + + @Test + void scanForClassesInClasspathRootWithinJarWithSpacesInPath() throws Exception { + scanForClassesInClasspathRootWithinJarFile("/folder with spaces/jar test with spaces.jar"); + } + + private void scanForClassesInClasspathRootWithinJarFile(String resourceName) throws Exception { + var jarfile = getClass().getResource(resourceName); + + try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { + var classpathScanner = new DefaultClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var classes = classpathScanner.scanForClassesInClasspathRoot(jarfile.toURI(), allClasses); + assertThat(classes).extracting(Class::getName) // + .containsExactlyInAnyOrder("org.junit.platform.jartest.notincluded.NotIncluded", + "org.junit.platform.jartest.included.recursive.RecursivelyIncluded", + "org.junit.platform.jartest.included.Included"); + } + } + + @Test + void scanForResourcesInClasspathRootWithinJarFile() throws Exception { + scanForResourcesInClasspathRootWithinJarFile("/jartest.jar"); + } + + @Test + void scanForResourcesInClasspathRootWithinJarWithSpacesInPath() throws Exception { + scanForResourcesInClasspathRootWithinJarFile("/folder with spaces/jar test with spaces.jar"); + } + + private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) throws Exception { + var jarfile = getClass().getResource(resourceName); + + try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { + var classpathScanner = new DefaultClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var resources = classpathScanner.scanForResourcesInClasspathRoot(jarfile.toURI(), allResources); + assertThat(resources).extracting(Resource::getName) // + .containsExactlyInAnyOrder("org/junit/platform/jartest/notincluded/not-included.resource", + "org/junit/platform/jartest/included/included.resource", + "org/junit/platform/jartest/included/recursive/recursively-included.resource", + "META-INF/MANIFEST.MF"); + } + } + + @Test + void scanForResourcesInShadowedClassPathRoot() throws Exception { + var jarFile = getClass().getResource("/jartest.jar"); + var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); + + try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { + var classpathScanner = new DefaultClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var resources = classpathScanner.scanForResourcesInClasspathRoot(shadowedJarFile.toURI(), allResources); + assertThat(resources).extracting(Resource::getName).containsExactlyInAnyOrder( + "org/junit/platform/jartest/included/unique.resource", // + "org/junit/platform/jartest/included/included.resource", // + "org/junit/platform/jartest/included/recursive/recursively-included.resource", // + "META-INF/MANIFEST.MF"); + + assertThat(resources).extracting(Resource::getUri) // + .map(DefaultClasspathScannerTests::jarFileAndEntry) // + .containsExactlyInAnyOrder( + // This resource only exists in the shadowed jar file + "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", + // These resources exist in both the jar and shadowed jar file. + // They must be discovered in the shadowed jar as we're searching in that classpath root. + "jartest-shadowed.jar!/org/junit/platform/jartest/included/included.resource", + "jartest-shadowed.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", + "jartest-shadowed.jar!/META-INF/MANIFEST.MF"); + } + } + + @Test + void scanForResourcesInPackageWithDuplicateResources() throws Exception { + var jarFile = getClass().getResource("/jartest.jar"); + var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); + + try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { + var classpathScanner = new DefaultClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", + allResources); + + assertThat(resources).extracting(Resource::getUri) // + .map(DefaultClasspathScannerTests::jarFileAndEntry) // + .containsExactlyInAnyOrder( + // This resource only exists in the shadowed jar file + "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", + // These resources exist in both the jar and shadowed jar file. + "jartest.jar!/org/junit/platform/jartest/included/included.resource", + "jartest-shadowed.jar!/org/junit/platform/jartest/included/included.resource", + "jartest.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", + "jartest-shadowed.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource"); + } + } + + private static String jarFileAndEntry(URI uri) { + var uriString = uri.toString(); + int lastJarUriSeparator = uriString.lastIndexOf("!/"); + var jarUri = uriString.substring(0, lastJarUriSeparator); + var jarEntry = uriString.substring(lastJarUriSeparator + 1); + var fileName = jarUri.substring(jarUri.lastIndexOf("/") + 1); + return fileName + "!" + jarEntry; + } + + @Test + void scanForClassesInPackage() { + var classes = classpathScanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); + assertThat(classes).hasSizeGreaterThanOrEqualTo(20); + assertTrue(classes.contains(NestedClassToBeFound.class)); + assertTrue(classes.contains(MemberClassToBeFound.class)); + } + + @Test + void scanForResourcesInPackage() { + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); + assertThat(resources).extracting(Resource::getUri).containsExactlyInAnyOrder( + uriOf("/org/junit/platform/commons/example.resource"), + uriOf("/org/junit/platform/commons/other-example.resource")); + } + + @Test // #2500 + @DisabledInEclipse + void scanForClassesInPackageWithinModulesSharingNamePrefix(@TempDir Path temp) throws Exception { + var moduleSourcePath = Path.of(getClass().getResource("/modules-2500/").toURI()).toString(); + run("javac", "--module", "foo,foo.bar", "--module-source-path", moduleSourcePath, "-d", temp.toString()); + + checkModules2500(ModuleFinder.of(temp)); // exploded modules + + var foo = temp.resolve("foo.jar"); + var bar = temp.resolve("foo.bar.jar"); + run("jar", "--create", "--file", foo.toString(), "-C", temp.resolve("foo").toString(), "."); + run("jar", "--create", "--file", bar.toString(), "-C", temp.resolve("foo.bar").toString(), "."); + + checkModules2500(ModuleFinder.of(foo, bar)); // jarred modules + + System.gc(); // required on Windows in order to release JAR file handles + } + + private static int run(String tool, String... args) { + return ToolProvider.findFirst(tool).orElseThrow().run(System.out, System.err, args); + } + + private void checkModules2500(ModuleFinder finder) { + var root = "foo.bar"; + var before = ModuleFinder.of(); + var boot = ModuleLayer.boot(); + var configuration = boot.configuration().resolve(before, finder, Set.of(root)); + var parent = ClassLoader.getPlatformClassLoader(); + var layer = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(boot), parent).layer(); + + var classpathScanner = new DefaultClasspathScanner(() -> layer.findLoader(root), + ReflectionUtils::tryToLoadClass); + { + var classes = classpathScanner.scanForClassesInPackage("foo", allClasses); + var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); + assertThat(classNames).hasSize(2).contains("foo.Foo", "foo.bar.FooBar"); + } + { + var classes = classpathScanner.scanForClassesInPackage("foo.bar", allClasses); + var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); + assertThat(classNames).hasSize(1).contains("foo.bar.FooBar"); + } + } + + @Test + void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { + var jarFile = getClass().getResource("/jartest.jar"); + var jarUri = URI.create("jar:" + jarFile); + + try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { + var classpathScanner = new DefaultClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var results = executeConcurrently(10, + () -> classpathScanner.scanForClassesInPackage("org.junit.platform.jartest.included", allClasses)); + + assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), + "FileSystem should be closed"); + + results.forEach(classes -> assertThat(classes) // + .hasSize(2) // + .extracting(Class::getSimpleName) // + .containsExactlyInAnyOrder("Included", "RecursivelyIncluded")); + } + } + + @Test + void findAllResourcesInPackageWithinJarFileConcurrently() throws Exception { + var jarFile = getClass().getResource("/jartest.jar"); + var jarUri = URI.create("jar:" + jarFile); + + try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { + var classpathScanner = new DefaultClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var results = executeConcurrently(10, + () -> classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", allResources)); + + assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), + "FileSystem should be closed"); + + // @formatter:off + results.forEach(resources -> assertThat(resources) + .hasSize(2) + .extracting(Resource::getName).containsExactlyInAnyOrder( + "org/junit/platform/jartest/included/included.resource", + "org/junit/platform/jartest/included/recursive/recursively-included.resource" + )); + // @formatter:on + } + } + + @Test + void scanForClassesInDefaultPackage() { + var classFilter = ClassFilter.of(this::inDefaultPackage); + var classes = classpathScanner.scanForClassesInPackage("", classFilter); + + assertThat(classes).as("number of classes found in default package").isNotEmpty(); + assertTrue(classes.stream().allMatch(this::inDefaultPackage)); + assertTrue(classes.stream().anyMatch(clazz -> "DefaultPackageTestCase".equals(clazz.getName()))); + } + + @Test + void scanForResourcesInDefaultPackage() { + var resourceFilter = ResourceFilter.of(this::inDefaultPackage); + var resources = classpathScanner.scanForResourcesInPackage("", resourceFilter); + + assertThat(resources).as("number of resources found in default package").isNotEmpty(); + assertTrue(resources.stream().allMatch(this::inDefaultPackage)); + assertTrue(resources.stream().anyMatch(resource -> "default-package.resource".equals(resource.getName()))); + } + + @Test + void scanForClassesInPackageWithFilter() { + var thisClassOnly = ClassFilter.of(clazz -> clazz == DefaultClasspathScannerTests.class); + var classes = classpathScanner.scanForClassesInPackage("org.junit.platform.commons", thisClassOnly); + assertSame(DefaultClasspathScannerTests.class, classes.getFirst()); + } + + @Test + void scanForResourcesInPackageWithFilter() { + var thisResourceOnly = ResourceFilter.of( + resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); + assertThat(resources).extracting(Resource::getName).containsExactly( + "org/junit/platform/commons/example.resource"); + } + + @Test + void resourcesCanBeRead() throws IOException { + var thisResourceOnly = ResourceFilter.of( + resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); + Resource resource = resources.getFirst(); + + assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); + assertThat(resource.getUri()).isEqualTo(uriOf("/org/junit/platform/commons/example.resource")); + try (InputStream is = resource.getInputStream()) { + String contents = new String(is.readAllBytes(), StandardCharsets.UTF_8); + assertThat(contents).isEqualTo("This file was unintentionally left blank.\n"); + } + } + + @Test + void scanForClassesInPackageForNullBasePackage() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForClassesInPackage(null, allClasses)); + } + + @Test + void scanForResourcesInPackageForNullBasePackage() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForResourcesInPackage(null, allResources)); + } + + @Test + void scanForClassesInPackageForWhitespaceBasePackage() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForClassesInPackage(" ", allClasses)); + } + + @Test + void scanForResourcesInPackageForWhitespaceBasePackage() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForResourcesInPackage(" ", allResources)); + } + + @Test + void scanForClassesInPackageForNullClassFilter() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForClassesInPackage("org.junit.platform.commons", null)); + } + + @Test + void scanForClassesInPackageWhenIOExceptionOccurs() { + var scanner = new DefaultClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); + var classes = scanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); + assertThat(classes).isEmpty(); + } + + @Test + void scanForResourcesInPackageWhenIOExceptionOccurs() { + var scanner = new DefaultClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); + var classes = scanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); + assertThat(classes).isEmpty(); + } + + @Test + void scanForClassesInPackageOnlyLoadsClassesThatAreIncludedByTheClassNameFilter() { + Predicate classNameFilter = name -> DefaultClasspathScannerTests.class.getName().equals(name); + var classFilter = ClassFilter.of(classNameFilter, type -> true); + + classpathScanner.scanForClassesInPackage("org.junit.platform.commons", classFilter); + + assertThat(loadedClasses).containsExactly(DefaultClasspathScannerTests.class); + } + + @Test + void findAllClassesInClasspathRoot() throws Exception { + var thisClassOnly = ClassFilter.of(clazz -> clazz == DefaultClasspathScannerTests.class); + var root = getTestClasspathRoot(); + var classes = classpathScanner.scanForClassesInClasspathRoot(root, thisClassOnly); + assertSame(DefaultClasspathScannerTests.class, classes.getFirst()); + } + + @Test + void findAllClassesInDefaultPackageInClasspathRoot() throws Exception { + var classFilter = ClassFilter.of(this::inDefaultPackage); + var classes = classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), classFilter); + + assertEquals(1, classes.size(), "number of classes found in default package"); + var testClass = classes.getFirst(); + assertTrue(inDefaultPackage(testClass)); + assertEquals("DefaultPackageTestCase", testClass.getName()); + } + + @Test + void doesNotLoopInfinitelyWithCircularSymlinks(@TempDir Path tempDir) throws Exception { + + // Abort if running on Microsoft Windows since we are testing symbolic links + assumeFalse(System.getProperty("os.name").toLowerCase().contains("win")); + + var directory = Files.createDirectory(tempDir.resolve("directory")); + var symlink1 = Files.createSymbolicLink(tempDir.resolve("symlink1"), directory); + Files.createSymbolicLink(directory.resolve("symlink2"), symlink1); + + var classes = classpathScanner.scanForClassesInClasspathRoot(symlink1.toUri(), allClasses); + + assertThat(classes).isEmpty(); + } + + private boolean inDefaultPackage(Class clazz) { + // OpenJDK returns NULL for the default package. + var pkg = clazz.getPackage(); + return pkg == null || "".equals(clazz.getPackage().getName()); + } + + private boolean inDefaultPackage(Resource resource) { + return !resource.getName().contains("/"); + } + + @Test + void findAllClassesInClasspathRootWithFilter() throws Exception { + var root = getTestClasspathRoot(); + var classes = classpathScanner.scanForClassesInClasspathRoot(root, allClasses); + + assertThat(classes).hasSizeGreaterThanOrEqualTo(20); + assertTrue(classes.contains(DefaultClasspathScannerTests.class)); + } + + @Test + void findAllClassesInClasspathRootForNullRoot() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForClassesInClasspathRoot(null, allClasses)); + } + + @Test + void findAllClassesInClasspathRootForNonExistingRoot() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForClassesInClasspathRoot(Paths.get("does_not_exist").toUri(), allClasses)); + } + + @Test + void findAllClassesInClasspathRootForNullClassFilter() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForClassesInClasspathRoot(getTestClasspathRoot(), null)); + } + + @Test + void onlyLoadsClassesInClasspathRootThatAreIncludedByTheClassNameFilter() throws Exception { + var classFilter = ClassFilter.of(name -> DefaultClasspathScannerTests.class.getName().equals(name), + type -> true); + var root = getTestClasspathRoot(); + + classpathScanner.scanForClassesInClasspathRoot(root, classFilter); + + assertThat(loadedClasses).containsExactly(DefaultClasspathScannerTests.class); + } + + private static URI uriOf(String name) { + var resource = DefaultClasspathScannerTests.class.getResource(name); + try { + return requireNonNull(resource).toURI(); + } + catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + private URI getTestClasspathRoot() throws Exception { + var location = getClass().getProtectionDomain().getCodeSource().getLocation(); + return location.toURI(); + } + + private URI getTestClasspathResourceRoot() { + // Gradle puts classes and resources in different roots. + var defaultPackageResource = "/default-package.resource"; + var resourceUri = getClass().getResource(defaultPackageResource).toString(); + return URI.create(resourceUri.substring(0, resourceUri.length() - defaultPackageResource.length())); + } + + class MemberClassToBeFound { + } + + static class NestedClassToBeFound { + } + + static class ClassForMalformedClassNameSimulation { + } + + static class ClassForOtherInternalErrorSimulation { + } + + static class ClassForGenericRuntimeExceptionSimulation { + } + + static class ClassForOutOfMemoryErrorSimulation { + } + + private static class ThrowingClassLoader extends ClassLoader { + + @Override + public Enumeration getResources(String name) throws IOException { + throw new IOException("Demo I/O error"); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ExceptionUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ExceptionUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ExceptionUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ExceptionUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/FunctionUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/FunctionUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/FunctionUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/FunctionUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/LruCacheTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/LruCacheTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/LruCacheTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/LruCacheTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ModuleUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ModuleUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ModuleUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ModuleUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PackageUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PackageUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PackageUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PackageUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PreconditionsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PreconditionsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PreconditionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/PreconditionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,16 +13,17 @@ import static java.time.Duration.ofMillis; import static java.util.Arrays.stream; import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.platform.commons.function.Try.success; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.TOP_DOWN; import static org.junit.platform.commons.util.ReflectionUtils.findFields; @@ -66,8 +67,10 @@ import org.junit.jupiter.api.io.TempDir; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.io.Resource; import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.commons.test.TestClassLoader; +import org.junit.platform.commons.util.ReflectionUtils.CycleErrorHandling; import org.junit.platform.commons.util.ReflectionUtilsTests.NestedClassTests.ClassWithNestedClasses.Nested1; import org.junit.platform.commons.util.ReflectionUtilsTests.NestedClassTests.ClassWithNestedClasses.Nested2; import org.junit.platform.commons.util.ReflectionUtilsTests.NestedClassTests.ClassWithNestedClasses.Nested3; @@ -264,7 +267,7 @@ } /** - * @see #3684 + * @see #3684 */ @Test void getInterfaceMethodIfPossible() throws Exception { @@ -284,6 +287,23 @@ assertThat(interfaceMethod.getDeclaringClass()).isEqualTo(Closeable.class); } + @Test + void isRecordObject() { + assertTrue(ReflectionUtils.isRecordObject(new SomeRecord(1))); + assertFalse(ReflectionUtils.isRecordObject(new ClassWithOneCustomConstructor(""))); + assertFalse(ReflectionUtils.isRecordObject(null)); + } + + @Test + void isRecordClass() { + assertTrue(ReflectionUtils.isRecordClass(SomeRecord.class)); + assertFalse(ReflectionUtils.isRecordClass(ClassWithOneCustomConstructor.class)); + assertFalse(ReflectionUtils.isRecordClass(Object.class)); + } + + record SomeRecord(int n) { + } + static class ClassWithVoidAndNonVoidMethods { void voidMethod() { @@ -516,22 +536,19 @@ @Test void isAssignableToForNullSourceType() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> ReflectionUtils.isAssignableTo(null, getClass()))// + assertPreconditionViolationFor(() -> ReflectionUtils.isAssignableTo(null, getClass()))// .withMessage("source type must not be null"); } @Test void isAssignableToForPrimitiveSourceType() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> ReflectionUtils.isAssignableTo(int.class, Integer.class))// + assertPreconditionViolationFor(() -> ReflectionUtils.isAssignableTo(int.class, Integer.class))// .withMessage("source type must not be a primitive type"); } @Test void isAssignableToForNullTargetType() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> ReflectionUtils.isAssignableTo(getClass(), null))// + assertPreconditionViolationFor(() -> ReflectionUtils.isAssignableTo(getClass(), null))// .withMessage("target type must not be null"); } @@ -560,6 +577,9 @@ assertTrue(ReflectionUtils.isAssignableTo(Integer.class, int.class)); assertTrue(ReflectionUtils.isAssignableTo(Boolean.class, boolean.class)); + // Void to void + assertFalse(ReflectionUtils.isAssignableTo(Void.class, void.class)); + // Widening Conversions from Wrappers to Primitives assertTrue(ReflectionUtils.isAssignableTo(Integer.class, long.class)); assertTrue(ReflectionUtils.isAssignableTo(Float.class, double.class)); @@ -710,6 +730,47 @@ } @Nested + class ResourceLoadingTests { + + @Test + void tryToGetResourcePreconditions() { + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResources("")); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResources(" ")); + + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResources(null)); + assertThrows(PreconditionViolationException.class, + () -> ReflectionUtils.tryToGetResources("org/junit/platform/commons/example.resource", null)); + } + + @Test + void tryToGetResource() { + var tryToGetResource = ReflectionUtils.tryToGetResources("org/junit/platform/commons/example.resource"); + var resource = assertDoesNotThrow(tryToGetResource::get); + assertAll( // + () -> assertThat(resource).hasSize(1), // + () -> assertThat(resource).extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource")); + } + + @Test + void tryToGetResourceWithPrefixedSlash() { + var tryToGetResource = ReflectionUtils.tryToGetResources("/org/junit/platform/commons/example.resource"); + var resource = assertDoesNotThrow(tryToGetResource::get); + assertAll( // + () -> assertThat(resource).hasSize(1), // + () -> assertThat(resource).extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource")); + } + + @Test + void tryToGetResourceWhenResourceNotFound() { + var tryToGetResource = ReflectionUtils.tryToGetResources("org/junit/platform/commons/no-such.resource"); + var resource = assertDoesNotThrow(tryToGetResource::get); + assertThat(resource).isEmpty(); + } + } + + @Nested class ClassLoadingTests { @Test @@ -758,71 +819,132 @@ @Test void tryToLoadClass() { - assertThat(ReflectionUtils.tryToLoadClass(Integer.class.getName())).isEqualTo(success(Integer.class)); + assertTryToLoadClass(getClass().getName(), getClass()); + assertTryToLoadClass(Integer.class.getName(), Integer.class); + assertTryToLoadClass(Void.class.getName(), Void.class); } @Test void tryToLoadClassTrimsClassName() { - assertThat(ReflectionUtils.tryToLoadClass(" " + Integer.class.getName() + "\t"))// - .isEqualTo(success(Integer.class)); + assertTryToLoadClass(" " + Integer.class.getName() + "\t", Integer.class); } @Test - void tryToLoadClassForPrimitive() { - assertThat(ReflectionUtils.tryToLoadClass(int.class.getName())).isEqualTo(success(int.class)); + void tryToLoadClassForVoidPseudoPrimitiveType() { + assertTryToLoadClass("void", void.class); } @Test - void tryToLoadClassForPrimitiveArray() { - assertThat(ReflectionUtils.tryToLoadClass(int[].class.getName())).isEqualTo(success(int[].class)); + void tryToLoadClassForPrimitiveType() { + assertTryToLoadClass("boolean", boolean.class); + assertTryToLoadClass("char", char.class); + assertTryToLoadClass("byte", byte.class); + assertTryToLoadClass("short", short.class); + assertTryToLoadClass("int", int.class); + assertTryToLoadClass("long", long.class); + assertTryToLoadClass("float", float.class); + assertTryToLoadClass("double", double.class); } @Test - void tryToLoadClassForPrimitiveArrayUsingSourceCodeSyntax() { - assertThat(ReflectionUtils.tryToLoadClass("int[]")).isEqualTo(success(int[].class)); + void tryToLoadClassForBinaryPrimitiveArrayName() { + assertTryToLoadClass("[Z", boolean[].class); + assertTryToLoadClass("[C", char[].class); + assertTryToLoadClass("[B", byte[].class); + assertTryToLoadClass("[S", short[].class); + assertTryToLoadClass("[I", int[].class); + assertTryToLoadClass("[J", long[].class); + assertTryToLoadClass("[F", float[].class); + assertTryToLoadClass("[D", double[].class); } @Test - void tryToLoadClassForObjectArray() { - assertThat(ReflectionUtils.tryToLoadClass(String[].class.getName())).isEqualTo(success(String[].class)); + void tryToLoadClassForCanonicalPrimitiveArrayName() { + assertTryToLoadClass("boolean[]", boolean[].class); + assertTryToLoadClass("char[]", char[].class); + assertTryToLoadClass("byte[]", byte[].class); + assertTryToLoadClass("short[]", short[].class); + assertTryToLoadClass("int[]", int[].class); + assertTryToLoadClass("long[]", long[].class); + assertTryToLoadClass("float[]", float[].class); + assertTryToLoadClass("double[]", double[].class); } @Test - void tryToLoadClassForObjectArrayUsingSourceCodeSyntax() { - assertThat(ReflectionUtils.tryToLoadClass("java.lang.String[]")).isEqualTo(success(String[].class)); + void tryToLoadClassForBinaryObjectArrayName() { + assertTryToLoadClass(String[].class.getName(), String[].class); } @Test - void tryToLoadClassForTwoDimensionalPrimitiveArray() { - assertThat(ReflectionUtils.tryToLoadClass(int[][].class.getName())).isEqualTo(success(int[][].class)); + void tryToLoadClassForCanonicalObjectArrayName() { + assertTryToLoadClass("java.lang.String[]", String[].class); } @Test - void tryToLoadClassForTwoDimensionaldimensionalPrimitiveArrayUsingSourceCodeSyntax() { - assertThat(ReflectionUtils.tryToLoadClass("int[][]")).isEqualTo(success(int[][].class)); + void tryToLoadClassForBinaryTwoDimensionalPrimitiveArrayName() { + assertTryToLoadClass("[[Z", boolean[][].class); + assertTryToLoadClass("[[C", char[][].class); + assertTryToLoadClass("[[B", byte[][].class); + assertTryToLoadClass("[[S", short[][].class); + assertTryToLoadClass("[[I", int[][].class); + assertTryToLoadClass("[[J", long[][].class); + assertTryToLoadClass("[[F", float[][].class); + assertTryToLoadClass("[[D", double[][].class); } @Test - void tryToLoadClassForMultidimensionalPrimitiveArray() { - assertThat(ReflectionUtils.tryToLoadClass(int[][][][][].class.getName()))// - .isEqualTo(success(int[][][][][].class)); + void tryToLoadClassForCanonicalTwoDimensionalPrimitiveArrayName() { + assertTryToLoadClass("boolean[][]", boolean[][].class); + assertTryToLoadClass("char[][]", char[][].class); + assertTryToLoadClass("byte[][]", byte[][].class); + assertTryToLoadClass("short[][]", short[][].class); + assertTryToLoadClass("int[][]", int[][].class); + assertTryToLoadClass("long[][]", long[][].class); + assertTryToLoadClass("float[][]", float[][].class); + assertTryToLoadClass("double[][]", double[][].class); } @Test - void tryToLoadClassForMultidimensionalPrimitiveArrayUsingSourceCodeSyntax() { - assertThat(ReflectionUtils.tryToLoadClass("int[][][][][]")).isEqualTo(success(int[][][][][].class)); + void tryToLoadClassForBinaryMultidimensionalPrimitiveArrayName() { + assertTryToLoadClass("[[[[[Z", boolean[][][][][].class); + assertTryToLoadClass("[[[[[C", char[][][][][].class); + assertTryToLoadClass("[[[[[B", byte[][][][][].class); + assertTryToLoadClass("[[[[[S", short[][][][][].class); + assertTryToLoadClass("[[[[[I", int[][][][][].class); + assertTryToLoadClass("[[[[[J", long[][][][][].class); + assertTryToLoadClass("[[[[[F", float[][][][][].class); + assertTryToLoadClass("[[[[[D", double[][][][][].class); } @Test - void tryToLoadClassForMultidimensionalObjectArray() { - assertThat(ReflectionUtils.tryToLoadClass(String[][][][][].class.getName()))// - .isEqualTo(success(String[][][][][].class)); + void tryToLoadClassForCanonicalMultidimensionalPrimitiveArrayName() { + assertTryToLoadClass("boolean[][][][][]", boolean[][][][][].class); + assertTryToLoadClass("char[][][][][]", char[][][][][].class); + assertTryToLoadClass("byte[][][][][]", byte[][][][][].class); + assertTryToLoadClass("short[][][][][]", short[][][][][].class); + assertTryToLoadClass("int[][][][][]", int[][][][][].class); + assertTryToLoadClass("long[][][][][]", long[][][][][].class); + assertTryToLoadClass("float[][][][][]", float[][][][][].class); + assertTryToLoadClass("double[][][][][]", double[][][][][].class); } @Test - void tryToLoadClassForMultidimensionalObjectArrayUsingSourceCodeSyntax() { - assertThat(ReflectionUtils.tryToLoadClass("java.lang.String[][][][][]"))// - .isEqualTo(success(String[][][][][].class)); + void tryToLoadClassForBinaryMultidimensionalObjectArrayName() { + assertTryToLoadClass(String[][][][][].class.getName(), String[][][][][].class); + } + + @Test + void tryToLoadClassForCanonicalMultidimensionalObjectArrayName() { + assertTryToLoadClass("java.lang.String[][][][][]", String[][][][][].class); + } + + private static void assertTryToLoadClass(String name, Class type) { + try { + assertThat(ReflectionUtils.tryToLoadClass(name).get()).as(name).isEqualTo(type); + } + catch (Exception ex) { + ExceptionUtils.throwAsUncheckedException(ex); + } } } @@ -914,23 +1036,43 @@ } @Test + void isNestedClassPresentPreconditions() { + // @formatter:off + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.isNestedClassPresent(null, null, null)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.isNestedClassPresent(null, clazz -> true, CycleErrorHandling.THROW_EXCEPTION)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.isNestedClassPresent(getClass(), null, CycleErrorHandling.ABORT_VISIT)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.isNestedClassPresent(getClass(), clazz -> true, null)); + // @formatter:on + } + + @Test void findNestedClasses() { // @formatter:off assertThat(findNestedClasses(Object.class)).isEmpty(); + assertThat(isNestedClassPresent(Object.class)).isFalse(); assertThat(findNestedClasses(ClassWithNestedClasses.class)) .containsOnly(Nested1.class, Nested2.class, Nested3.class); + assertThat(isNestedClassPresent(ClassWithNestedClasses.class)) + .isTrue(); assertThat(ReflectionUtils.findNestedClasses(ClassWithNestedClasses.class, clazz -> clazz.getName().contains("1"))) .containsExactly(Nested1.class); + assertThat(ReflectionUtils.isNestedClassPresent(ClassWithNestedClasses.class, clazz -> clazz.getName().contains("1"), CycleErrorHandling.THROW_EXCEPTION)) + .isTrue(); assertThat(ReflectionUtils.findNestedClasses(ClassWithNestedClasses.class, ReflectionUtils::isStatic)) .containsExactly(Nested3.class); + assertThat(ReflectionUtils.isNestedClassPresent(ClassWithNestedClasses.class, ReflectionUtils::isStatic, CycleErrorHandling.THROW_EXCEPTION)) + .isTrue(); assertThat(findNestedClasses(ClassExtendingClassWithNestedClasses.class)) .containsOnly(Nested1.class, Nested2.class, Nested3.class, Nested4.class, Nested5.class); + assertThat(isNestedClassPresent(ClassExtendingClassWithNestedClasses.class)) + .isTrue(); assertThat(findNestedClasses(ClassWithNestedClasses.Nested1.class)).isEmpty(); + assertThat(isNestedClassPresent(ClassWithNestedClasses.Nested1.class)).isFalse(); // @formatter:on } @@ -941,26 +1083,41 @@ void findNestedClassesWithSeeminglyRecursiveHierarchies() { assertThat(findNestedClasses(AbstractOuterClass.class))// .containsExactly(AbstractOuterClass.InnerClass.class); + assertThat(isNestedClassPresent(AbstractOuterClass.class))// + .isTrue(); // OuterClass contains recursive hierarchies, but the non-matching // predicate should prevent cycle detection. - // See https://github.com/junit-team/junit5/issues/2249 + // See https://github.com/junit-team/junit-framework/issues/2249 assertThat(ReflectionUtils.findNestedClasses(OuterClass.class, clazz -> false)).isEmpty(); + assertThat(ReflectionUtils.isNestedClassPresent(OuterClass.class, clazz -> false, + CycleErrorHandling.THROW_EXCEPTION)).isFalse(); + // RecursiveInnerInnerClass is part of a recursive hierarchy, but the non-matching // predicate should prevent cycle detection. assertThat(ReflectionUtils.findNestedClasses(RecursiveInnerInnerClass.class, clazz -> false)).isEmpty(); + assertThat(ReflectionUtils.isNestedClassPresent(RecursiveInnerInnerClass.class, clazz -> false, + CycleErrorHandling.THROW_EXCEPTION)).isFalse(); // Sibling types don't actually result in cycles. assertThat(findNestedClasses(StaticNestedSiblingClass.class))// .containsExactly(AbstractOuterClass.InnerClass.class); + assertThat(isNestedClassPresent(StaticNestedSiblingClass.class))// + .isTrue(); assertThat(findNestedClasses(InnerSiblingClass.class))// .containsExactly(AbstractOuterClass.InnerClass.class); + assertThat(isNestedClassPresent(InnerSiblingClass.class))// + .isTrue(); // Interfaces with static nested classes assertThat(findNestedClasses(OuterClassImplementingInterface.class))// .containsExactly(InnerClassImplementingInterface.class, Nested4.class); + assertThat(isNestedClassPresent(OuterClassImplementingInterface.class))// + .isTrue(); assertThat(findNestedClasses(InnerClassImplementingInterface.class))// .containsExactly(Nested4.class); + assertThat(isNestedClassPresent(InnerClassImplementingInterface.class))// + .isTrue(); } /** @@ -982,6 +1139,10 @@ return ReflectionUtils.findNestedClasses(clazz, c -> true); } + private static boolean isNestedClassPresent(Class clazz) { + return ReflectionUtils.isNestedClassPresent(clazz, c -> true, CycleErrorHandling.THROW_EXCEPTION); + } + private void assertNestedCycle(Class from, Class to) { assertNestedCycle(from, from, to); } @@ -1316,7 +1477,7 @@ /** * @since 1.9.1 - * @see https://github.com/junit-team/junit5/issues/2993 + * @see https://github.com/junit-team/junit-framework/issues/2993 */ @Test void findMethodsFindsDistinctMethodsDeclaredInMultipleInterfaces() { @@ -1446,7 +1607,7 @@ var methods = findMethods(MethodShadowingChild.class, method -> true, TOP_DOWN); assertEquals(6, methods.size()); - assertEquals(MethodShadowingInterface.class.getMethod("method2", int.class, int.class), methods.get(0)); + assertEquals(MethodShadowingInterface.class.getMethod("method2", int.class, int.class), methods.getFirst()); assertThat(methods.subList(1, 3)).containsOnly( MethodShadowingParent.class.getMethod("method2", int.class, int.class, int.class), MethodShadowingParent.class.getMethod("method5", String.class)); @@ -1550,7 +1711,6 @@ var methods = findMethods(child, method -> true, TOP_DOWN); assertEquals(9, methods.size()); - methods.forEach(System.err::println); assertThat(methods.subList(0, 2)).containsOnly(ifcMethod1, ifcMethod2); assertThat(methods.subList(2, 6)).containsOnly(parentMethod1, parentMethod2, parentMethod4, parentMethod5); assertThat(methods.subList(6, 9)).containsOnly(childMethod1, childMethod4, childMethod5); @@ -1582,7 +1742,7 @@ var methods = findMethods(child, method -> true, TOP_DOWN); assertEquals(6, methods.size()); - assertEquals(ifcMethod2, methods.get(0)); + assertEquals(ifcMethod2, methods.getFirst()); assertThat(methods.subList(1, 3)).containsOnly(parentMethod2, parentMethod5); assertThat(methods.subList(3, 6)).containsOnly(childMethod1, childMethod4, childMethod5); } @@ -1610,7 +1770,7 @@ } @Test - void findMethodsReturnsAllOverloadedMethodsInGenericTypeHieararchy() { + void findMethodsReturnsAllOverloadedMethodsInGenericTypeHierarchy() { Class clazz = InterfaceWithGenericDefaultMethodImpl.class; // Search for all foo(*) methods. @@ -1642,7 +1802,7 @@ // @formatter:off return methods.stream() .map(m -> String.format("%s(%s)", m.getName(), ClassUtils.nullSafeToString(m.getParameterTypes()))) - .collect(toList()); + .toList(); // @formatter:on } @@ -1661,7 +1821,7 @@ } /** - * @see https://github.com/junit-team/junit5/issues/3553 + * @see https://github.com/junit-team/junit-framework/issues/3553 */ @Test void findMethodsDoesNotAllowInstanceMethodToHideStaticMethod() throws Exception { @@ -1848,7 +2008,7 @@ class FindAndReadFieldsTests { /** - * @see https://github.com/junit-team/junit5/issues/3553 + * @see https://github.com/junit-team/junit-framework/issues/3553 */ @Test void findFieldsDoesNotAllowInstanceFieldToHideStaticField() throws Exception { @@ -1896,11 +2056,11 @@ } /** - * @see https://github.com/junit-team/junit5/issues/3646 + * @see https://github.com/junit-team/junit-framework/issues/3646 * @since 1.11 */ @Test - void readFieldValuesFromInteracesAndClassesInTypeHierarchy() { + void readFieldValuesFromInterfacesAndClassesInTypeHierarchy() { var fields = findFields(InterfaceWithField.class, ReflectionUtils::isStatic, TOP_DOWN); var values = readFieldValues(fields, null); assertThat(values).containsOnly("ifc"); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsWithGenericTypeHierarchiesTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsWithGenericTypeHierarchiesTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsWithGenericTypeHierarchiesTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsWithGenericTypeHierarchiesTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/SerializationUtils.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/SerializationUtils.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/SerializationUtils.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/SerializationUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/StringUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/StringUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/StringUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/StringUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ToStringBuilderTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ToStringBuilderTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ToStringBuilderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/ToStringBuilderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AExecutionConditionClass.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AExecutionConditionClass.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AExecutionConditionClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AExecutionConditionClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/ATestExecutionListenerClass.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/ATestExecutionListenerClass.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/ATestExecutionListenerClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/ATestExecutionListenerClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AVanillaEmpty.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AVanillaEmpty.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AVanillaEmpty.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/AVanillaEmpty.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BExecutionConditionClass.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BExecutionConditionClass.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BExecutionConditionClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BExecutionConditionClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BTestExecutionListenerClass.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BTestExecutionListenerClass.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BTestExecutionListenerClass.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BTestExecutionListenerClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BVanillaEmpty.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BVanillaEmpty.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BVanillaEmpty.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/BVanillaEmpty.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/CustomType.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/CustomType.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/CustomType.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/classes/CustomType.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import org.junit.jupiter.api.BeforeAll; /** - * @see https://github.com/junit-team/junit5/issues/3553 + * @see https://github.com/junit-team/junit-framework/issues/3553 */ public class SuperclassWithStaticPackagePrivateBeforeMethod { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import java.nio.file.Path; /** - * @see https://github.com/junit-team/junit5/issues/3553 + * @see https://github.com/junit-team/junit-framework/issues/3553 */ public class SuperclassWithStaticPackagePrivateTempDirField { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,7 +14,7 @@ import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateBeforeMethod; /** - * @see https://github.com/junit-team/junit5/issues/3553 + * @see https://github.com/junit-team/junit-framework/issues/3553 */ public class SubclassWithNonStaticPackagePrivateBeforeMethod extends SuperclassWithStaticPackagePrivateBeforeMethod { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,7 +16,7 @@ import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateTempDirField; /** - * @see https://github.com/junit-team/junit5/issues/3553 + * @see https://github.com/junit-team/junit-framework/issues/3553 */ public class SubclassWithNonStaticPackagePrivateTempDirField extends SuperclassWithStaticPackagePrivateTempDirField { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleDetailsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleDetailsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleDetailsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleDetailsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,7 +17,8 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; import static org.junit.jupiter.api.DynamicTest.dynamicTest; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; +import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN; +import static org.junit.platform.commons.support.ReflectionSupport.findMethods; import static org.junit.platform.commons.util.ReflectionUtils.getFullyQualifiedMethodName; import java.io.File; @@ -41,7 +42,7 @@ import org.junit.jupiter.api.TestReporter; import org.junit.jupiter.api.function.Executable; import org.junit.platform.console.options.Details; -import org.junit.platform.console.options.Theme; +import org.junit.platform.console.output.Theme; import org.opentest4j.TestAbortedException; /** @@ -78,7 +79,7 @@ // String containerName = containerClass.getSimpleName(); List nodes = new ArrayList<>(); Map> map = new EnumMap<>(Details.class); - for (var method : findMethods(containerClass, m -> m.isAnnotationPresent(Test.class))) { + for (var method : findMethods(containerClass, m -> m.isAnnotationPresent(Test.class), TOP_DOWN)) { var methodName = method.getName(); var types = method.getParameterTypes(); for (var details : Details.values()) { @@ -108,6 +109,7 @@ return nodes; } + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("Basic") static class BasicTestCase { @@ -122,6 +124,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("Skip") static class SkipTestCase { @@ -137,6 +140,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("Fail") static class FailTestCase { @@ -152,6 +156,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") @DisplayName("Report") static class ReportTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,10 +14,21 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.console.command.StdStreamTestCase; /** * @since 1.0 @@ -40,8 +51,8 @@ "execute -e junit-jupiter -p org.junit.platform.console.subpackage" // }) void executeWithoutExcludeClassnameOptionDoesNotExcludeClassesAndMustIncludeAllClassesMatchingTheStandardClassnamePattern( - final String line) { - String[] args = line.split(" "); + String line) { + var args = line.split(" "); assertEquals(9, new ConsoleLauncherWrapper().execute(args).getTestsFoundCount()); } @@ -52,8 +63,8 @@ "execute -e junit-jupiter -p org.junit.platform.console.subpackage --exclude-classname" + " ^org\\.junit\\.platform\\.console\\.subpackage\\..*" // }) - void executeWithExcludeClassnameOptionExcludesClasses(final String line) { - String[] args = line.split(" "); + void executeWithExcludeClassnameOptionExcludesClasses(String line) { + var args = line.split(" "); var result = new ConsoleLauncherWrapper().execute(args); assertAll("all subpackage test classes are excluded by the class name filter", // () -> assertArrayEquals(args, result.args), // @@ -62,21 +73,66 @@ ); } + @Test + void executeWithExcludeMethodNameOptionExcludesMethods() { + var line = "execute -e junit-jupiter -p org.junit.platform.console.subpackage --exclude-methodname" + + " ^org\\.junit\\.platform\\.console\\.subpackage\\..+#test"; + var args = line.split(" "); + var result = new ConsoleLauncherWrapper().execute(args); + assertAll("all subpackage test methods are excluded by the method name filter", // + () -> assertArrayEquals(args, result.args), // + () -> assertEquals(0, result.code), // + () -> assertEquals(0, result.getTestsFoundCount()) // + ); + } + @ParameterizedTest @ValueSource(strings = { // "-e junit-jupiter -o java.base", "-e junit-jupiter --select-module java.base", // "execute -e junit-jupiter -o java.base", "execute -e junit-jupiter --select-module java.base" // }) - void executeSelectingModuleNames(final String line) { - String[] args1 = line.split(" "); - assertEquals(0, new ConsoleLauncherWrapper().execute(args1).getTestsFoundCount()); + void executeSelectingModuleNames(String line) { + var args = line.split(" "); + assertEquals(0, new ConsoleLauncherWrapper().execute(args).getTestsFoundCount()); } @ParameterizedTest @ValueSource(strings = { "-e junit-jupiter --scan-modules", "execute -e junit-jupiter --scan-modules" }) - void executeScanModules(final String line) { - String[] args1 = line.split(" "); - assertEquals(0, new ConsoleLauncherWrapper().execute(args1).getTestsFoundCount()); + void executeScanModules(String line) { + var args = line.split(" "); + assertEquals(0, new ConsoleLauncherWrapper().execute(args).getTestsFoundCount()); + } + + @ParameterizedTest + @FieldSource("redirectStreamArguments") + void executeWithRedirectedStdStream(String redirectedStream, int outputFileSize, @TempDir Path tempDir) + throws IOException { + + var outputFile = tempDir.resolve("output.txt"); + var line = String.format("execute -e junit-jupiter --select-class %s %s %s", StdStreamTestCase.class.getName(), + redirectedStream, outputFile); + var args = line.split(" "); + new ConsoleLauncherWrapper().execute(args); + + assertTrue(Files.exists(outputFile), "File does not exist."); + assertEquals(outputFileSize, Files.size(outputFile), "Invalid file size."); + } + + static List redirectStreamArguments = List.of( + arguments("--redirect-stdout", StdStreamTestCase.getStdoutOutputFileSize()), + arguments("--redirect-stderr", StdStreamTestCase.getStderrOutputFileSize())); + + @Test + void executeWithRedirectedStdStreamsToSameFile(@TempDir Path tempDir) throws IOException { + var outputFile = tempDir.resolve("output.txt"); + var line = String.format("execute -e junit-jupiter --select-class %s --redirect-stdout %s --redirect-stderr %s", + StdStreamTestCase.class.getName(), outputFile, outputFile); + var args = line.split(" "); + new ConsoleLauncherWrapper().execute(args); + + assertTrue(Files.exists(outputFile), "File does not exist."); + assertEquals(StdStreamTestCase.getStdoutOutputFileSize() + StdStreamTestCase.getStderrOutputFileSize(), + Files.size(outputFile), "Invalid file size."); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapper.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapper.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapper.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapper.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,8 +17,8 @@ import java.io.StringWriter; import java.util.Optional; -import org.junit.platform.console.options.CommandFacade; -import org.junit.platform.console.tasks.ConsoleTestExecutor; +import org.junit.platform.console.command.CommandFacade; +import org.junit.platform.console.command.ConsoleTestExecutor; /** * @since 1.0 diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapperResult.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapperResult.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapperResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherWrapperResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import java.io.PrintWriter; import java.util.List; -import org.junit.platform.console.options.CommandResult; +import org.junit.platform.console.command.CommandResult; import org.junit.platform.launcher.listeners.TestExecutionSummary; /** diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CommandLineOptionsParsingTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CommandLineOptionsParsingTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CommandLineOptionsParsingTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CommandLineOptionsParsingTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,762 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.engine.discovery.ClassNameFilter.STANDARD_INCLUDE_PATTERN; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResource; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectDirectory; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectFile; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectIteration; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectModule; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUri; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.platform.console.options.Details; +import org.junit.platform.console.options.TestConsoleOutputOptions; +import org.junit.platform.console.options.TestDiscoveryOptions; +import org.junit.platform.console.output.Theme; +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.engine.discovery.FilePosition; + +/** + * @since 1.10 + */ +class CommandLineOptionsParsingTests { + + @Test + void parseNoArguments() { + String[] noArguments = {}; + Result options = parse(noArguments); + + // @formatter:off + assertAll( + () -> assertFalse(options.output.isAnsiColorOutputDisabled()), + () -> assertNull(options.output.getStdoutPath()), + () -> assertNull(options.output.getStderrPath()), + () -> assertEquals(TestConsoleOutputOptions.DEFAULT_DETAILS, options.output.getDetails()), + () -> assertFalse(options.discovery.isScanClasspath()), + () -> assertEquals(List.of(STANDARD_INCLUDE_PATTERN), options.discovery.getIncludedClassNamePatterns()), + () -> assertEquals(List.of(), options.discovery.getExcludedClassNamePatterns()), + () -> assertEquals(List.of(), options.discovery.getIncludedPackages()), + () -> assertEquals(List.of(), options.discovery.getExcludedPackages()), + () -> assertEquals(List.of(), options.discovery.getIncludedMethodNamePatterns()), + () -> assertEquals(List.of(), options.discovery.getExcludedMethodNamePatterns()), + () -> assertEquals(List.of(), options.discovery.getIncludedTagExpressions()), + () -> assertEquals(List.of(), options.discovery.getExcludedTagExpressions()), + () -> assertEquals(List.of(), options.discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(), options.discovery.getSelectedUris()), + () -> assertEquals(List.of(), options.discovery.getSelectedFiles()), + () -> assertEquals(List.of(), options.discovery.getSelectedDirectories()), + () -> assertEquals(List.of(), options.discovery.getSelectedModules()), + () -> assertEquals(List.of(), options.discovery.getSelectedPackages()), + () -> assertEquals(List.of(), options.discovery.getSelectedMethods()), + () -> assertEquals(List.of(), options.discovery.getSelectedClasspathEntries()), + () -> assertEquals(Map.of(), options.discovery.getConfigurationParameters()) + ); + // @formatter:on + } + + @Test + void parseSwitches() { + // @formatter:off + assertAll( + () -> assertTrue(parse("--disable-ansi-colors").output.isAnsiColorOutputDisabled(), "disable ansi"), + () -> assertTrue(parse("--scan-class-path").discovery.isScanClasspath(), "scan class path") + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidDetails(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(Details.VERBOSE, type.parseArgLine("--details verbose").output.getDetails()), + () -> assertEquals(Details.TREE, type.parseArgLine("--details tree").output.getDetails()), + () -> assertEquals(Details.FLAT, type.parseArgLine("--details flat").output.getDetails()), + () -> assertEquals(Details.NONE, type.parseArgLine("--details NONE").output.getDetails()), + () -> assertEquals(Details.NONE, type.parseArgLine("--details none").output.getDetails()), + () -> assertEquals(Details.NONE, type.parseArgLine("--details None").output.getDetails()) + ); + // @formatter:on + } + + @Test + void parseInvalidDetails() { + assertOptionWithMissingRequiredArgumentThrowsException("--details"); + } + + @ParameterizedTest + @EnumSource + void parseValidDetailsTheme(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(Theme.ASCII, type.parseArgLine("--details-theme ascii").output.getTheme()), + () -> assertEquals(Theme.ASCII, type.parseArgLine("--details-theme ASCII").output.getTheme()), + () -> assertEquals(Theme.UNICODE, type.parseArgLine("--details-theme unicode").output.getTheme()), + () -> assertEquals(Theme.UNICODE, type.parseArgLine("--details-theme UNICODE").output.getTheme()), + () -> assertEquals(Theme.UNICODE, type.parseArgLine("--details-theme uniCode").output.getTheme()) + ); + // @formatter:on + } + + @Test + void parseInvalidDetailsTheme() { + assertOptionWithMissingRequiredArgumentThrowsException("--details-theme"); + } + + @ParameterizedTest + @EnumSource + void parseValidIncludeClassNamePatterns(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(".*Test"), type.parseArgLine("-n .*Test").discovery.getIncludedClassNamePatterns()), + () -> assertEquals(List.of(".*Test", ".*Tests"), type.parseArgLine("--include-classname .*Test --include-classname .*Tests").discovery.getIncludedClassNamePatterns()), + () -> assertEquals(List.of(".*Test"), type.parseArgLine("--include-classname=.*Test").discovery.getIncludedClassNamePatterns()) + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidExcludeClassNamePatterns(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(".*Test"), type.parseArgLine("-N .*Test").discovery.getExcludedClassNamePatterns()), + () -> assertEquals(List.of(".*Test", ".*Tests"), type.parseArgLine("--exclude-classname .*Test --exclude-classname .*Tests").discovery.getExcludedClassNamePatterns()), + () -> assertEquals(List.of(".*Test"), type.parseArgLine("--exclude-classname=.*Test").discovery.getExcludedClassNamePatterns()) + ); + // @formatter:on + } + + @Test + void usesDefaultClassNamePatternWithoutExplicitArgument() throws Exception { + assertEquals(List.of(STANDARD_INCLUDE_PATTERN), + ArgsType.args.parseArgLine("").discovery.getIncludedClassNamePatterns()); + } + + @Test + void parseInvalidIncludeClassNamePatterns() { + assertOptionWithMissingRequiredArgumentThrowsException("-n", "--include-classname"); + } + + @Test + void parseInvalidExcludeClassNamePatterns() { + assertOptionWithMissingRequiredArgumentThrowsException("-N", "--exclude-classname"); + } + + @ParameterizedTest + @EnumSource + void parseValidIncludedPackages(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of("org.junit.included"), + type.parseArgLine("--include-package org.junit.included").discovery.getIncludedPackages()), + () -> assertEquals(List.of("org.junit.included"), + type.parseArgLine("--include-package=org.junit.included").discovery.getIncludedPackages()), + () -> assertEquals(List.of("org.junit.included1", "org.junit.included2"), + type.parseArgLine("--include-package org.junit.included1 --include-package org.junit.included2").discovery.getIncludedPackages()) + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidExcludedPackages(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of("org.junit.excluded"), + type.parseArgLine("--exclude-package org.junit.excluded").discovery.getExcludedPackages()), + () -> assertEquals(List.of("org.junit.excluded"), + type.parseArgLine("--exclude-package=org.junit.excluded").discovery.getExcludedPackages()), + () -> assertEquals(List.of("org.junit.excluded1", "org.junit.excluded2"), + type.parseArgLine("--exclude-package org.junit.excluded1 --exclude-package org.junit.excluded2").discovery.getExcludedPackages()) + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidIncludeMethodNamePatterns(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(".+#method.*"), + type.parseArgLine("--include-methodname .+#method.*").discovery.getIncludedMethodNamePatterns()), + () -> assertEquals(List.of(".+#methodA.*", ".+#methodB.*"), + type.parseArgLine("--include-methodname .+#methodA.* --include-methodname .+#methodB.*").discovery.getIncludedMethodNamePatterns()), + () -> assertEquals(List.of(".+#method.*"), + type.parseArgLine("--include-methodname=.+#method.*").discovery.getIncludedMethodNamePatterns()) + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidExcludeMethodNamePatterns(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(".+#method.*"), + type.parseArgLine("--exclude-methodname .+#method.*").discovery.getExcludedMethodNamePatterns()), + () -> assertEquals(List.of(".+#methodA.*", ".+#methodB.*"), + type.parseArgLine("--exclude-methodname .+#methodA.* --exclude-methodname .+#methodB.*").discovery.getExcludedMethodNamePatterns()), + () -> assertEquals(List.of(".+#method.*"), + type.parseArgLine("--exclude-methodname=.+#method.*").discovery.getExcludedMethodNamePatterns()) + ); + // @formatter:on + } + + @Test + void parseInvalidIncludeMethodNamePatterns() { + assertOptionWithMissingRequiredArgumentThrowsException("--include-methodname"); + } + + @Test + void parseInvalidExcludeMethodNamePatterns() { + assertOptionWithMissingRequiredArgumentThrowsException("--exclude-methodname"); + } + + @ParameterizedTest + @EnumSource + void parseValidIncludedTags(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of("fast"), type.parseArgLine("-t fast").discovery.getIncludedTagExpressions()), + () -> assertEquals(List.of("fast"), type.parseArgLine("--include-tag fast").discovery.getIncludedTagExpressions()), + () -> assertEquals(List.of("fast"), type.parseArgLine("--include-tag=fast").discovery.getIncludedTagExpressions()), + () -> assertEquals(List.of("fast", "slow"), type.parseArgLine("-t fast -t slow").discovery.getIncludedTagExpressions()) + ); + // @formatter:on + } + + @Test + void parseInvalidIncludedTags() { + assertOptionWithMissingRequiredArgumentThrowsException("-t", "--include-tag"); + } + + @ParameterizedTest + @EnumSource + void parseValidExcludedTags(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of("fast"), type.parseArgLine("-T fast").discovery.getExcludedTagExpressions()), + () -> assertEquals(List.of("fast"), type.parseArgLine("--exclude-tag fast").discovery.getExcludedTagExpressions()), + () -> assertEquals(List.of("fast"), type.parseArgLine("--exclude-tag=fast").discovery.getExcludedTagExpressions()), + () -> assertEquals(List.of("fast", "slow"), type.parseArgLine("-T fast -T slow").discovery.getExcludedTagExpressions()) + ); + // @formatter:on + } + + @Test + void parseInvalidExcludedTags() { + assertOptionWithMissingRequiredArgumentThrowsException("-T", "--exclude-tag"); + } + + @ParameterizedTest + @EnumSource + void parseValidIncludedEngines(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of("junit-jupiter"), type.parseArgLine("-e junit-jupiter").discovery.getIncludedEngines()), + () -> assertEquals(List.of("junit-vintage"), type.parseArgLine("--include-engine junit-vintage").discovery.getIncludedEngines()), + () -> assertEquals(List.of(), type.parseArgLine("").discovery.getIncludedEngines()) + ); + // @formatter:on + } + + @Test + void parseInvalidIncludedEngines() { + assertOptionWithMissingRequiredArgumentThrowsException("-e", "--include-engine"); + } + + @ParameterizedTest + @EnumSource + void parseValidExcludedEngines(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of("junit-jupiter"), type.parseArgLine("-E junit-jupiter").discovery.getExcludedEngines()), + () -> assertEquals(List.of("junit-vintage"), type.parseArgLine("--exclude-engine junit-vintage").discovery.getExcludedEngines()), + () -> assertEquals(List.of(), type.parseArgLine("").discovery.getExcludedEngines()) + ); + // @formatter:on + } + + @Test + void parseInvalidExcludedEngines() { + assertOptionWithMissingRequiredArgumentThrowsException("-E", "--exclude-engine"); + } + + @ParameterizedTest + @EnumSource + void parseValidAdditionalClasspathEntries(ArgsType type) { + var dir = Paths.get("."); + // @formatter:off + assertAll( + () -> assertEquals(List.of(dir), type.parseArgLine("-cp .").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("--cp .").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("-classpath .").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("-classpath=.").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("--classpath .").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("--classpath=.").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("--class-path .").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("--class-path=.").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir, Path.of("lib/some.jar")), type.parseArgLine("-cp . -cp lib/some.jar").discovery.getAdditionalClasspathEntries()), + () -> assertEquals(List.of(dir, Path.of("lib/some.jar")), type.parseArgLine("-cp ." + File.pathSeparator + "lib/some.jar").discovery.getAdditionalClasspathEntries()) + ); + // @formatter:on + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void parseValidAndAbsoluteAdditionalClasspathEntries() throws Exception { + ArgsType type = ArgsType.args; + assertEquals(List.of(Path.of("C:\\a.jar")), + type.parseArgLine("-cp C:\\a.jar").discovery.getAdditionalClasspathEntries()); + assertEquals(List.of(Path.of("C:\\foo.jar"), Path.of("D:\\bar.jar")), + type.parseArgLine("-cp C:\\foo.jar;D:\\bar.jar").discovery.getAdditionalClasspathEntries()); + } + + @Test + void parseInvalidAdditionalClasspathEntries() { + assertOptionWithMissingRequiredArgumentThrowsException("-cp", "--classpath", "--class-path"); + } + + @Test + void parseInvalidXmlReportsDirs() { + assertOptionWithMissingRequiredArgumentThrowsException("--reports-dir"); + } + + @ParameterizedTest + @EnumSource + void parseValidUriSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("-u file:///foo.txt").discovery.getSelectedUris()), + () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("--u file:///foo.txt").discovery.getSelectedUris()), + () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("-select-uri file:///foo.txt").discovery.getSelectedUris()), + () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("-select-uri=file:///foo.txt").discovery.getSelectedUris()), + () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("--select-uri file:///foo.txt").discovery.getSelectedUris()), + () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("--select-uri=file:///foo.txt").discovery.getSelectedUris()), + () -> assertEquals(List.of(selectUri("file:///foo.txt"), selectUri("https://example")), type.parseArgLine("-u file:///foo.txt -u https://example").discovery.getSelectedUris()), + () -> assertEquals(List.of(selectUri("file:///foo.txt"), selectUri("https://example")), type.parseArgLine("-u file:///foo.txt https://example").discovery.getSelectedUris()) + ); + // @formatter:on + } + + @Test + void parseInvalidUriSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-u", "--select-uri", "-u unknown-scheme:"); + } + + @ParameterizedTest + @EnumSource + void parseValidFileSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("-f foo.txt").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("--f foo.txt").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("-select-file foo.txt").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("-select-file=foo.txt").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("--select-file foo.txt").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("--select-file=foo.txt").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt"), selectFile("bar.csv")), type.parseArgLine("-f foo.txt -f bar.csv").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt"), selectFile("bar.csv")), type.parseArgLine("-f foo.txt bar.csv").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt", FilePosition.from(5))), type.parseArgLine("-f foo.txt?line=5").discovery.getSelectedFiles()), + () -> assertEquals(List.of(selectFile("foo.txt", FilePosition.from(12, 34))), type.parseArgLine("-f foo.txt?line=12&column=34").discovery.getSelectedFiles()) + ); + // @formatter:on + } + + @Test + void parseInvalidFileSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-f", "--select-file"); + } + + @ParameterizedTest + @EnumSource + void parseValidDirectorySelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("-d foo/bar").discovery.getSelectedDirectories()), + () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("--d foo/bar").discovery.getSelectedDirectories()), + () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("-select-directory foo/bar").discovery.getSelectedDirectories()), + () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("-select-directory=foo/bar").discovery.getSelectedDirectories()), + () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("--select-directory foo/bar").discovery.getSelectedDirectories()), + () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("--select-directory=foo/bar").discovery.getSelectedDirectories()), + () -> assertEquals(List.of(selectDirectory("foo/bar"), selectDirectory("bar/qux")), type.parseArgLine("-d foo/bar -d bar/qux").discovery.getSelectedDirectories()), + () -> assertEquals(List.of(selectDirectory("foo/bar"), selectDirectory("bar/qux")), type.parseArgLine("-d foo/bar bar/qux").discovery.getSelectedDirectories()) + ); + // @formatter:on + } + + @Test + void parseInvalidDirectorySelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-d", "--select-directory"); + } + + @ParameterizedTest + @EnumSource + void parseValidModuleSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("-o com.acme.foo").discovery.getSelectedModules()), + () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("--o com.acme.foo").discovery.getSelectedModules()), + () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("-select-module com.acme.foo").discovery.getSelectedModules()), + () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("-select-module=com.acme.foo").discovery.getSelectedModules()), + () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("--select-module com.acme.foo").discovery.getSelectedModules()), + () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("--select-module=com.acme.foo").discovery.getSelectedModules()), + () -> assertEquals(List.of(selectModule("com.acme.foo"), selectModule("com.example.bar")), type.parseArgLine("-o com.acme.foo -o com.example.bar").discovery.getSelectedModules()), + () -> assertEquals(List.of(selectModule("com.acme.foo"), selectModule("com.example.bar")), type.parseArgLine("-o com.acme.foo com.example.bar").discovery.getSelectedModules()) + ); + // @formatter:on + } + + @Test + void parseInvalidModuleSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-o", "--select-module"); + } + + @ParameterizedTest + @EnumSource + void parseValidPackageSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("-p com.acme.foo").discovery.getSelectedPackages()), + () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("--p com.acme.foo").discovery.getSelectedPackages()), + () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("-select-package com.acme.foo").discovery.getSelectedPackages()), + () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("-select-package=com.acme.foo").discovery.getSelectedPackages()), + () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("--select-package com.acme.foo").discovery.getSelectedPackages()), + () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("--select-package=com.acme.foo").discovery.getSelectedPackages()), + () -> assertEquals(List.of(selectPackage("com.acme.foo"), selectPackage("com.example.bar")), type.parseArgLine("-p com.acme.foo -p com.example.bar").discovery.getSelectedPackages()), + () -> assertEquals(List.of(selectPackage("com.acme.foo"), selectPackage("com.example.bar")), type.parseArgLine("-p com.acme.foo com.example.bar").discovery.getSelectedPackages()) + ); + // @formatter:on + } + + @Test + void parseInvalidPackageSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-p", "--select-package"); + } + + @ParameterizedTest + @EnumSource + void parseValidClassSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("-c com.acme.Foo").discovery.getSelectedClasses()), + () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("--c com.acme.Foo").discovery.getSelectedClasses()), + () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("-select-class com.acme.Foo").discovery.getSelectedClasses()), + () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("-select-class=com.acme.Foo").discovery.getSelectedClasses()), + () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("--select-class com.acme.Foo").discovery.getSelectedClasses()), + () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("--select-class=com.acme.Foo").discovery.getSelectedClasses()), + () -> assertEquals(List.of(selectClass("com.acme.Foo"), selectClass("com.example.Bar")), type.parseArgLine("-c com.acme.Foo -c com.example.Bar").discovery.getSelectedClasses()), + () -> assertEquals(List.of(selectClass("com.acme.Foo"), selectClass("com.example.Bar")), type.parseArgLine("-c com.acme.Foo com.example.Bar").discovery.getSelectedClasses()) + ); + // @formatter:on + } + + @Test + void parseInvalidClassSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-c", "--select-class"); + } + + @ParameterizedTest + @EnumSource + void parseValidMethodSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("-m com.acme.Foo#m()").discovery.getSelectedMethods()), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("--m com.acme.Foo#m()").discovery.getSelectedMethods()), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("-select-method com.acme.Foo#m()").discovery.getSelectedMethods()), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("-select-method=com.acme.Foo#m()").discovery.getSelectedMethods()), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("--select-method com.acme.Foo#m()").discovery.getSelectedMethods()), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("--select-method=com.acme.Foo#m()").discovery.getSelectedMethods()), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()"), selectMethod("com.example.Bar#method(java.lang.Object)")), + type.parseArgLine("-m com.acme.Foo#m() -m com.example.Bar#method(java.lang.Object)").discovery.getSelectedMethods()), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()"), selectMethod("com.example.Bar#method(java.lang.Object)")), + type.parseArgLine("-m com.acme.Foo#m() com.example.Bar#method(java.lang.Object)").discovery.getSelectedMethods()) + ); + // @formatter:on + } + + @Test + void parseInvalidMethodSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-m", "--select-method"); + } + + @ParameterizedTest + @EnumSource + void parseValidClasspathResourceSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("-r /foo.csv").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("--r /foo.csv").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("-select-resource /foo.csv").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("-select-resource=/foo.csv").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("--select-resource /foo.csv").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("--select-resource=/foo.csv").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv"), selectClasspathResource("bar.json")), type.parseArgLine("-r /foo.csv -r bar.json").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv"), selectClasspathResource("bar.json")), type.parseArgLine("-r /foo.csv bar.json").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv", FilePosition.from(5))), type.parseArgLine("-r /foo.csv?line=5").discovery.getSelectedClasspathResources()), + () -> assertEquals(List.of(selectClasspathResource("/foo.csv", FilePosition.from(12, 34))), type.parseArgLine("-r /foo.csv?line=12&column=34").discovery.getSelectedClasspathResources()) + ); + // @formatter:on + } + + @Test + void parseInvalidClasspathResourceSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-r", "--select-resource"); + } + + @ParameterizedTest + @EnumSource + void parseValidIterationSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectIteration(selectClasspathResource("/foo.csv"), 0)), type.parseArgLine("-i resource:/foo.csv[0]").discovery.getSelectedIterations()), + () -> assertEquals(List.of(selectIteration(selectMethod("com.acme.Foo#m()"), 1, 2)), type.parseArgLine("--i method:com.acme.Foo#m()[1..2]").discovery.getSelectedIterations()), + () -> assertEquals(List.of(selectIteration(selectClass("com.acme.Foo"), 0, 2)), type.parseArgLine("-select-iteration class:com.acme.Foo[0,2]").discovery.getSelectedIterations()), + () -> assertEquals(List.of(selectIteration(selectPackage("com.acme.foo"), 3)), type.parseArgLine("-select-iteration=package:com.acme.foo[3]").discovery.getSelectedIterations()), + () -> assertEquals(List.of(selectIteration(selectModule("com.acme.foo"), 0, 1, 2, 4, 5, 6)), type.parseArgLine("--select-iteration module:com.acme.foo[0..2,4..6]").discovery.getSelectedIterations()), + () -> assertEquals(List.of(selectIteration(selectDirectory("foo/bar"), 1, 5)), type.parseArgLine("--select-iteration=directory:foo/bar[1,5]").discovery.getSelectedIterations()), + () -> assertEquals(List.of(selectIteration(selectFile("foo.txt"), 6), selectIteration(selectUri("file:///foo.txt"), 7)), type.parseArgLine("-i file:foo.txt[6] -i uri:file:///foo.txt[7]").discovery.getSelectedIterations()), + () -> assertEquals(List.of(selectIteration(selectFile("foo.txt"), 6), selectIteration(selectUri("file:///foo.txt"), 7)), type.parseArgLine("-i file:foo.txt[6] uri:file:///foo.txt[7]").discovery.getSelectedIterations()) + ); + // @formatter:on + } + + @Test + void parseInvalidIterationSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("-i", "--select-iteration"); + } + + @ParameterizedTest + @EnumSource + void parseValidUniqueIdSelectors(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectUniqueId("[engine:junit-jupiter]/[class:MyClass]/[method:myMethod]")), type.parseArgLine("--uid [engine:junit-jupiter]/[class:MyClass]/[method:myMethod]").discovery.getSelectedUniqueIds()), + () -> assertEquals(List.of(selectUniqueId("[engine:junit-jupiter]/[class:MyClass]/[method:myMethod]")), type.parseArgLine("--select-unique-id [engine:junit-jupiter]/[class:MyClass]/[method:myMethod]").discovery.getSelectedUniqueIds()), + () -> assertEquals(List.of(selectUniqueId("[engine:junit-jupiter]/[class:MyClass1]"), selectUniqueId("[engine:junit-jupiter]/[class:MyClass2]")), type.parseArgLine("--uid [engine:junit-jupiter]/[class:MyClass1] --uid [engine:junit-jupiter]/[class:MyClass2]").discovery.getSelectedUniqueIds()), + () -> assertEquals(List.of(selectUniqueId("[engine:junit-jupiter]/[class:MyClass1]"), selectUniqueId("[engine:junit-jupiter]/[class:MyClass2]")), type.parseArgLine("--uid [engine:junit-jupiter]/[class:MyClass1] [engine:junit-jupiter]/[class:MyClass2]").discovery.getSelectedUniqueIds()) + ); + // @formatter:on + } + + @Test + void parseInvalidUniqueIdSelectors() { + assertOptionWithMissingRequiredArgumentThrowsException("--uid", "--select-unique-id"); + } + + @ParameterizedTest + @EnumSource + void parseClasspathScanningEntries(ArgsType type) { + var dir = Paths.get("."); + // @formatter:off + assertAll( + () -> assertTrue(type.parseArgLine("--scan-class-path").discovery.isScanClasspath()), + () -> assertEquals(List.of(), type.parseArgLine("--scan-class-path").discovery.getSelectedClasspathEntries()), + () -> assertTrue(type.parseArgLine("--scan-classpath").discovery.isScanClasspath()), + () -> assertEquals(List.of(), type.parseArgLine("--scan-classpath").discovery.getSelectedClasspathEntries()), + () -> assertTrue(type.parseArgLine("--scan-class-path .").discovery.isScanClasspath()), + () -> assertEquals(List.of(dir), type.parseArgLine("--scan-class-path .").discovery.getSelectedClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("--scan-class-path=.").discovery.getSelectedClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("-scan-class-path .").discovery.getSelectedClasspathEntries()), + () -> assertEquals(List.of(dir), type.parseArgLine("-scan-class-path=.").discovery.getSelectedClasspathEntries()), + () -> assertEquals(List.of(dir, Paths.get("src/test/java")), type.parseArgLine("--scan-class-path . --scan-class-path src/test/java").discovery.getSelectedClasspathEntries()), + () -> assertEquals(List.of(dir, Paths.get("src/test/java")), type.parseArgLine("--scan-class-path ." + File.pathSeparator + "src/test/java").discovery.getSelectedClasspathEntries()) + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidConfigurationParameters(ArgsType type) { + // @formatter:off + assertAll( + () -> assertThat(type.parseArgLine("-config foo=bar").discovery.getConfigurationParameters()) + .containsOnly(entry("foo", "bar")), + () -> assertThat(type.parseArgLine("-config=foo=bar").discovery.getConfigurationParameters()) + .containsOnly(entry("foo", "bar")), + () -> assertThat(type.parseArgLine("--config foo=bar").discovery.getConfigurationParameters()) + .containsOnly(entry("foo", "bar")), + () -> assertThat(type.parseArgLine("--config=foo=bar").discovery.getConfigurationParameters()) + .containsOnly(entry("foo", "bar")), + () -> assertThat(type.parseArgLine("--config foo=bar --config baz=qux").discovery.getConfigurationParameters()) + .containsExactly(entry("foo", "bar"), entry("baz", "qux")) + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidConfigurationParametersResource(ArgsType type) { + // @formatter:off + assertAll( + () -> assertThat(type.parseArgLine("--config-resource foo.properties").discovery.getConfigurationParametersResources()) + .containsOnly("foo.properties"), + () -> assertThat(type.parseArgLine("--config-resource foo.properties --config-resource bar.properties").discovery.getConfigurationParametersResources()) + .containsExactly("foo.properties", "bar.properties") + ); + // @formatter:on + } + + @Test + void parseInvalidConfigurationParameters() { + assertOptionWithMissingRequiredArgumentThrowsException("-config", "--config"); + } + + @ParameterizedTest + @EnumSource + void parseValidStdoutRedirectionFile(ArgsType type) { + var file = Paths.get("foo.txt"); + // @formatter:off + assertAll( + () -> assertNull(type.parseArgLine("").output.getStdoutPath()), + () -> assertEquals(file, type.parseArgLine("--redirect-stdout=foo.txt").output.getStdoutPath()), + () -> assertEquals(file, type.parseArgLine("--redirect-stdout foo.txt").output.getStdoutPath()), + () -> assertEquals(file, type.parseArgLine("--redirect-stdout bar.txt --redirect-stdout foo.txt").output.getStdoutPath()) + ); + // @formatter:on + } + + @ParameterizedTest + @EnumSource + void parseValidStderrRedirectionFile(ArgsType type) { + var file = Paths.get("foo.txt"); + // @formatter:off + assertAll( + () -> assertNull(type.parseArgLine("").output.getStderrPath()), + () -> assertEquals(file, type.parseArgLine("--redirect-stderr=foo.txt").output.getStderrPath()), + () -> assertEquals(file, type.parseArgLine("--redirect-stderr foo.txt").output.getStderrPath()), + () -> assertEquals(file, type.parseArgLine("--redirect-stderr bar.txt --redirect-stderr foo.txt").output.getStderrPath()) + ); + // @formatter:on + } + + @Test + void parseInvalidStdoutRedirectionFile() { + assertOptionWithMissingRequiredArgumentThrowsException("--redirect-stdout"); + } + + @Test + void parseInvalidStderrRedirectionFile() { + assertOptionWithMissingRequiredArgumentThrowsException("--redirect-stderr"); + } + + @Test + void parseInvalidConfigurationParametersResource() { + assertOptionWithMissingRequiredArgumentThrowsException("--config-resource"); + } + + @ParameterizedTest + @EnumSource + void parseInvalidConfigurationParametersWithDuplicateKey(ArgsType type) { + Exception e = assertThrows(Exception.class, () -> type.parseArgLine("--config foo=bar --config foo=baz")); + + assertThat(e.getMessage()).isEqualTo("Duplicate key 'foo' for values 'bar' and 'baz'."); + } + + @ParameterizedTest + @EnumSource + void parseValidSelectorIdentifier(ArgsType type) { + // @formatter:off + assertAll( + () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), parseIdentifiers(type,"--select resource:/foo.csv")), + () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), parseIdentifiers(type,"--select method:com.acme.Foo#m()")), + () -> assertEquals(List.of(selectClass("com.acme.Foo")), parseIdentifiers(type,"--select class:com.acme.Foo")), + () -> assertEquals(List.of(selectPackage("com.acme.foo")), parseIdentifiers(type,"--select package:com.acme.foo")), + () -> assertEquals(List.of(selectModule("com.acme.foo")), parseIdentifiers(type,"--select module:com.acme.foo")), + () -> assertEquals(List.of(selectDirectory("foo/bar")), parseIdentifiers(type,"--select directory:foo/bar")), + () -> assertEquals(List.of(selectFile("foo.txt"), selectUri("file:///foo.txt")), parseIdentifiers(type,"--select file:foo.txt --select uri:file:///foo.txt")), + () -> assertEquals(List.of(selectUniqueId("[engine:junit-jupiter]/[class:MyClass]/[method:myMethod]")), parseIdentifiers(type,"--select uid:[engine:junit-jupiter]/[class:MyClass]/[method:myMethod]")) + ); + // @formatter:on + } + + private static List parseIdentifiers(ArgsType type, String argLine) + throws IOException { + return DiscoverySelectors.parseAll(type.parseArgLine(argLine).discovery.getSelectorIdentifiers()).toList(); + } + + @Test + void parseInvalidSelectorIdentifier() { + assertOptionWithMissingRequiredArgumentThrowsException("--select"); + } + + private void assertOptionWithMissingRequiredArgumentThrowsException(String... options) { + assertAll( + Stream.of(options).map(opt -> () -> assertThrows(Exception.class, () -> ArgsType.args.parseArgLine(opt)))); + } + + enum ArgsType { + args { + @Override + Result parseArgLine(String argLine) { + return parse(split(argLine)); + } + }, + atFile { + @Override + Result parseArgLine(String argLine) throws IOException { + var atFile = Files.createTempFile("junit-launcher-args", ".txt"); + try { + Files.write(atFile, List.of(split(argLine))); + return parse("@" + atFile); + } + finally { + Files.deleteIfExists(atFile); + } + } + }; + + abstract Result parseArgLine(String argLine) throws IOException; + + private static String[] split(String argLine) { + return "".equals(argLine) ? new String[0] : argLine.split("\\s+"); + } + } + + private static Result parse(String... args) { + ExecuteTestsCommand command = new ExecuteTestsCommand((__, ___) -> null); + command.parseArgs(args); + return new Result(command.toTestDiscoveryOptions(), command.toTestConsoleOutputOptions()); + } + + record Result(TestDiscoveryOptions discovery, TestConsoleOutputOptions output) { + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleTestExecutorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleTestExecutorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleTestExecutorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleTestExecutorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.platform.commons.util.ClassLoaderUtils.getDefaultClassLoader; +import static org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly.createLauncher; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.junit.platform.console.options.Details; +import org.junit.platform.console.options.TestConsoleOutputOptions; +import org.junit.platform.console.options.TestDiscoveryOptions; +import org.junit.platform.engine.support.hierarchical.DemoHierarchicalTestEngine; + +/** + * @since 1.0 + */ +class ConsoleTestExecutorTests { + + private static final Runnable FAILING_BLOCK = () -> fail("should fail"); + private static final Runnable SUCCEEDING_TEST = () -> { + }; + + private final StringWriter stringWriter = new StringWriter(); + private final TestDiscoveryOptions discoveryOptions = new TestDiscoveryOptions(); + private final TestConsoleOutputOptions outputOptions = new TestConsoleOutputOptions(); + private final DemoHierarchicalTestEngine dummyTestEngine = new DemoHierarchicalTestEngine(); + + { + discoveryOptions.setScanClasspath(true); + } + + @Test + void printsSummary() { + dummyTestEngine.addTest("succeedingTest", SUCCEEDING_TEST); + dummyTestEngine.addTest("failingTest", FAILING_BLOCK); + + var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); + task.execute(new PrintWriter(stringWriter), Optional.empty()); + + assertThat(stringWriter.toString()).contains("Test run finished after", "2 tests found", "0 tests skipped", + "2 tests started", "0 tests aborted", "1 tests successful", "1 tests failed"); + } + + @Test + void printsDetailsIfTheyAreNotHidden() { + outputOptions.setDetails(Details.FLAT); + + dummyTestEngine.addTest("failingTest", FAILING_BLOCK); + + var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); + task.execute(new PrintWriter(stringWriter), Optional.empty()); + + assertThat(stringWriter.toString()).contains("Test execution started."); + } + + @Test + void printsNoDetailsIfTheyAreHidden() { + outputOptions.setDetails(Details.NONE); + + dummyTestEngine.addTest("failingTest", FAILING_BLOCK); + + var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); + task.execute(new PrintWriter(stringWriter), Optional.empty()); + + assertThat(stringWriter.toString()).doesNotContain("Test execution started."); + } + + @Test + void printsFailuresEvenIfDetailsAreHidden() { + outputOptions.setDetails(Details.NONE); + + dummyTestEngine.addTest("failingTest", FAILING_BLOCK); + dummyTestEngine.addContainer("failingContainer", FAILING_BLOCK); + + var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); + task.execute(new PrintWriter(stringWriter), Optional.empty()); + + assertThat(stringWriter.toString()).contains("Failures (2)", "failingTest", "failingContainer"); + } + + @Test + void usesCustomClassLoaderIfAdditionalClassPathEntriesArePresent() { + discoveryOptions.setAdditionalClasspathEntries(List.of(Paths.get("."))); + + var oldClassLoader = getDefaultClassLoader(); + dummyTestEngine.addTest("failingTest", + () -> assertSame(oldClassLoader, getDefaultClassLoader(), "should fail")); + + var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); + task.execute(new PrintWriter(stringWriter), Optional.empty()); + + assertThat(stringWriter.toString()).contains("failingTest", "should fail", "1 tests failed"); + } + + @Test + void usesSameClassLoaderIfNoAdditionalClassPathEntriesArePresent() { + discoveryOptions.setAdditionalClasspathEntries(List.of()); + + var oldClassLoader = getDefaultClassLoader(); + dummyTestEngine.addTest("failingTest", + () -> assertNotSame(oldClassLoader, getDefaultClassLoader(), "should fail")); + + var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); + task.execute(new PrintWriter(stringWriter), Optional.empty()); + + assertThat(stringWriter.toString()).contains("failingTest", "should fail", "1 tests failed"); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleUtilsTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ConsoleUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.charset.Charset; + +import org.junit.jupiter.api.Test; +import org.junit.platform.console.options.ConsoleUtils; + +class ConsoleUtilsTests { + + @Test + void consoleCharsetReportedByConsoleUtilsIsEitherNativeCharsetOrDefaultCharset() { + var console = System.console(); + var expected = console != null ? console.charset() : Charset.defaultCharset(); + assertEquals(expected, ConsoleUtils.charset()); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CustomContextClassLoaderExecutorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CustomContextClassLoaderExecutorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CustomContextClassLoaderExecutorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/CustomContextClassLoaderExecutorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.jupiter.api.Test; + +/** + * @since 1.0 + */ +class CustomContextClassLoaderExecutorTests { + + @Test + void invokeWithoutCustomClassLoaderDoesNotSetClassLoader() { + var originalClassLoader = Thread.currentThread().getContextClassLoader(); + var executor = new CustomContextClassLoaderExecutor(Optional.empty()); + + int result = executor.invoke(() -> { + assertSame(originalClassLoader, Thread.currentThread().getContextClassLoader()); + return 42; + }); + + assertEquals(42, result); + assertSame(originalClassLoader, Thread.currentThread().getContextClassLoader()); + } + + @Test + void invokeWithCustomClassLoaderSetsCustomAndResetsToOriginal() { + var originalClassLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader customClassLoader = URLClassLoader.newInstance(new URL[0]); + var executor = new CustomContextClassLoaderExecutor(Optional.of(customClassLoader)); + + int result = executor.invoke(() -> { + assertSame(customClassLoader, Thread.currentThread().getContextClassLoader()); + return 23; + }); + + assertEquals(23, result); + assertSame(originalClassLoader, Thread.currentThread().getContextClassLoader()); + } + + @Test + void invokeWithCustomClassLoaderAndEnsureItIsClosedAfterUsage() { + var closed = new AtomicBoolean(false); + ClassLoader localClassLoader = new URLClassLoader(new URL[0]) { + @Override + public void close() throws IOException { + closed.set(true); + super.close(); + } + }; + var executor = new CustomContextClassLoaderExecutor(Optional.of(localClassLoader)); + + int result = executor.invoke(() -> 4711); + + assertEquals(4711, result); + assertTrue(closed.get()); + } + + @Test + void invokeWithCustomClassLoaderAndKeepItOpenAfterUsage() { + var closed = new AtomicBoolean(false); + ClassLoader localClassLoader = new URLClassLoader(new URL[0]) { + @Override + public void close() throws IOException { + closed.set(true); + super.close(); + } + }; + var executor = new CustomContextClassLoaderExecutor(Optional.of(localClassLoader), + CustomClassLoaderCloseStrategy.KEEP_OPEN); + + int result = executor.invoke(() -> 4711); + + assertEquals(4711, result); + assertFalse(closed.get()); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/DiscoveryRequestCreatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/DiscoveryRequestCreatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/DiscoveryRequestCreatorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/DiscoveryRequestCreatorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,430 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static java.util.stream.Collectors.toMap; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.platform.engine.discovery.ClassNameFilter.STANDARD_INCLUDE_PATTERN; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResource; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectDirectory; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectFile; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectIteration; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUri; + +import java.io.File; +import java.net.URI; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.LogRecord; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.fixtures.TrackLogRecords; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.console.options.TestDiscoveryOptions; +import org.junit.platform.engine.Filter; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.discovery.ClassNameFilter; +import org.junit.platform.engine.discovery.ClassSelector; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; +import org.junit.platform.engine.discovery.ClasspathRootSelector; +import org.junit.platform.engine.discovery.DirectorySelector; +import org.junit.platform.engine.discovery.FileSelector; +import org.junit.platform.engine.discovery.IterationSelector; +import org.junit.platform.engine.discovery.MethodSelector; +import org.junit.platform.engine.discovery.PackageNameFilter; +import org.junit.platform.engine.discovery.PackageSelector; +import org.junit.platform.engine.discovery.UniqueIdSelector; +import org.junit.platform.engine.discovery.UriSelector; +import org.junit.platform.launcher.LauncherDiscoveryRequest; + +/** + * @since 1.0 + */ +class DiscoveryRequestCreatorTests { + + private final TestDiscoveryOptions options = new TestDiscoveryOptions(); + + @Test + void convertsScanClasspathOptionWithoutExplicitRootDirectories() { + options.setScanClasspath(true); + + var request = convert(); + + var classpathRootSelectors = request.getSelectorsByType(ClasspathRootSelector.class); + // @formatter:off + assertThat(classpathRootSelectors).extracting(ClasspathRootSelector::getClasspathRoot) + .hasAtLeastOneElementOfType(URI.class) + .doesNotContainNull(); + // @formatter:on + } + + @Test + void convertsScanClasspathOptionWithExplicitRootDirectories() { + options.setScanClasspath(true); + options.setSelectedClasspathEntries(List.of(Paths.get("."), Paths.get(".."))); + + var request = convert(); + + var classpathRootSelectors = request.getSelectorsByType(ClasspathRootSelector.class); + // @formatter:off + assertThat(classpathRootSelectors).extracting(ClasspathRootSelector::getClasspathRoot) + .containsExactly(new File(".").toURI(), new File("..").toURI()); + // @formatter:on + } + + @Test + void convertsScanClasspathOptionWithAdditionalClasspathEntries() { + options.setScanClasspath(true); + options.setAdditionalClasspathEntries(List.of(Paths.get("."), Paths.get(".."))); + + var request = convert(); + + var classpathRootSelectors = request.getSelectorsByType(ClasspathRootSelector.class); + // @formatter:off + assertThat(classpathRootSelectors).extracting(ClasspathRootSelector::getClasspathRoot) + .contains(new File(".").toURI(), new File("..").toURI()); + // @formatter:on + } + + @Test + void doesNotSupportScanClasspathAndExplicitSelectors() { + options.setScanClasspath(true); + options.setSelectedClasses(List.of(selectClass("SomeTest"))); + + Throwable cause = assertThrows(PreconditionViolationException.class, this::convert); + + assertThat(cause).hasMessageContaining("not supported"); + } + + @Test + void convertsDefaultIncludeClassNamePatternOption() { + options.setScanClasspath(true); + + var request = convert(); + + var filters = request.getFiltersByType(ClassNameFilter.class); + assertThat(filters).hasSize(1); + assertExcludes(filters.getFirst(), STANDARD_INCLUDE_PATTERN); + } + + @Test + void convertsExplicitIncludeClassNamePatternOption() { + options.setScanClasspath(true); + options.setIncludedClassNamePatterns(List.of("Foo.*Bar", "Bar.*Foo")); + + var request = convert(); + + var filters = request.getFiltersByType(ClassNameFilter.class); + assertThat(filters).hasSize(1); + assertIncludes(filters.getFirst(), "Foo.*Bar"); + assertIncludes(filters.getFirst(), "Bar.*Foo"); + } + + @Test + void includeSelectedClassesAndMethodsRegardlessOfClassNamePatterns() { + options.setSelectedClasses(List.of(selectClass("SomeTest"))); + options.setSelectedMethods(List.of(selectMethod("com.acme.Foo#m()"))); + options.setSelectedIterations(List.of(selectIteration(selectMethod("com.acme.Bar#n()"), 0))); + options.setIncludedClassNamePatterns(List.of("Foo.*Bar")); + + var request = convert(); + + var filters = request.getFiltersByType(ClassNameFilter.class); + assertThat(filters).hasSize(1); + assertIncludes(filters.getFirst(), "SomeTest"); + assertIncludes(filters.getFirst(), "com.acme.Foo"); + assertIncludes(filters.getFirst(), "com.acme.Bar"); + assertIncludes(filters.getFirst(), "Foo.*Bar"); + } + + @Test + void convertsExcludeClassNamePatternOption() { + options.setScanClasspath(true); + options.setExcludedClassNamePatterns(List.of("Foo.*Bar", "Bar.*Foo")); + + var request = convert(); + + var filters = request.getFiltersByType(ClassNameFilter.class); + assertThat(filters).hasSize(2); + assertExcludes(filters.get(1), "Foo.*Bar"); + assertExcludes(filters.get(1), "Bar.*Foo"); + } + + @Test + void convertsPackageOptions() { + options.setScanClasspath(true); + options.setIncludedPackages(List.of("org.junit.included1", "org.junit.included2", "org.junit.included3")); + options.setExcludedPackages(List.of("org.junit.excluded1")); + + var request = convert(); + var packageNameFilters = request.getFiltersByType(PackageNameFilter.class); + + assertThat(packageNameFilters).hasSize(2); + assertIncludes(packageNameFilters.getFirst(), "org.junit.included1"); + assertIncludes(packageNameFilters.get(0), "org.junit.included2"); + assertIncludes(packageNameFilters.get(0), "org.junit.included3"); + assertExcludes(packageNameFilters.get(1), "org.junit.excluded1"); + } + + @Test + void convertsMethodNamePatternOptions() { + options.setScanClasspath(true); + options.setIncludedMethodNamePatterns(List.of(".+#foo.*Bar", ".+#toString", ".+#method.*")); + options.setExcludedMethodNamePatterns(List.of(".+#bar.*Foo")); + var request = convert(); + var methodNameFilters = request.getPostDiscoveryFilters(); + assertThat(methodNameFilters).hasSize(2); + assertThat(methodNameFilters.get(0).toString()).contains(".+#foo.*Bar", ".+#toString", ".+#method.*"); + assertThat(methodNameFilters.get(1).toString()).contains(".+#bar.*Foo"); + } + + @Test + void convertsTagOptions() { + options.setScanClasspath(true); + options.setIncludedTagExpressions(List.of("fast", "medium", "slow")); + options.setExcludedTagExpressions(List.of("slow")); + + var request = convert(); + var postDiscoveryFilters = request.getPostDiscoveryFilters(); + + assertThat(postDiscoveryFilters).hasSize(2); + assertThat(postDiscoveryFilters.get(0).toString()).contains("TagFilter"); + assertThat(postDiscoveryFilters.get(1).toString()).contains("TagFilter"); + } + + @Test + void convertsEngineOptions() { + options.setScanClasspath(true); + options.setIncludedEngines(List.of("engine1", "engine2", "engine3")); + options.setExcludedEngines(List.of("engine2")); + + var request = convert(); + var engineFilters = request.getEngineFilters(); + + assertThat(engineFilters).hasSize(2); + assertThat(engineFilters.get(0).toString()).contains("includes", "[engine1, engine2, engine3]"); + assertThat(engineFilters.get(1).toString()).contains("excludes", "[engine2]"); + } + + @Test + void propagatesUniqueIdSelectors() { + options.setSelectedUniqueId(List.of(selectUniqueId("[engine:a]/[1:1]"), selectUniqueId("[engine:b]/[2:2]"))); + + var request = convert(); + var uriSelectors = request.getSelectorsByType(UniqueIdSelector.class); + + assertThat(uriSelectors) // + .extracting(UniqueIdSelector::getUniqueId) // + .containsExactly( // + UniqueId.parse("[engine:a]/[1:1]"), //, // + UniqueId.parse("[engine:b]/[2:2]") // + ); + } + + @Test + void propagatesUriSelectors() { + options.setSelectedUris(List.of(selectUri("a"), selectUri("b"))); + + var request = convert(); + var uriSelectors = request.getSelectorsByType(UriSelector.class); + + assertThat(uriSelectors).extracting(UriSelector::getUri).containsExactly(URI.create("a"), URI.create("b")); + } + + @Test + void propagatesFileSelectors() { + options.setSelectedFiles(List.of(selectFile("foo.txt"), selectFile("bar.csv"))); + + var request = convert(); + var fileSelectors = request.getSelectorsByType(FileSelector.class); + + assertThat(fileSelectors).extracting(FileSelector::getRawPath).containsExactly("foo.txt", "bar.csv"); + } + + @Test + void propagatesDirectorySelectors() { + options.setSelectedDirectories(List.of(selectDirectory("foo/bar"), selectDirectory("bar/qux"))); + + var request = convert(); + var directorySelectors = request.getSelectorsByType(DirectorySelector.class); + + assertThat(directorySelectors).extracting(DirectorySelector::getRawPath).containsExactly("foo/bar", "bar/qux"); + } + + @Test + void propagatesPackageSelectors() { + options.setSelectedPackages(List.of(selectPackage("com.acme.foo"), selectPackage("com.example.bar"))); + + var request = convert(); + var packageSelectors = request.getSelectorsByType(PackageSelector.class); + + assertThat(packageSelectors).extracting(PackageSelector::getPackageName).containsExactly("com.acme.foo", + "com.example.bar"); + } + + @Test + void propagatesClassSelectors() { + options.setSelectedClasses(List.of(selectClass("com.acme.Foo"), selectClass("com.example.Bar"))); + + var request = convert(); + var classSelectors = request.getSelectorsByType(ClassSelector.class); + + assertThat(classSelectors).extracting(ClassSelector::getClassName).containsExactly("com.acme.Foo", + "com.example.Bar"); + } + + @Test + void propagatesMethodSelectors() { + options.setSelectedMethods( + List.of(selectMethod("com.acme.Foo#m()"), selectMethod("com.example.Bar#method(java.lang.Object)"))); + + var request = convert(); + var methodSelectors = request.getSelectorsByType(MethodSelector.class); + + assertThat(methodSelectors).hasSize(2); + assertThat(methodSelectors.getFirst().getClassName()).isEqualTo("com.acme.Foo"); + assertThat(methodSelectors.get(0).getMethodName()).isEqualTo("m"); + assertThat(methodSelectors.get(0).getParameterTypeNames()).isEmpty(); + assertThat(methodSelectors.get(1).getClassName()).isEqualTo("com.example.Bar"); + assertThat(methodSelectors.get(1).getMethodName()).isEqualTo("method"); + assertThat(methodSelectors.get(1).getParameterTypeNames()).isEqualTo("java.lang.Object"); + } + + @Test + void propagatesClasspathResourceSelectors() { + options.setSelectedClasspathResources( + List.of(selectClasspathResource("foo.csv"), selectClasspathResource("com/example/bar.json"))); + + var request = convert(); + var classpathResourceSelectors = request.getSelectorsByType(ClasspathResourceSelector.class); + + assertThat(classpathResourceSelectors).extracting( + ClasspathResourceSelector::getClasspathResourceName).containsExactly("foo.csv", "com/example/bar.json"); + } + + @Test + void propagatesIterationSelectors() { + var methodSelector = selectMethod("com.acme.Foo#m()"); + var classSelector = selectClass("com.example.Bar"); + options.setSelectedIterations(List.of(selectIteration(methodSelector, 1), selectIteration(classSelector, 2))); + + var request = convert(); + var iterationSelectors = request.getSelectorsByType(IterationSelector.class); + + assertThat(iterationSelectors).hasSize(2); + assertThat(iterationSelectors.get(0).getParentSelector()).isEqualTo(methodSelector); + assertThat(iterationSelectors.get(0).getIterationIndices()).containsExactly(1); + assertThat(iterationSelectors.get(1).getParentSelector()).isEqualTo(classSelector); + assertThat(iterationSelectors.get(1).getIterationIndices()).containsExactly(2); + } + + @Test + void propagatesSelectorIdentifiers() { + var methodSelector = selectMethod("com.acme.Foo#m()"); + var classSelector = selectClass("com.example.Bar"); + options.setSelectorIdentifiers( + List.of(methodSelector.toIdentifier().orElseThrow(), classSelector.toIdentifier().orElseThrow())); + + var request = convert(); + + assertThat(request.getSelectorsByType(MethodSelector.class)).containsExactly(methodSelector); + assertThat(request.getSelectorsByType(ClassSelector.class)).containsExactly(classSelector); + } + + @Test + @SuppressWarnings("deprecation") + void convertsConfigurationParameters() { + options.setScanClasspath(true); + options.setConfigurationParameters(mapOf(entry("foo", "bar"), entry("baz", "true"))); + + var request = convert(); + var configurationParameters = request.getConfigurationParameters(); + + assertThat(configurationParameters.size()).isEqualTo(2); + assertThat(configurationParameters.get("foo")).contains("bar"); + assertThat(configurationParameters.getBoolean("baz")).contains(true); + } + + @Test + @SuppressWarnings("deprecation") + void convertsConfigurationParametersResources() { + options.setScanClasspath(true); + options.setConfigurationParameters(mapOf(entry("foo", "bar"), entry("com.example.prop.first", "baz"))); + options.setConfigurationParametersResources(List.of("config-test.properties")); + + var request = convert(); + var configurationParameters = request.getConfigurationParameters(); + + assertThat(configurationParameters.size()).isEqualTo(2); + assertThat(configurationParameters.get("foo")).contains("bar"); + assertThat(configurationParameters.get("com.example.prop.first")).contains("baz"); + assertThat(configurationParameters.get("com.example.prop.second")).contains("second value"); + } + + @Test + void logsInvalidSearchPathRoots(@TrackLogRecords LogRecordListener listener) { + var opts = new TestDiscoveryOptions(); + opts.setScanClasspath(true); + var missingPath = Paths.get("/does/not/exist"); + opts.setSelectedClasspathEntries(List.of(missingPath)); + + DiscoveryRequestCreator.toDiscoveryRequestBuilder(opts); + + assertThat(listener.stream(DiscoveryRequestCreator.class)) // + .map(LogRecord::getMessage) // + .filteredOn(message -> message.contains(missingPath.toString())) // + .hasSize(1); + } + + @Test + void logsInvalidAdditionalClasspathRoots(@TrackLogRecords LogRecordListener listener) { + var opts = new TestDiscoveryOptions(); + opts.setScanClasspath(true); + var missingPath = Paths.get("/also/does/not/exist"); + opts.setAdditionalClasspathEntries(List.of(missingPath)); + + DiscoveryRequestCreator.toDiscoveryRequestBuilder(opts); + + assertThat(listener.stream(DiscoveryRequestCreator.class)) // + .map(LogRecord::getMessage) // + .filteredOn(message -> message.contains(missingPath.toString())) // + .hasSize(1); + } + + private LauncherDiscoveryRequest convert() { + return DiscoveryRequestCreator.toDiscoveryRequestBuilder(options).build(); + } + + private void assertIncludes(Filter filter, String included) { + assertThat(filter.apply(included).included()).isTrue(); + } + + private void assertExcludes(Filter filter, String excluded) { + assertThat(filter.apply(excluded).excluded()).isTrue(); + } + + @SafeVarargs + @SuppressWarnings("varargs") + private static Map mapOf(Entry... entries) { + return Stream.of(entries).collect(toMap(Entry::getKey, Entry::getValue)); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ExecuteTestsCommandTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ExecuteTestsCommandTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ExecuteTestsCommandTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ExecuteTestsCommandTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.nio.file.Paths; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.platform.launcher.listeners.TestExecutionSummary; + +/** + * @since 1.10 + */ +class ExecuteTestsCommandTests { + + private final TestExecutionSummary summary = mock(); + private final ConsoleTestExecutor consoleTestExecutor = mock(); + private final ExecuteTestsCommand command = new ExecuteTestsCommand((__, ___) -> consoleTestExecutor); + + @BeforeEach + void setUp() { + when(consoleTestExecutor.execute(any(), any())).thenReturn(summary); + } + + @Test + void hasStatusCode0ForNoTotalFailures() { + when(summary.getTotalFailureCount()).thenReturn(0L); + + command.execute(); + + assertThat(command.getExitCode()).isEqualTo(0); + } + + @Test + void hasStatusCode1ForForAnyFailure() { + when(summary.getTotalFailureCount()).thenReturn(1L); + + command.execute(); + + assertThat(command.getExitCode()).isEqualTo(1); + } + + /** + * @since 1.3 + */ + @Test + void hasStatusCode2ForNoTestsAndHasOptionFailIfNoTestsFound() { + when(summary.getTestsFoundCount()).thenReturn(0L); + + command.execute("--fail-if-no-tests"); + + assertThat(command.getExitCode()).isEqualTo(2); + } + + /** + * @since 1.3 + */ + @Test + void hasStatusCode0ForTestsAndHasOptionFailIfNoTestsFound() { + when(summary.getTestsFoundCount()).thenReturn(1L); + when(summary.getTotalFailureCount()).thenReturn(0L); + + command.execute("--fail-if-no-tests"); + + assertThat(command.getExitCode()).isEqualTo(0); + } + + /** + * @since 1.3 + */ + @Test + void hasStatusCode0ForNoTestsAndNotFailIfNoTestsFound() { + when(summary.getTestsFoundCount()).thenReturn(0L); + + command.execute(); + + assertThat(command.getExitCode()).isEqualTo(0); + } + + @Test + void parseValidXmlReportsDirs() { + var dir = Paths.get("build", "test-results"); + // @formatter:off + assertAll( + () -> assertEquals(Optional.empty(), parseArgs().getReportsDir()), + () -> assertEquals(Optional.of(dir), parseArgs("--reports-dir", "build/test-results").getReportsDir()), + () -> assertEquals(Optional.of(dir), parseArgs("--reports-dir=build/test-results").getReportsDir()) + ); + // @formatter:on + } + + private ExecuteTestsCommand parseArgs(String... args) { + command.parseArgs(args); + return command; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/StdStreamTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/StdStreamTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/StdStreamTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/StdStreamTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import org.junit.jupiter.api.Test; + +public class StdStreamTestCase { + + private static final String STDOUT_DATA = "Writing to STDOUT..."; + private static final String STDERR_DATA = "Writing to STDERR..."; + + public static int getStdoutOutputFileSize() { + return STDOUT_DATA.length(); + } + + public static int getStderrOutputFileSize() { + return STDERR_DATA.length(); + } + + @Test + void printTest() { + System.out.print(STDOUT_DATA); + System.err.print(STDERR_DATA); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ThemeTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ThemeTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ThemeTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/command/ThemeTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.command; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.Test; +import org.junit.platform.console.output.Theme; + +class ThemeTests { + + @Test + void givenUtf8ShouldReturnUnicode() { + assertEquals(Theme.UNICODE, Theme.valueOf(StandardCharsets.UTF_8)); + } + + @Test + void givenAnythingElseShouldReturnAscii() { + assertAll("All character sets that are not UTF-8 should return Theme.ASCII", () -> { + assertEquals(Theme.ASCII, Theme.valueOf(StandardCharsets.ISO_8859_1)); + assertEquals(Theme.ASCII, Theme.valueOf(StandardCharsets.US_ASCII)); + assertEquals(Theme.ASCII, Theme.valueOf(StandardCharsets.UTF_16)); + }); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/CommandLineOptionsParsingTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/CommandLineOptionsParsingTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/CommandLineOptionsParsingTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/CommandLineOptionsParsingTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,640 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.platform.engine.discovery.ClassNameFilter.STANDARD_INCLUDE_PATTERN; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResource; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectDirectory; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectFile; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectIteration; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectModule; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUri; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledOnOs; -import org.junit.jupiter.api.condition.OS; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.platform.engine.DiscoverySelector; -import org.junit.platform.engine.discovery.DiscoverySelectors; - -/** - * @since 1.10 - */ -class CommandLineOptionsParsingTests { - - @Test - void parseNoArguments() { - String[] noArguments = {}; - var options = parse(noArguments); - - // @formatter:off - assertAll( - () -> assertFalse(options.output.isAnsiColorOutputDisabled()), - () -> assertEquals(TestConsoleOutputOptions.DEFAULT_DETAILS, options.output.getDetails()), - () -> assertFalse(options.discovery.isScanClasspath()), - () -> assertEquals(List.of(STANDARD_INCLUDE_PATTERN), options.discovery.getIncludedClassNamePatterns()), - () -> assertEquals(List.of(), options.discovery.getExcludedClassNamePatterns()), - () -> assertEquals(List.of(), options.discovery.getIncludedPackages()), - () -> assertEquals(List.of(), options.discovery.getExcludedPackages()), - () -> assertEquals(List.of(), options.discovery.getIncludedTagExpressions()), - () -> assertEquals(List.of(), options.discovery.getExcludedTagExpressions()), - () -> assertEquals(List.of(), options.discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(), options.discovery.getSelectedUris()), - () -> assertEquals(List.of(), options.discovery.getSelectedFiles()), - () -> assertEquals(List.of(), options.discovery.getSelectedDirectories()), - () -> assertEquals(List.of(), options.discovery.getSelectedModules()), - () -> assertEquals(List.of(), options.discovery.getSelectedPackages()), - () -> assertEquals(List.of(), options.discovery.getSelectedMethods()), - () -> assertEquals(List.of(), options.discovery.getSelectedClasspathEntries()), - () -> assertEquals(Map.of(), options.discovery.getConfigurationParameters()) - ); - // @formatter:on - } - - @Test - void parseSwitches() { - // @formatter:off - assertAll( - () -> assertTrue(parse("--disable-ansi-colors").output.isAnsiColorOutputDisabled(), "disable ansi"), - () -> assertTrue(parse("--scan-class-path").discovery.isScanClasspath(), "scan class path") - ); - // @formatter:on - } - - @ParameterizedTest - @EnumSource - void parseValidDetails(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(Details.VERBOSE, type.parseArgLine("--details verbose").output.getDetails()), - () -> assertEquals(Details.TREE, type.parseArgLine("--details tree").output.getDetails()), - () -> assertEquals(Details.FLAT, type.parseArgLine("--details flat").output.getDetails()), - () -> assertEquals(Details.NONE, type.parseArgLine("--details NONE").output.getDetails()), - () -> assertEquals(Details.NONE, type.parseArgLine("--details none").output.getDetails()), - () -> assertEquals(Details.NONE, type.parseArgLine("--details None").output.getDetails()) - ); - // @formatter:on - } - - @Test - void parseInvalidDetails() { - assertOptionWithMissingRequiredArgumentThrowsException("--details"); - } - - @ParameterizedTest - @EnumSource - void parseValidDetailsTheme(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(Theme.ASCII, type.parseArgLine("--details-theme ascii").output.getTheme()), - () -> assertEquals(Theme.ASCII, type.parseArgLine("--details-theme ASCII").output.getTheme()), - () -> assertEquals(Theme.UNICODE, type.parseArgLine("--details-theme unicode").output.getTheme()), - () -> assertEquals(Theme.UNICODE, type.parseArgLine("--details-theme UNICODE").output.getTheme()), - () -> assertEquals(Theme.UNICODE, type.parseArgLine("--details-theme uniCode").output.getTheme()) - ); - // @formatter:on - } - - @Test - void parseInvalidDetailsTheme() { - assertOptionWithMissingRequiredArgumentThrowsException("--details-theme"); - } - - @ParameterizedTest - @EnumSource - void parseValidIncludeClassNamePatterns(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(".*Test"), type.parseArgLine("-n .*Test").discovery.getIncludedClassNamePatterns()), - () -> assertEquals(List.of(".*Test", ".*Tests"), type.parseArgLine("--include-classname .*Test --include-classname .*Tests").discovery.getIncludedClassNamePatterns()), - () -> assertEquals(List.of(".*Test"), type.parseArgLine("--include-classname=.*Test").discovery.getIncludedClassNamePatterns()) - ); - // @formatter:on - } - - @ParameterizedTest - @EnumSource - void parseValidExcludeClassNamePatterns(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(".*Test"), type.parseArgLine("-N .*Test").discovery.getExcludedClassNamePatterns()), - () -> assertEquals(List.of(".*Test", ".*Tests"), type.parseArgLine("--exclude-classname .*Test --exclude-classname .*Tests").discovery.getExcludedClassNamePatterns()), - () -> assertEquals(List.of(".*Test"), type.parseArgLine("--exclude-classname=.*Test").discovery.getExcludedClassNamePatterns()) - ); - // @formatter:on - } - - @Test - void usesDefaultClassNamePatternWithoutExplicitArgument() throws Exception { - assertEquals(List.of(STANDARD_INCLUDE_PATTERN), - ArgsType.args.parseArgLine("").discovery.getIncludedClassNamePatterns()); - } - - @Test - void parseInvalidIncludeClassNamePatterns() { - assertOptionWithMissingRequiredArgumentThrowsException("-n", "--include-classname"); - } - - @Test - void parseInvalidExcludeClassNamePatterns() { - assertOptionWithMissingRequiredArgumentThrowsException("-N", "--exclude-classname"); - } - - @ParameterizedTest - @EnumSource - void parseValidIncludedPackages(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of("org.junit.included"), - type.parseArgLine("--include-package org.junit.included").discovery.getIncludedPackages()), - () -> assertEquals(List.of("org.junit.included"), - type.parseArgLine("--include-package=org.junit.included").discovery.getIncludedPackages()), - () -> assertEquals(List.of("org.junit.included1", "org.junit.included2"), - type.parseArgLine("--include-package org.junit.included1 --include-package org.junit.included2").discovery.getIncludedPackages()) - ); - // @formatter:on - } - - @ParameterizedTest - @EnumSource - void parseValidExcludedPackages(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of("org.junit.excluded"), - type.parseArgLine("--exclude-package org.junit.excluded").discovery.getExcludedPackages()), - () -> assertEquals(List.of("org.junit.excluded"), - type.parseArgLine("--exclude-package=org.junit.excluded").discovery.getExcludedPackages()), - () -> assertEquals(List.of("org.junit.excluded1", "org.junit.excluded2"), - type.parseArgLine("--exclude-package org.junit.excluded1 --exclude-package org.junit.excluded2").discovery.getExcludedPackages()) - ); - // @formatter:on - } - - @ParameterizedTest - @EnumSource - void parseValidIncludedTags(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of("fast"), type.parseArgLine("-t fast").discovery.getIncludedTagExpressions()), - () -> assertEquals(List.of("fast"), type.parseArgLine("--include-tag fast").discovery.getIncludedTagExpressions()), - () -> assertEquals(List.of("fast"), type.parseArgLine("--include-tag=fast").discovery.getIncludedTagExpressions()), - () -> assertEquals(List.of("fast", "slow"), type.parseArgLine("-t fast -t slow").discovery.getIncludedTagExpressions()) - ); - // @formatter:on - } - - @Test - void parseInvalidIncludedTags() { - assertOptionWithMissingRequiredArgumentThrowsException("-t", "--include-tag"); - } - - @ParameterizedTest - @EnumSource - void parseValidExcludedTags(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of("fast"), type.parseArgLine("-T fast").discovery.getExcludedTagExpressions()), - () -> assertEquals(List.of("fast"), type.parseArgLine("--exclude-tag fast").discovery.getExcludedTagExpressions()), - () -> assertEquals(List.of("fast"), type.parseArgLine("--exclude-tag=fast").discovery.getExcludedTagExpressions()), - () -> assertEquals(List.of("fast", "slow"), type.parseArgLine("-T fast -T slow").discovery.getExcludedTagExpressions()) - ); - // @formatter:on - } - - @Test - void parseInvalidExcludedTags() { - assertOptionWithMissingRequiredArgumentThrowsException("-T", "--exclude-tag"); - } - - @ParameterizedTest - @EnumSource - void parseValidIncludedEngines(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of("junit-jupiter"), type.parseArgLine("-e junit-jupiter").discovery.getIncludedEngines()), - () -> assertEquals(List.of("junit-vintage"), type.parseArgLine("--include-engine junit-vintage").discovery.getIncludedEngines()), - () -> assertEquals(List.of(), type.parseArgLine("").discovery.getIncludedEngines()) - ); - // @formatter:on - } - - @Test - void parseInvalidIncludedEngines() { - assertOptionWithMissingRequiredArgumentThrowsException("-e", "--include-engine"); - } - - @ParameterizedTest - @EnumSource - void parseValidExcludedEngines(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of("junit-jupiter"), type.parseArgLine("-E junit-jupiter").discovery.getExcludedEngines()), - () -> assertEquals(List.of("junit-vintage"), type.parseArgLine("--exclude-engine junit-vintage").discovery.getExcludedEngines()), - () -> assertEquals(List.of(), type.parseArgLine("").discovery.getExcludedEngines()) - ); - // @formatter:on - } - - @Test - void parseInvalidExcludedEngines() { - assertOptionWithMissingRequiredArgumentThrowsException("-E", "--exclude-engine"); - } - - @ParameterizedTest - @EnumSource - void parseValidAdditionalClasspathEntries(ArgsType type) { - var dir = Paths.get("."); - // @formatter:off - assertAll( - () -> assertEquals(List.of(dir), type.parseArgLine("-cp .").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("--cp .").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("-classpath .").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("-classpath=.").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("--classpath .").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("--classpath=.").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("--class-path .").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("--class-path=.").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir, Path.of("lib/some.jar")), type.parseArgLine("-cp . -cp lib/some.jar").discovery.getAdditionalClasspathEntries()), - () -> assertEquals(List.of(dir, Path.of("lib/some.jar")), type.parseArgLine("-cp ." + File.pathSeparator + "lib/some.jar").discovery.getAdditionalClasspathEntries()) - ); - // @formatter:on - } - - @Test - @EnabledOnOs(OS.WINDOWS) - void parseValidAndAbsoluteAdditionalClasspathEntries() throws Exception { - ArgsType type = ArgsType.args; - assertEquals(List.of(Path.of("C:\\a.jar")), - type.parseArgLine("-cp C:\\a.jar").discovery.getAdditionalClasspathEntries()); - assertEquals(List.of(Path.of("C:\\foo.jar"), Path.of("D:\\bar.jar")), - type.parseArgLine("-cp C:\\foo.jar;D:\\bar.jar").discovery.getAdditionalClasspathEntries()); - } - - @Test - void parseInvalidAdditionalClasspathEntries() { - assertOptionWithMissingRequiredArgumentThrowsException("-cp", "--classpath", "--class-path"); - } - - @Test - void parseInvalidXmlReportsDirs() { - assertOptionWithMissingRequiredArgumentThrowsException("--reports-dir"); - } - - @ParameterizedTest - @EnumSource - void parseValidUriSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("-u file:///foo.txt").discovery.getSelectedUris()), - () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("--u file:///foo.txt").discovery.getSelectedUris()), - () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("-select-uri file:///foo.txt").discovery.getSelectedUris()), - () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("-select-uri=file:///foo.txt").discovery.getSelectedUris()), - () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("--select-uri file:///foo.txt").discovery.getSelectedUris()), - () -> assertEquals(List.of(selectUri("file:///foo.txt")), type.parseArgLine("--select-uri=file:///foo.txt").discovery.getSelectedUris()), - () -> assertEquals(List.of(selectUri("file:///foo.txt"), selectUri("https://example")), type.parseArgLine("-u file:///foo.txt -u https://example").discovery.getSelectedUris()) - ); - // @formatter:on - } - - @Test - void parseInvalidUriSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-u", "--select-uri", "-u unknown-scheme:"); - } - - @ParameterizedTest - @EnumSource - void parseValidFileSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("-f foo.txt").discovery.getSelectedFiles()), - () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("--f foo.txt").discovery.getSelectedFiles()), - () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("-select-file foo.txt").discovery.getSelectedFiles()), - () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("-select-file=foo.txt").discovery.getSelectedFiles()), - () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("--select-file foo.txt").discovery.getSelectedFiles()), - () -> assertEquals(List.of(selectFile("foo.txt")), type.parseArgLine("--select-file=foo.txt").discovery.getSelectedFiles()), - () -> assertEquals(List.of(selectFile("foo.txt"), selectFile("bar.csv")), type.parseArgLine("-f foo.txt -f bar.csv").discovery.getSelectedFiles()) - ); - // @formatter:on - } - - @Test - void parseInvalidFileSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-f", "--select-file"); - } - - @ParameterizedTest - @EnumSource - void parseValidDirectorySelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("-d foo/bar").discovery.getSelectedDirectories()), - () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("--d foo/bar").discovery.getSelectedDirectories()), - () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("-select-directory foo/bar").discovery.getSelectedDirectories()), - () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("-select-directory=foo/bar").discovery.getSelectedDirectories()), - () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("--select-directory foo/bar").discovery.getSelectedDirectories()), - () -> assertEquals(List.of(selectDirectory("foo/bar")), type.parseArgLine("--select-directory=foo/bar").discovery.getSelectedDirectories()), - () -> assertEquals(List.of(selectDirectory("foo/bar"), selectDirectory("bar/qux")), type.parseArgLine("-d foo/bar -d bar/qux").discovery.getSelectedDirectories()) - ); - // @formatter:on - } - - @Test - void parseInvalidDirectorySelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-d", "--select-directory"); - } - - @ParameterizedTest - @EnumSource - void parseValidModuleSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("-o com.acme.foo").discovery.getSelectedModules()), - () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("--o com.acme.foo").discovery.getSelectedModules()), - () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("-select-module com.acme.foo").discovery.getSelectedModules()), - () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("-select-module=com.acme.foo").discovery.getSelectedModules()), - () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("--select-module com.acme.foo").discovery.getSelectedModules()), - () -> assertEquals(List.of(selectModule("com.acme.foo")), type.parseArgLine("--select-module=com.acme.foo").discovery.getSelectedModules()), - () -> assertEquals(List.of(selectModule("com.acme.foo"), selectModule("com.example.bar")), type.parseArgLine("-o com.acme.foo -o com.example.bar").discovery.getSelectedModules()) - ); - // @formatter:on - } - - @Test - void parseInvalidModuleSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-o", "--select-module"); - } - - @ParameterizedTest - @EnumSource - void parseValidPackageSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("-p com.acme.foo").discovery.getSelectedPackages()), - () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("--p com.acme.foo").discovery.getSelectedPackages()), - () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("-select-package com.acme.foo").discovery.getSelectedPackages()), - () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("-select-package=com.acme.foo").discovery.getSelectedPackages()), - () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("--select-package com.acme.foo").discovery.getSelectedPackages()), - () -> assertEquals(List.of(selectPackage("com.acme.foo")), type.parseArgLine("--select-package=com.acme.foo").discovery.getSelectedPackages()), - () -> assertEquals(List.of(selectPackage("com.acme.foo"), selectPackage("com.example.bar")), type.parseArgLine("-p com.acme.foo -p com.example.bar").discovery.getSelectedPackages()) - ); - // @formatter:on - } - - @Test - void parseInvalidPackageSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-p", "--select-package"); - } - - @ParameterizedTest - @EnumSource - void parseValidClassSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("-c com.acme.Foo").discovery.getSelectedClasses()), - () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("--c com.acme.Foo").discovery.getSelectedClasses()), - () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("-select-class com.acme.Foo").discovery.getSelectedClasses()), - () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("-select-class=com.acme.Foo").discovery.getSelectedClasses()), - () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("--select-class com.acme.Foo").discovery.getSelectedClasses()), - () -> assertEquals(List.of(selectClass("com.acme.Foo")), type.parseArgLine("--select-class=com.acme.Foo").discovery.getSelectedClasses()), - () -> assertEquals(List.of(selectClass("com.acme.Foo"), selectClass("com.example.Bar")), type.parseArgLine("-c com.acme.Foo -c com.example.Bar").discovery.getSelectedClasses()) - ); - // @formatter:on - } - - @Test - void parseInvalidClassSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-c", "--select-class"); - } - - @ParameterizedTest - @EnumSource - void parseValidMethodSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("-m com.acme.Foo#m()").discovery.getSelectedMethods()), - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("--m com.acme.Foo#m()").discovery.getSelectedMethods()), - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("-select-method com.acme.Foo#m()").discovery.getSelectedMethods()), - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("-select-method=com.acme.Foo#m()").discovery.getSelectedMethods()), - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("--select-method com.acme.Foo#m()").discovery.getSelectedMethods()), - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), type.parseArgLine("--select-method=com.acme.Foo#m()").discovery.getSelectedMethods()), - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()"), selectMethod("com.example.Bar#method(java.lang.Object)")), - type.parseArgLine("-m com.acme.Foo#m() -m com.example.Bar#method(java.lang.Object)").discovery.getSelectedMethods()) - ); - // @formatter:on - } - - @Test - void parseInvalidMethodSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-m", "--select-method"); - } - - @ParameterizedTest - @EnumSource - void parseValidClasspathResourceSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("-r /foo.csv").discovery.getSelectedClasspathResources()), - () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("--r /foo.csv").discovery.getSelectedClasspathResources()), - () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("-select-resource /foo.csv").discovery.getSelectedClasspathResources()), - () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("-select-resource=/foo.csv").discovery.getSelectedClasspathResources()), - () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("--select-resource /foo.csv").discovery.getSelectedClasspathResources()), - () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), type.parseArgLine("--select-resource=/foo.csv").discovery.getSelectedClasspathResources()), - () -> assertEquals(List.of(selectClasspathResource("/foo.csv"), selectClasspathResource("bar.json")), type.parseArgLine("-r /foo.csv -r bar.json").discovery.getSelectedClasspathResources()) - ); - // @formatter:on - } - - @Test - void parseInvalidClasspathResourceSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-r", "--select-resource"); - } - - @ParameterizedTest - @EnumSource - void parseValidIterationSelectors(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectIteration(selectClasspathResource("/foo.csv"), 0)), type.parseArgLine("-i resource:/foo.csv[0]").discovery.getSelectedIterations()), - () -> assertEquals(List.of(selectIteration(selectMethod("com.acme.Foo#m()"), 1, 2)), type.parseArgLine("--i method:com.acme.Foo#m()[1..2]").discovery.getSelectedIterations()), - () -> assertEquals(List.of(selectIteration(selectClass("com.acme.Foo"), 0, 2)), type.parseArgLine("-select-iteration class:com.acme.Foo[0,2]").discovery.getSelectedIterations()), - () -> assertEquals(List.of(selectIteration(selectPackage("com.acme.foo"), 3)), type.parseArgLine("-select-iteration=package:com.acme.foo[3]").discovery.getSelectedIterations()), - () -> assertEquals(List.of(selectIteration(selectModule("com.acme.foo"), 0, 1, 2, 4, 5, 6)), type.parseArgLine("--select-iteration module:com.acme.foo[0..2,4..6]").discovery.getSelectedIterations()), - () -> assertEquals(List.of(selectIteration(selectDirectory("foo/bar"), 1, 5)), type.parseArgLine("--select-iteration=directory:foo/bar[1,5]").discovery.getSelectedIterations()), - () -> assertEquals(List.of(selectIteration(selectFile("foo.txt"), 6), selectIteration(selectUri("file:///foo.txt"), 7)), type.parseArgLine("-i file:foo.txt[6] -i uri:file:///foo.txt[7]").discovery.getSelectedIterations()) - ); - // @formatter:on - } - - @Test - void parseInvalidIterationSelectors() { - assertOptionWithMissingRequiredArgumentThrowsException("-i", "--select-iteration"); - } - - @ParameterizedTest - @EnumSource - void parseClasspathScanningEntries(ArgsType type) { - var dir = Paths.get("."); - // @formatter:off - assertAll( - () -> assertTrue(type.parseArgLine("--scan-class-path").discovery.isScanClasspath()), - () -> assertEquals(List.of(), type.parseArgLine("--scan-class-path").discovery.getSelectedClasspathEntries()), - () -> assertTrue(type.parseArgLine("--scan-classpath").discovery.isScanClasspath()), - () -> assertEquals(List.of(), type.parseArgLine("--scan-classpath").discovery.getSelectedClasspathEntries()), - () -> assertTrue(type.parseArgLine("--scan-class-path .").discovery.isScanClasspath()), - () -> assertEquals(List.of(dir), type.parseArgLine("--scan-class-path .").discovery.getSelectedClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("--scan-class-path=.").discovery.getSelectedClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("-scan-class-path .").discovery.getSelectedClasspathEntries()), - () -> assertEquals(List.of(dir), type.parseArgLine("-scan-class-path=.").discovery.getSelectedClasspathEntries()), - () -> assertEquals(List.of(dir, Paths.get("src/test/java")), type.parseArgLine("--scan-class-path . --scan-class-path src/test/java").discovery.getSelectedClasspathEntries()), - () -> assertEquals(List.of(dir, Paths.get("src/test/java")), type.parseArgLine("--scan-class-path ." + File.pathSeparator + "src/test/java").discovery.getSelectedClasspathEntries()) - ); - // @formatter:on - } - - @ParameterizedTest - @EnumSource - void parseValidConfigurationParameters(ArgsType type) { - // @formatter:off - assertAll( - () -> assertThat(type.parseArgLine("-config foo=bar").discovery.getConfigurationParameters()) - .containsOnly(entry("foo", "bar")), - () -> assertThat(type.parseArgLine("-config=foo=bar").discovery.getConfigurationParameters()) - .containsOnly(entry("foo", "bar")), - () -> assertThat(type.parseArgLine("--config foo=bar").discovery.getConfigurationParameters()) - .containsOnly(entry("foo", "bar")), - () -> assertThat(type.parseArgLine("--config=foo=bar").discovery.getConfigurationParameters()) - .containsOnly(entry("foo", "bar")), - () -> assertThat(type.parseArgLine("--config foo=bar --config baz=qux").discovery.getConfigurationParameters()) - .containsExactly(entry("foo", "bar"), entry("baz", "qux")) - ); - // @formatter:on - } - - @ParameterizedTest - @EnumSource - void parseValidConfigurationParametersResource(ArgsType type) { - // @formatter:off - assertAll( - () -> assertThat(type.parseArgLine("--config-resource foo.properties").discovery.getConfigurationParametersResources()) - .containsOnly("foo.properties"), - () -> assertThat(type.parseArgLine("--config-resource foo.properties --config-resource bar.properties").discovery.getConfigurationParametersResources()) - .containsExactly("foo.properties", "bar.properties") - ); - // @formatter:on - } - - @Test - void parseInvalidConfigurationParameters() { - assertOptionWithMissingRequiredArgumentThrowsException("-config", "--config"); - } - - @Test - void parseInvalidConfigurationParametersResource() { - assertOptionWithMissingRequiredArgumentThrowsException("--config-resource"); - } - - @ParameterizedTest - @EnumSource - void parseInvalidConfigurationParametersWithDuplicateKey(ArgsType type) { - Exception e = assertThrows(Exception.class, () -> type.parseArgLine("--config foo=bar --config foo=baz")); - - assertThat(e.getMessage()).isEqualTo("Duplicate key 'foo' for values 'bar' and 'baz'."); - } - - @ParameterizedTest - @EnumSource - void parseValidSelectorIdentifier(ArgsType type) { - // @formatter:off - assertAll( - () -> assertEquals(List.of(selectClasspathResource("/foo.csv")), parseIdentifiers(type,"--select resource:/foo.csv")), - () -> assertEquals(List.of(selectMethod("com.acme.Foo#m()")), parseIdentifiers(type,"--select method:com.acme.Foo#m()")), - () -> assertEquals(List.of(selectClass("com.acme.Foo")), parseIdentifiers(type,"--select class:com.acme.Foo")), - () -> assertEquals(List.of(selectPackage("com.acme.foo")), parseIdentifiers(type,"--select package:com.acme.foo")), - () -> assertEquals(List.of(selectModule("com.acme.foo")), parseIdentifiers(type,"--select module:com.acme.foo")), - () -> assertEquals(List.of(selectDirectory("foo/bar")), parseIdentifiers(type,"--select directory:foo/bar")), - () -> assertEquals(List.of(selectFile("foo.txt"), selectUri("file:///foo.txt")), parseIdentifiers(type,"--select file:foo.txt --select uri:file:///foo.txt")) - ); - // @formatter:on - } - - private static List parseIdentifiers(ArgsType type, String argLine) - throws IOException { - return DiscoverySelectors.parseAll(type.parseArgLine(argLine).discovery.getSelectorIdentifiers()).toList(); - } - - @Test - void parseInvalidSelectorIdentifier() { - assertOptionWithMissingRequiredArgumentThrowsException("--select"); - } - - private void assertOptionWithMissingRequiredArgumentThrowsException(String... options) { - assertAll( - Stream.of(options).map(opt -> () -> assertThrows(Exception.class, () -> ArgsType.args.parseArgLine(opt)))); - } - - enum ArgsType { - args { - @Override - Result parseArgLine(String argLine) { - return parse(split(argLine)); - } - }, - atFile { - @Override - Result parseArgLine(String argLine) throws IOException { - var atFile = Files.createTempFile("junit-launcher-args", ".txt"); - try { - Files.write(atFile, List.of(split(argLine))); - return parse("@" + atFile); - } - finally { - Files.deleteIfExists(atFile); - } - } - }; - - abstract Result parseArgLine(String argLine) throws IOException; - - private static String[] split(String argLine) { - return "".equals(argLine) ? new String[0] : argLine.split("\\s+"); - } - } - - private static Result parse(String... args) { - ExecuteTestsCommand command = new ExecuteTestsCommand((__, ___) -> null); - command.parseArgs(args); - return new Result(command.toTestDiscoveryOptions(), command.toTestConsoleOutputOptions()); - } - - record Result(TestDiscoveryOptions discovery, TestConsoleOutputOptions output) { - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ConsoleUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ConsoleUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ConsoleUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ConsoleUtilsTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.nio.charset.Charset; - -import org.junit.jupiter.api.Test; - -class ConsoleUtilsTests { - - @Test - void consoleCharsetReportedByConsoleUtilsIsEitherNativeCharsetOrDefaultCharset() { - var console = System.console(); - var expected = console != null ? console.charset() : Charset.defaultCharset(); - assertEquals(expected, ConsoleUtils.charset()); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ExecuteTestsCommandTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ExecuteTestsCommandTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ExecuteTestsCommandTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ExecuteTestsCommandTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.nio.file.Paths; -import java.util.Optional; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.platform.console.tasks.ConsoleTestExecutor; -import org.junit.platform.launcher.listeners.TestExecutionSummary; - -/** - * @since 1.10 - */ -class ExecuteTestsCommandTests { - - private final TestExecutionSummary summary = mock(); - private final ConsoleTestExecutor consoleTestExecutor = mock(); - private final ExecuteTestsCommand command = new ExecuteTestsCommand((__, ___) -> consoleTestExecutor); - - @BeforeEach - void setUp() { - when(consoleTestExecutor.execute(any(), any())).thenReturn(summary); - } - - @Test - void hasStatusCode0ForNoTotalFailures() { - when(summary.getTotalFailureCount()).thenReturn(0L); - - command.execute(); - - assertThat(command.getExitCode()).isEqualTo(0); - } - - @Test - void hasStatusCode1ForForAnyFailure() { - when(summary.getTotalFailureCount()).thenReturn(1L); - - command.execute(); - - assertThat(command.getExitCode()).isEqualTo(1); - } - - /** - * @since 1.3 - */ - @Test - void hasStatusCode2ForNoTestsAndHasOptionFailIfNoTestsFound() { - when(summary.getTestsFoundCount()).thenReturn(0L); - - command.execute("--fail-if-no-tests"); - - assertThat(command.getExitCode()).isEqualTo(2); - } - - /** - * @since 1.3 - */ - @Test - void hasStatusCode0ForTestsAndHasOptionFailIfNoTestsFound() { - when(summary.getTestsFoundCount()).thenReturn(1L); - when(summary.getTotalFailureCount()).thenReturn(0L); - - command.execute("--fail-if-no-tests"); - - assertThat(command.getExitCode()).isEqualTo(0); - } - - /** - * @since 1.3 - */ - @Test - void hasStatusCode0ForNoTestsAndNotFailIfNoTestsFound() { - when(summary.getTestsFoundCount()).thenReturn(0L); - - command.execute(); - - assertThat(command.getExitCode()).isEqualTo(0); - } - - @Test - void parseValidXmlReportsDirs() { - var dir = Paths.get("build", "test-results"); - // @formatter:off - assertAll( - () -> assertEquals(Optional.empty(), parseArgs().getReportsDir()), - () -> assertEquals(Optional.of(dir), parseArgs("--reports-dir", "build/test-results").getReportsDir()), - () -> assertEquals(Optional.of(dir), parseArgs("--reports-dir=build/test-results").getReportsDir()) - ); - // @formatter:on - } - - private ExecuteTestsCommand parseArgs(String... args) { - command.parseArgs(args); - return command; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ThemeTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ThemeTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ThemeTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/options/ThemeTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.options; - -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.nio.charset.StandardCharsets; - -import org.junit.jupiter.api.Test; - -class ThemeTests { - - @Test - void givenUtf8ShouldReturnUnicode() { - assertEquals(Theme.UNICODE, Theme.valueOf(StandardCharsets.UTF_8)); - } - - @Test - void givenAnythingElseShouldReturnAscii() { - assertAll("All character sets that are not UTF-8 should return Theme.ASCII", () -> { - assertEquals(Theme.ASCII, Theme.valueOf(StandardCharsets.ISO_8859_1)); - assertEquals(Theme.ASCII, Theme.valueOf(StandardCharsets.US_ASCII)); - assertEquals(Theme.ASCII, Theme.valueOf(StandardCharsets.UTF_16)); - }); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/ColorPaletteTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/ColorPaletteTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/ColorPaletteTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/ColorPaletteTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; +import static org.mockito.Mockito.mock; + +import java.io.PrintWriter; +import java.io.StringReader; +import java.util.List; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.fakes.TestDescriptorStub; +import org.junit.platform.launcher.TestExecutionListener; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +/** + * Unit tests for {@link ColorPalette}. + * + * @since 1.9 + */ +class ColorPaletteTests { + + @Nested + class LoadFromPropertiesTests { + + @Test + void singleOverride() { + String properties = """ + SUCCESSFUL = 35;1 + """; + ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); + + String actual = colorPalette.paint(Style.SUCCESSFUL, "text"); + + assertEquals("\u001B[35;1mtext\u001B[0m", actual); + } + + @Test + void keysAreCaseInsensitive() { + String properties = """ + suCcESSfuL = 35;1 + """; + ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); + + String actual = colorPalette.paint(Style.SUCCESSFUL, "text"); + + assertEquals("\u001B[35;1mtext\u001B[0m", actual); + } + + @Test + void junkKeysAreIgnored() { + String properties = """ + SUCCESSFUL = 35;1 + JUNK = 1;31;40 + """; + ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); + + String actual = colorPalette.paint(Style.SUCCESSFUL, "text"); + + assertEquals("\u001B[35;1mtext\u001B[0m", actual); + } + + @Test + void multipleOverrides() { + String properties = """ + SUCCESSFUL = 35;1 + FAILED = 33;4 + """; + ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); + + String successful = colorPalette.paint(Style.SUCCESSFUL, "text"); + String failed = colorPalette.paint(Style.FAILED, "text"); + + assertEquals("\u001B[35;1mtext\u001B[0m", successful); + assertEquals("\u001B[33;4mtext\u001B[0m", failed); + } + + @Test + void unspecifiedStylesAreDefault() { + String properties = """ + SUCCESSFUL = 35;1 + """; + ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); + + String actual = colorPalette.paint(Style.FAILED, "text"); + + assertEquals("\u001B[31mtext\u001B[0m", actual); + } + + @Test + void cannotOverrideNone() { + String properties = """ + NONE = 35;1 + """; + StringReader reader = new StringReader(properties); + + assertThrows(IllegalArgumentException.class, () -> new ColorPalette(reader)); + } + } + + /** + * TODO Actually assert something in these "demo" tests and stop printing to SYSOUT. + */ + @Nested + class DemonstratePalettesTests { + + @Test + void verbose_default() { + PrintWriter out = new PrintWriter(System.out); + TestExecutionListener listener = new VerboseTreePrintingListener(out, ColorPalette.DEFAULT, 16, + Theme.ASCII); + + demoTestRun(listener); + + assertDoesNotThrow(out::flush); + } + + @Test + void verbose_single_color() { + PrintWriter out = new PrintWriter(System.out); + TestExecutionListener listener = new VerboseTreePrintingListener(out, ColorPalette.SINGLE_COLOR, 16, + Theme.ASCII); + + demoTestRun(listener); + + assertDoesNotThrow(out::flush); + } + + @Test + void simple_default() { + PrintWriter out = new PrintWriter(System.out); + TestExecutionListener listener = new TreePrintingListener(out, ColorPalette.DEFAULT, Theme.ASCII); + + demoTestRun(listener); + + assertDoesNotThrow(out::flush); + } + + @Test + void simple_single_color() { + PrintWriter out = new PrintWriter(System.out); + TestExecutionListener listener = new TreePrintingListener(out, ColorPalette.SINGLE_COLOR, Theme.ASCII); + + demoTestRun(listener); + + assertDoesNotThrow(out::flush); + } + + @Test + void flat_default() { + PrintWriter out = new PrintWriter(System.out); + TestExecutionListener listener = new FlatPrintingListener(out, ColorPalette.DEFAULT); + + demoTestRun(listener); + + assertDoesNotThrow(out::flush); + } + + @Test + void flat_single_color() { + PrintWriter out = new PrintWriter(System.out); + TestExecutionListener listener = new FlatPrintingListener(out, ColorPalette.SINGLE_COLOR); + + demoTestRun(listener); + + assertDoesNotThrow(out::flush); + } + + private void demoTestRun(TestExecutionListener listener) { + TestDescriptor testDescriptor = new TestDescriptorStub(UniqueId.forEngine("demo-engine"), "My Test"); + TestPlan testPlan = TestPlan.from(true, List.of(testDescriptor), mock(), dummyOutputDirectoryCreator()); + listener.testPlanExecutionStarted(testPlan); + listener.executionStarted(TestIdentifier.from(testDescriptor)); + listener.executionFinished(TestIdentifier.from(testDescriptor), TestExecutionResult.successful()); + listener.dynamicTestRegistered(TestIdentifier.from(testDescriptor)); + listener.executionStarted(TestIdentifier.from(testDescriptor)); + listener.executionFinished(TestIdentifier.from(testDescriptor), + TestExecutionResult.failed(new Exception())); + listener.executionStarted(TestIdentifier.from(testDescriptor)); + listener.executionFinished(TestIdentifier.from(testDescriptor), + TestExecutionResult.aborted(new Exception())); + listener.reportingEntryPublished(TestIdentifier.from(testDescriptor), ReportEntry.from("Key", "Value")); + listener.executionSkipped(TestIdentifier.from(testDescriptor), "to demonstrate skipping"); + listener.testPlanExecutionFinished(testPlan); + } + + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/FlatPrintingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/FlatPrintingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/FlatPrintingListenerTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/FlatPrintingListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,191 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.console.output.FlatPrintingListener.INDENTATION; +import static org.junit.platform.engine.TestExecutionResult.failed; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Path; + +import org.assertj.core.util.Maps; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.fakes.TestDescriptorStub; +import org.junit.platform.launcher.TestIdentifier; + +/** + * @since 1.0 + */ +class FlatPrintingListenerTests { + + private static final String EOL = System.lineSeparator(); + + @Test + void executionSkipped() { + var stringWriter = new StringWriter(); + listener(stringWriter).executionSkipped(newTestIdentifier(), "Test" + EOL + "disabled"); + var lines = lines(stringWriter); + + assertEquals(3, lines.length); + assertAll("lines in the output", // + () -> assertEquals("Skipped: demo-test ([engine:demo-engine])", lines[0]), // + () -> assertEquals(INDENTATION + "=> Reason: Test", lines[1]), // + () -> assertEquals(INDENTATION + "disabled", lines[2])); + } + + @Test + void reportingEntryPublished() { + var stringWriter = new StringWriter(); + listener(stringWriter).reportingEntryPublished(newTestIdentifier(), ReportEntry.from("foo", "bar")); + var lines = lines(stringWriter); + + assertEquals(2, lines.length); + assertAll("lines in the output", // + () -> assertEquals("Reported: demo-test ([engine:demo-engine])", lines[0]), // + () -> assertTrue(lines[1].startsWith(INDENTATION + "=> Reported values: ReportEntry [timestamp =")), // + () -> assertTrue(lines[1].endsWith(", foo = 'bar']"))); + } + + @Test + void fileEntryPublished() { + var stringWriter = new StringWriter(); + listener(stringWriter).fileEntryPublished(newTestIdentifier(), + FileEntry.from(Path.of("test.txt"), "text/plain")); + var lines = lines(stringWriter); + + assertEquals(2, lines.length); + assertAll("lines in the output", // + () -> assertEquals("Reported: demo-test ([engine:demo-engine])", lines[0]), // + () -> assertTrue(lines[1].startsWith(INDENTATION + "=> Reported file: FileEntry [timestamp =")), // + () -> assertTrue(lines[1].endsWith(", path = test.txt, mediaType = 'text/plain']"))); + } + + @Test + void executionFinishedWithFailure() { + var stringWriter = new StringWriter(); + listener(stringWriter).executionFinished(newTestIdentifier(), failed(new AssertionError("Boom!"))); + var lines = lines(stringWriter); + + assertAll("lines in the output", // + () -> assertEquals("Finished: demo-test ([engine:demo-engine])", lines[0]), // + () -> assertEquals(INDENTATION + "=> Exception: java.lang.AssertionError: Boom!", lines[1])); + } + + @Nested + class ColorPaletteTests { + + @Nested + class DefaultColorPaletteTests { + + @Test + void executionSkipped() { + var stringWriter = new StringWriter(); + new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.DEFAULT).executionSkipped( + newTestIdentifier(), "Test" + EOL + "disabled"); + var lines = lines(stringWriter); + + assertEquals(3, lines.length); + assertAll("lines in the output", // + () -> assertEquals("\u001B[35mSkipped: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // + () -> assertEquals("\u001B[35m" + INDENTATION + "=> Reason: Test", lines[1]), // + () -> assertEquals(INDENTATION + "disabled\u001B[0m", lines[2])); + } + + @Test + void reportingEntryPublished() { + var stringWriter = new StringWriter(); + new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.DEFAULT).reportingEntryPublished( + newTestIdentifier(), ReportEntry.from("foo", "bar")); + var lines = lines(stringWriter); + + assertEquals(2, lines.length); + assertAll("lines in the output", // + () -> assertEquals("\u001B[37mReported: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // + () -> assertTrue(lines[1].startsWith( + "\u001B[37m" + INDENTATION + "=> Reported values: ReportEntry [timestamp =")), // + () -> assertTrue(lines[1].endsWith(", foo = 'bar']\u001B[0m"))); + } + + @Test + void executionFinishedWithFailure() { + var stringWriter = new StringWriter(); + new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.DEFAULT).executionFinished( + newTestIdentifier(), failed(new AssertionError("Boom!"))); + var lines = lines(stringWriter); + + assertAll("lines in the output", // + () -> assertEquals("\u001B[31mFinished: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // + () -> assertEquals("\u001B[31m" + INDENTATION + "=> Exception: java.lang.AssertionError: Boom!", + lines[1]), + () -> assertTrue(lines[lines.length - 1].endsWith("\u001B[0m"))); + } + + } + + @Nested + class ColorPaletteOverrideTests { + + @Test + void overridingSkipped() { + var stringWriter = new StringWriter(); + ColorPalette colorPalette = new ColorPalette(Maps.newHashMap(Style.SKIPPED, "36;7")); + new FlatPrintingListener(new PrintWriter(stringWriter), colorPalette).executionSkipped( + newTestIdentifier(), "Test" + EOL + "disabled"); + var lines = lines(stringWriter); + + assertEquals(3, lines.length); + assertAll("lines in the output", // + () -> assertEquals("\u001B[36;7mSkipped: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // + () -> assertEquals("\u001B[36;7m" + INDENTATION + "=> Reason: Test", lines[1]), // + () -> assertEquals(INDENTATION + "disabled\u001B[0m", lines[2])); + } + + @Test + void overridingUnusedStyle() { + var stringWriter = new StringWriter(); + ColorPalette colorPalette = new ColorPalette(Maps.newHashMap(Style.FAILED, "36;7")); + new FlatPrintingListener(new PrintWriter(stringWriter), colorPalette).executionSkipped( + newTestIdentifier(), "Test" + EOL + "disabled"); + var lines = lines(stringWriter); + + assertEquals(3, lines.length); + assertAll("lines in the output", // + () -> assertEquals("\u001B[35mSkipped: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // + () -> assertEquals("\u001B[35m" + INDENTATION + "=> Reason: Test", lines[1]), // + () -> assertEquals(INDENTATION + "disabled\u001B[0m", lines[2])); + } + + } + + } + + private FlatPrintingListener listener(StringWriter stringWriter) { + return new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.NONE); + } + + private static TestIdentifier newTestIdentifier() { + var testDescriptor = new TestDescriptorStub(UniqueId.forEngine("demo-engine"), "demo-test"); + return TestIdentifier.from(testDescriptor); + } + + private String[] lines(StringWriter stringWriter) { + return stringWriter.toString().split(EOL); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TestFeedPrintingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TestFeedPrintingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TestFeedPrintingListenerTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TestFeedPrintingListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,116 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; +import static org.mockito.Mockito.mock; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collections; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.EngineDescriptor; +import org.junit.platform.fakes.TestDescriptorStub; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; +import org.opentest4j.TestAbortedException; + +public class TestFeedPrintingListenerTests { + + TestPlan testPlan; + TestIdentifier testIdentifier; + + StringWriter stringWriter = new StringWriter(); + TestFeedPrintingListener listener = new TestFeedPrintingListener(new PrintWriter(stringWriter), ColorPalette.NONE); + + @BeforeEach + void prepareListener() { + var engineDescriptor = new EngineDescriptor(UniqueId.forEngine("demo-engine"), "Demo Engine"); + var testDescriptor = new TestDescriptorStub(engineDescriptor.getUniqueId().append("type", "test"), + "%c ool test"); + engineDescriptor.addChild(testDescriptor); + + testPlan = TestPlan.from(true, Collections.singleton(engineDescriptor), mock(), dummyOutputDirectoryCreator()); + testIdentifier = testPlan.getTestIdentifier(testDescriptor.getUniqueId()); + + listener.testPlanExecutionStarted(testPlan); + } + + @Test + public void testExecutionSkipped() { + listener.executionSkipped(testIdentifier, "Test disabled"); + assertLinesMatch( // + """ + Demo Engine > %c ool test :: SKIPPED + \tReason: Test disabled + """.lines(), // + actualLines() // + ); + } + + @Test + public void testExecutionFailed() { + listener.executionFinished(testIdentifier, TestExecutionResult.failed(new AssertionError("Boom!"))); + assertLinesMatch( // + """ + Demo Engine > %c ool test :: FAILED + \tjava.lang.AssertionError: Boom! + >>>> + """.lines(), // + actualLines() // + ); + } + + @Test + public void testExecutionAborted() { + listener.executionFinished(testIdentifier, TestExecutionResult.aborted(new TestAbortedException("Boom!"))); + assertLinesMatch( // + """ + Demo Engine > %c ool test :: ABORTED + \torg.opentest4j.TestAbortedException: Boom! + >>>> + """.lines(), // + actualLines() // + ); + } + + @Test + public void testExecutionSucceeded() { + listener.executionFinished(testIdentifier, TestExecutionResult.successful()); + assertLinesMatch(Stream.of("Demo Engine > %c ool test :: SUCCESSFUL"), actualLines()); + } + + @Test + public void testExecutionFailedOfContainer() { + var engineIdentifier = getOnlyElement(testPlan.getRoots()); + listener.executionFinished(engineIdentifier, TestExecutionResult.failed(new AssertionError("Boom!"))); + assertLinesMatch( // + """ + Demo Engine :: FAILED + \tjava.lang.AssertionError: Boom! + >>>> + """.lines(), // + actualLines() // + ); + } + + private Stream actualLines() { + return stringWriter.toString().lines(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreeNodeTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreeNodeTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreeNodeTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreeNodeTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.reporting.ReportEntry; + +class TreeNodeTests { + + private static final int NUM_THREADS = 2; + private static final int ITEMS_PER_THREAD = 1000; + + @Test + void caption() { + assertEquals("", TreeNode.createCaption("")); + assertEquals("[@@]", TreeNode.createCaption("[@@]")); + assertEquals("[@ @]", TreeNode.createCaption("[@ @]")); + assertEquals("[@ @]", TreeNode.createCaption("[@\u000B@]")); + assertEquals("[@ @]", TreeNode.createCaption("[@\t@]")); + assertEquals("[@ @]", TreeNode.createCaption("[@\t\n@]")); + assertEquals("[@ @]", TreeNode.createCaption("[@\t\n\r@]")); + assertEquals("[@ @]", TreeNode.createCaption("[@\t\n\r\f@]")); + assertEquals("@".repeat(80) + "...", TreeNode.createCaption("@".repeat(1000) + "!")); + } + + @Test + void childrenCanBeAddedConcurrently() throws Exception { + var treeNode = new TreeNode("root"); + + runConcurrently(() -> { + for (long i = 0; i < ITEMS_PER_THREAD; i++) { + treeNode.addChild(new TreeNode(String.valueOf(i))); + } + }); + + assertThat(treeNode.children).hasSize(NUM_THREADS * ITEMS_PER_THREAD); + } + + @Test + void reportEntriesCanBeAddedConcurrently() throws Exception { + var treeNode = new TreeNode("root"); + + runConcurrently(() -> { + for (long i = 0; i < ITEMS_PER_THREAD; i++) { + treeNode.addReportEntry(ReportEntry.from("index", String.valueOf(i))); + } + }); + + assertThat(treeNode.reports).hasSize(NUM_THREADS * ITEMS_PER_THREAD); + } + + @SuppressWarnings("resource") + private void runConcurrently(Runnable action) throws InterruptedException { + ExecutorService executor = new ThreadPoolExecutor(NUM_THREADS, NUM_THREADS, 10, SECONDS, + new ArrayBlockingQueue<>(NUM_THREADS)); + try { + var barrier = new CyclicBarrier(NUM_THREADS); + for (long i = 0; i < NUM_THREADS; i++) { + executor.submit(() -> { + await(barrier); + action.run(); + }); + } + } + finally { + executor.shutdown(); + var terminated = executor.awaitTermination(10, SECONDS); + assertTrue(terminated, "Executor was not terminated"); + } + } + + private void await(CyclicBarrier barrier) { + try { + barrier.await(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreePrinterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreePrinterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreePrinterTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/TreePrinterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.platform.engine.TestExecutionResult.aborted; +import static org.junit.platform.engine.TestExecutionResult.failed; +import static org.junit.platform.engine.TestExecutionResult.successful; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.fakes.TestDescriptorStub; +import org.junit.platform.launcher.TestIdentifier; + +class TreePrinterTests { + + private final Charset charset = StandardCharsets.UTF_8; + private final ByteArrayOutputStream stream = new ByteArrayOutputStream(1000); + private final PrintWriter out = new PrintWriter(new OutputStreamWriter(stream, charset)); + + private List actual() { + out.flush(); + return List.of(stream.toString(charset).split("\\R")); + } + + @Test + void emptyTree() { + new TreePrinter(out, Theme.UNICODE, ColorPalette.NONE).print(new TreeNode("")); + assertIterableEquals(List.of("╷"), actual()); + } + + @Test + void emptyEngines() { + var root = new TreeNode(""); + root.addChild(new TreeNode(identifier("e-0", "engine zero"), "none")); + root.addChild(new TreeNode(identifier("e-1", "engine one")).setResult(successful())); + root.addChild(new TreeNode(identifier("e-2", "engine two")).setResult(failed(null))); + root.addChild(new TreeNode(identifier("e-3", "engine three")).setResult(aborted(null))); + new TreePrinter(out, Theme.UNICODE, ColorPalette.NONE).print(root); + assertIterableEquals( // + List.of( // + "╷", // + "├─ engine zero ↷ none", // + "├─ engine one ✔", // + "├─ engine two ✘", // + "└─ engine three ■"), // + actual()); + } + + @Test + // https://github.com/junit-team/junit-framework/issues/786 + void printNodeHandlesNullMessageThrowableGracefully() { + var result = TestExecutionResult.failed(new NullPointerException()); + var node = new TreeNode(identifier("NPE", "test()")).setResult(result); + new TreePrinter(out, Theme.ASCII, ColorPalette.NONE).print(node); + assertLinesMatch(List.of(".", "+-- test() [X] java.lang.NullPointerException"), actual()); + } + + @Test + // https://github.com/junit-team/junit-framework/issues/1531 + void reportsAreTabbedCorrectly() { + var root = new TreeNode(""); + var e1 = new TreeNode(identifier("e-1", "engine one")).setResult(successful()); + e1.addReportEntry(ReportEntry.from("key", "e-1")); + root.addChild(e1); + + var c1 = new TreeNode(identifier("c-1", "class one")).setResult(successful()); + c1.addReportEntry(ReportEntry.from("key", "c-1")); + e1.addChild(c1); + + var m1 = new TreeNode(identifier("m-1", "method one")).setResult(successful()); + m1.addReportEntry(ReportEntry.from("key", "m-1")); + c1.addChild(m1); + + var m2 = new TreeNode(identifier("m-2", "method two")).setResult(successful()); + m2.addFileEntry(FileEntry.from(Path.of("test.txt"), "text/plain")); + c1.addChild(m2); + + new TreePrinter(out, Theme.UNICODE, ColorPalette.NONE).print(root); + assertLinesMatch(List.of( // + "╷", // + "└─ engine one ✔", // + " │ ....-..-..T..:...* key = `e-1`", // + " └─ class one ✔", // + " │ ....-..-..T..:...* key = `c-1`", // + " ├─ method one ✔", // + " │ ....-..-..T..:...* key = `m-1`", // + " └─ method two ✔", // + " ....-..-..T..:...* file:.*" // + ), // + actual()); + } + + private static TestIdentifier identifier(String id, String displayName) { + var descriptor = new TestDescriptorStub(UniqueId.forEngine(id), displayName); + return TestIdentifier.from(descriptor); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/VerboseTreePrintingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/VerboseTreePrintingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/VerboseTreePrintingListenerTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/output/VerboseTreePrintingListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,109 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.console.output; + +import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.platform.engine.TestExecutionResult.failed; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; +import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.fakes.TestDescriptorStub; +import org.junit.platform.launcher.TestIdentifier; + +/** + * @since 1.3.2 + */ +class VerboseTreePrintingListenerTests { + + private static final String EOL = System.lineSeparator(); + + @Test + void executionSkipped() { + var stringWriter = new StringWriter(); + listener(stringWriter).executionSkipped(newTestIdentifier(), "Test" + EOL + "disabled"); + var lines = lines(stringWriter); + + assertLinesMatch(List.of( // + "+-- %c ool test", // + " tags: []", // + " uniqueId: [engine:demo-engine]", // + " parent: []", // + " reason: Test", // + " disabled", // + " status: [S] SKIPPED"), List.of(lines)); + } + + @Test + void reportingEntryPublished() { + var stringWriter = new StringWriter(); + listener(stringWriter).reportingEntryPublished(newTestIdentifier(), ReportEntry.from("foo", "bar")); + var lines = lines(stringWriter); + + assertLinesMatch(List.of(" reports: ReportEntry \\[timestamp = .+, foo = 'bar'\\]"), List.of(lines)); + } + + @Test + void fileEntryPublished() { + var stringWriter = new StringWriter(); + listener(stringWriter).fileEntryPublished(newTestIdentifier(), + FileEntry.from(Path.of("test.txt"), "text/plain")); + var lines = lines(stringWriter); + + assertLinesMatch( + List.of(" reports: FileEntry \\[timestamp = .+, path = test.txt, mediaType = 'text/plain'\\]"), + List.of(lines)); + } + + @Test + void executionFinishedWithFailure() { + var stringWriter = new StringWriter(); + listener(stringWriter).executionFinished(newTestIdentifier(), failed(new AssertionError("Boom!"))); + var lines = lines(stringWriter); + + assertLinesMatch(List.of(" caught: java.lang.AssertionError: Boom!", // + ">> STACKTRACE >>", // + " duration: \\d+ ms", // + " status: [X] FAILED"), List.of(lines)); + } + + @Test + void failureMessageWithFormatSpecifier() { + var stringWriter = new StringWriter(); + listener(stringWriter).executionFinished(newTestIdentifier(), failed(new AssertionError("%crash"))); + var lines = lines(stringWriter); + + assertLinesMatch(List.of(" caught: java.lang.AssertionError: %crash", // + ">> STACKTRACE >>", // + " duration: \\d+ ms", // + " status: [X] FAILED"), List.of(lines)); + } + + private VerboseTreePrintingListener listener(StringWriter stringWriter) { + return new VerboseTreePrintingListener(new PrintWriter(stringWriter), ColorPalette.NONE, 16, Theme.ASCII); + } + + private static TestIdentifier newTestIdentifier() { + var testDescriptor = new TestDescriptorStub(UniqueId.forEngine("demo-engine"), "%c ool test"); + return TestIdentifier.from(testDescriptor); + } + + private String[] lines(StringWriter stringWriter) { + return stringWriter.toString().split(EOL); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTest.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTest.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForInnerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTest.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTest.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,6 +18,7 @@ // problem since the test method here can never fail. class ContainerForStaticNestedTest { + @SuppressWarnings("JUnitMalformedDeclaration") static class NestedTest { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ContainerForStaticNestedTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,6 +18,7 @@ // problem since the test method here can never fail. class ContainerForStaticNestedTests { + @SuppressWarnings("JUnitMalformedDeclaration") static class NestedTests { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/SecondTest.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/SecondTest.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/SecondTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/SecondTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test1.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test1.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test1.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Test1.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Tests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Tests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Tests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/Tests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ThirdTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ThirdTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ThirdTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/subpackage/ThirdTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,207 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; - -import java.io.PrintWriter; -import java.io.StringReader; -import java.util.List; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.platform.console.options.Theme; -import org.junit.platform.engine.TestDescriptor; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.fakes.TestDescriptorStub; -import org.junit.platform.launcher.TestExecutionListener; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.launcher.TestPlan; - -/** - * Unit tests for {@link ColorPalette}. - * - * @since 1.9 - */ -class ColorPaletteTests { - - @Nested - class LoadFromPropertiesTests { - - @Test - void singleOverride() { - String properties = """ - SUCCESSFUL = 35;1 - """; - ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); - - String actual = colorPalette.paint(Style.SUCCESSFUL, "text"); - - assertEquals("\u001B[35;1mtext\u001B[0m", actual); - } - - @Test - void keysAreCaseInsensitive() { - String properties = """ - suCcESSfuL = 35;1 - """; - ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); - - String actual = colorPalette.paint(Style.SUCCESSFUL, "text"); - - assertEquals("\u001B[35;1mtext\u001B[0m", actual); - } - - @Test - void junkKeysAreIgnored() { - String properties = """ - SUCCESSFUL = 35;1 - JUNK = 1;31;40 - """; - ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); - - String actual = colorPalette.paint(Style.SUCCESSFUL, "text"); - - assertEquals("\u001B[35;1mtext\u001B[0m", actual); - } - - @Test - void multipleOverrides() { - String properties = """ - SUCCESSFUL = 35;1 - FAILED = 33;4 - """; - ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); - - String successful = colorPalette.paint(Style.SUCCESSFUL, "text"); - String failed = colorPalette.paint(Style.FAILED, "text"); - - assertEquals("\u001B[35;1mtext\u001B[0m", successful); - assertEquals("\u001B[33;4mtext\u001B[0m", failed); - } - - @Test - void unspecifiedStylesAreDefault() { - String properties = """ - SUCCESSFUL = 35;1 - """; - ColorPalette colorPalette = new ColorPalette(new StringReader(properties)); - - String actual = colorPalette.paint(Style.FAILED, "text"); - - assertEquals("\u001B[31mtext\u001B[0m", actual); - } - - @Test - void cannotOverrideNone() { - String properties = """ - NONE = 35;1 - """; - StringReader reader = new StringReader(properties); - - assertThrows(IllegalArgumentException.class, () -> new ColorPalette(reader)); - } - } - - /** - * TODO Actually assert something in these "demo" tests and stop printing to SYSOUT. - */ - @Nested - class DemonstratePalettesTests { - - @Test - void verbose_default() { - PrintWriter out = new PrintWriter(System.out); - TestExecutionListener listener = new VerboseTreePrintingListener(out, ColorPalette.DEFAULT, 16, - Theme.ASCII); - - demoTestRun(listener); - - assertDoesNotThrow(out::flush); - } - - @Test - void verbose_single_color() { - PrintWriter out = new PrintWriter(System.out); - TestExecutionListener listener = new VerboseTreePrintingListener(out, ColorPalette.SINGLE_COLOR, 16, - Theme.ASCII); - - demoTestRun(listener); - - assertDoesNotThrow(out::flush); - } - - @Test - void simple_default() { - PrintWriter out = new PrintWriter(System.out); - TestExecutionListener listener = new TreePrintingListener(out, ColorPalette.DEFAULT, Theme.ASCII); - - demoTestRun(listener); - - assertDoesNotThrow(out::flush); - } - - @Test - void simple_single_color() { - PrintWriter out = new PrintWriter(System.out); - TestExecutionListener listener = new TreePrintingListener(out, ColorPalette.SINGLE_COLOR, Theme.ASCII); - - demoTestRun(listener); - - assertDoesNotThrow(out::flush); - } - - @Test - void flat_default() { - PrintWriter out = new PrintWriter(System.out); - TestExecutionListener listener = new FlatPrintingListener(out, ColorPalette.DEFAULT); - - demoTestRun(listener); - - assertDoesNotThrow(out::flush); - } - - @Test - void flat_single_color() { - PrintWriter out = new PrintWriter(System.out); - TestExecutionListener listener = new FlatPrintingListener(out, ColorPalette.SINGLE_COLOR); - - demoTestRun(listener); - - assertDoesNotThrow(out::flush); - } - - private void demoTestRun(TestExecutionListener listener) { - TestDescriptor testDescriptor = new TestDescriptorStub(UniqueId.forEngine("demo-engine"), "My Test"); - TestPlan testPlan = TestPlan.from(List.of(testDescriptor), mock()); - listener.testPlanExecutionStarted(testPlan); - listener.executionStarted(TestIdentifier.from(testDescriptor)); - listener.executionFinished(TestIdentifier.from(testDescriptor), TestExecutionResult.successful()); - listener.dynamicTestRegistered(TestIdentifier.from(testDescriptor)); - listener.executionStarted(TestIdentifier.from(testDescriptor)); - listener.executionFinished(TestIdentifier.from(testDescriptor), - TestExecutionResult.failed(new Exception())); - listener.executionStarted(TestIdentifier.from(testDescriptor)); - listener.executionFinished(TestIdentifier.from(testDescriptor), - TestExecutionResult.aborted(new Exception())); - listener.reportingEntryPublished(TestIdentifier.from(testDescriptor), ReportEntry.from("Key", "Value")); - listener.executionSkipped(TestIdentifier.from(testDescriptor), "to demonstrate skipping"); - listener.testPlanExecutionFinished(testPlan); - } - - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ConsoleTestExecutorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ConsoleTestExecutorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ConsoleTestExecutorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/ConsoleTestExecutorTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.platform.commons.util.ClassLoaderUtils.getDefaultClassLoader; -import static org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly.createLauncher; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.file.Paths; -import java.util.List; -import java.util.Optional; - -import org.junit.jupiter.api.Test; -import org.junit.platform.console.options.Details; -import org.junit.platform.console.options.TestConsoleOutputOptions; -import org.junit.platform.console.options.TestDiscoveryOptions; -import org.junit.platform.engine.support.hierarchical.DemoHierarchicalTestEngine; - -/** - * @since 1.0 - */ -class ConsoleTestExecutorTests { - - private static final Runnable FAILING_BLOCK = () -> fail("should fail"); - private static final Runnable SUCCEEDING_TEST = () -> { - }; - - private final StringWriter stringWriter = new StringWriter(); - private final TestDiscoveryOptions discoveryOptions = new TestDiscoveryOptions(); - private final TestConsoleOutputOptions outputOptions = new TestConsoleOutputOptions(); - private final DemoHierarchicalTestEngine dummyTestEngine = new DemoHierarchicalTestEngine(); - - { - discoveryOptions.setScanClasspath(true); - } - - @Test - void printsSummary() { - dummyTestEngine.addTest("succeedingTest", SUCCEEDING_TEST); - dummyTestEngine.addTest("failingTest", FAILING_BLOCK); - - var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); - task.execute(new PrintWriter(stringWriter), Optional.empty()); - - assertThat(stringWriter.toString()).contains("Test run finished after", "2 tests found", "0 tests skipped", - "2 tests started", "0 tests aborted", "1 tests successful", "1 tests failed"); - } - - @Test - void printsDetailsIfTheyAreNotHidden() { - outputOptions.setDetails(Details.FLAT); - - dummyTestEngine.addTest("failingTest", FAILING_BLOCK); - - var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); - task.execute(new PrintWriter(stringWriter), Optional.empty()); - - assertThat(stringWriter.toString()).contains("Test execution started."); - } - - @Test - void printsNoDetailsIfTheyAreHidden() { - outputOptions.setDetails(Details.NONE); - - dummyTestEngine.addTest("failingTest", FAILING_BLOCK); - - var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); - task.execute(new PrintWriter(stringWriter), Optional.empty()); - - assertThat(stringWriter.toString()).doesNotContain("Test execution started."); - } - - @Test - void printsFailuresEvenIfDetailsAreHidden() { - outputOptions.setDetails(Details.NONE); - - dummyTestEngine.addTest("failingTest", FAILING_BLOCK); - dummyTestEngine.addContainer("failingContainer", FAILING_BLOCK); - - var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); - task.execute(new PrintWriter(stringWriter), Optional.empty()); - - assertThat(stringWriter.toString()).contains("Failures (2)", "failingTest", "failingContainer"); - } - - @Test - void usesCustomClassLoaderIfAdditionalClassPathEntriesArePresent() { - discoveryOptions.setAdditionalClasspathEntries(List.of(Paths.get("."))); - - var oldClassLoader = getDefaultClassLoader(); - dummyTestEngine.addTest("failingTest", - () -> assertSame(oldClassLoader, getDefaultClassLoader(), "should fail")); - - var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); - task.execute(new PrintWriter(stringWriter), Optional.empty()); - - assertThat(stringWriter.toString()).contains("failingTest", "should fail", "1 tests failed"); - } - - @Test - void usesSameClassLoaderIfNoAdditionalClassPathEntriesArePresent() { - discoveryOptions.setAdditionalClasspathEntries(List.of()); - - var oldClassLoader = getDefaultClassLoader(); - dummyTestEngine.addTest("failingTest", - () -> assertNotSame(oldClassLoader, getDefaultClassLoader(), "should fail")); - - var task = new ConsoleTestExecutor(discoveryOptions, outputOptions, () -> createLauncher(dummyTestEngine)); - task.execute(new PrintWriter(stringWriter), Optional.empty()); - - assertThat(stringWriter.toString()).contains("failingTest", "should fail", "1 tests failed"); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/CustomContextClassLoaderExecutorTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.jupiter.api.Test; - -/** - * @since 1.0 - */ -class CustomContextClassLoaderExecutorTests { - - @Test - void invokeWithoutCustomClassLoaderDoesNotSetClassLoader() throws Exception { - var originalClassLoader = Thread.currentThread().getContextClassLoader(); - var executor = new CustomContextClassLoaderExecutor(Optional.empty()); - - int result = executor.invoke(() -> { - assertSame(originalClassLoader, Thread.currentThread().getContextClassLoader()); - return 42; - }); - - assertEquals(42, result); - assertSame(originalClassLoader, Thread.currentThread().getContextClassLoader()); - } - - @Test - void invokeWithCustomClassLoaderSetsCustomAndResetsToOriginal() throws Exception { - var originalClassLoader = Thread.currentThread().getContextClassLoader(); - ClassLoader customClassLoader = URLClassLoader.newInstance(new URL[0]); - var executor = new CustomContextClassLoaderExecutor(Optional.of(customClassLoader)); - - int result = executor.invoke(() -> { - assertSame(customClassLoader, Thread.currentThread().getContextClassLoader()); - return 23; - }); - - assertEquals(23, result); - assertSame(originalClassLoader, Thread.currentThread().getContextClassLoader()); - } - - @Test - void invokeWithCustomClassLoaderAndEnsureItIsClosedAfterUsage() throws Exception { - var closed = new AtomicBoolean(false); - ClassLoader localClassLoader = new URLClassLoader(new URL[0]) { - @Override - public void close() throws IOException { - closed.set(true); - super.close(); - } - }; - var executor = new CustomContextClassLoaderExecutor(Optional.of(localClassLoader)); - - int result = executor.invoke(() -> 4711); - - assertEquals(4711, result); - assertTrue(closed.get()); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/DiscoveryRequestCreatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/DiscoveryRequestCreatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/DiscoveryRequestCreatorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/DiscoveryRequestCreatorTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,368 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static java.util.stream.Collectors.toMap; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.platform.engine.discovery.ClassNameFilter.STANDARD_INCLUDE_PATTERN; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResource; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectDirectory; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectFile; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectIteration; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUri; - -import java.io.File; -import java.net.URI; -import java.nio.file.Paths; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Stream; - -import org.junit.jupiter.api.Test; -import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.console.options.TestDiscoveryOptions; -import org.junit.platform.engine.Filter; -import org.junit.platform.engine.discovery.ClassNameFilter; -import org.junit.platform.engine.discovery.ClassSelector; -import org.junit.platform.engine.discovery.ClasspathResourceSelector; -import org.junit.platform.engine.discovery.ClasspathRootSelector; -import org.junit.platform.engine.discovery.DirectorySelector; -import org.junit.platform.engine.discovery.FileSelector; -import org.junit.platform.engine.discovery.IterationSelector; -import org.junit.platform.engine.discovery.MethodSelector; -import org.junit.platform.engine.discovery.PackageNameFilter; -import org.junit.platform.engine.discovery.PackageSelector; -import org.junit.platform.engine.discovery.UriSelector; -import org.junit.platform.launcher.LauncherDiscoveryRequest; - -/** - * @since 1.0 - */ -class DiscoveryRequestCreatorTests { - - private final TestDiscoveryOptions options = new TestDiscoveryOptions(); - - @Test - void convertsScanClasspathOptionWithoutExplicitRootDirectories() { - options.setScanClasspath(true); - - var request = convert(); - - var classpathRootSelectors = request.getSelectorsByType(ClasspathRootSelector.class); - // @formatter:off - assertThat(classpathRootSelectors).extracting(ClasspathRootSelector::getClasspathRoot) - .hasAtLeastOneElementOfType(URI.class) - .doesNotContainNull(); - // @formatter:on - } - - @Test - void convertsScanClasspathOptionWithExplicitRootDirectories() { - options.setScanClasspath(true); - options.setSelectedClasspathEntries(List.of(Paths.get("."), Paths.get(".."))); - - var request = convert(); - - var classpathRootSelectors = request.getSelectorsByType(ClasspathRootSelector.class); - // @formatter:off - assertThat(classpathRootSelectors).extracting(ClasspathRootSelector::getClasspathRoot) - .containsExactly(new File(".").toURI(), new File("..").toURI()); - // @formatter:on - } - - @Test - void convertsScanClasspathOptionWithAdditionalClasspathEntries() { - options.setScanClasspath(true); - options.setAdditionalClasspathEntries(List.of(Paths.get("."), Paths.get(".."))); - - var request = convert(); - - var classpathRootSelectors = request.getSelectorsByType(ClasspathRootSelector.class); - // @formatter:off - assertThat(classpathRootSelectors).extracting(ClasspathRootSelector::getClasspathRoot) - .contains(new File(".").toURI(), new File("..").toURI()); - // @formatter:on - } - - @Test - void doesNotSupportScanClasspathAndExplicitSelectors() { - options.setScanClasspath(true); - options.setSelectedClasses(List.of(selectClass("SomeTest"))); - - Throwable cause = assertThrows(PreconditionViolationException.class, this::convert); - - assertThat(cause).hasMessageContaining("not supported"); - } - - @Test - void convertsDefaultIncludeClassNamePatternOption() { - options.setScanClasspath(true); - - var request = convert(); - - var filters = request.getFiltersByType(ClassNameFilter.class); - assertThat(filters).hasSize(1); - assertExcludes(filters.get(0), STANDARD_INCLUDE_PATTERN); - } - - @Test - void convertsExplicitIncludeClassNamePatternOption() { - options.setScanClasspath(true); - options.setIncludedClassNamePatterns(List.of("Foo.*Bar", "Bar.*Foo")); - - var request = convert(); - - var filters = request.getFiltersByType(ClassNameFilter.class); - assertThat(filters).hasSize(1); - assertIncludes(filters.get(0), "Foo.*Bar"); - assertIncludes(filters.get(0), "Bar.*Foo"); - } - - @Test - void includeSelectedClassesAndMethodsRegardlessOfClassNamePatterns() { - options.setSelectedClasses(List.of(selectClass("SomeTest"))); - options.setSelectedMethods(List.of(selectMethod("com.acme.Foo#m()"))); - options.setSelectedIterations(List.of(selectIteration(selectMethod("com.acme.Bar#n()"), 0))); - options.setIncludedClassNamePatterns(List.of("Foo.*Bar")); - - var request = convert(); - - var filters = request.getFiltersByType(ClassNameFilter.class); - assertThat(filters).hasSize(1); - assertIncludes(filters.get(0), "SomeTest"); - assertIncludes(filters.get(0), "com.acme.Foo"); - assertIncludes(filters.get(0), "com.acme.Bar"); - assertIncludes(filters.get(0), "Foo.*Bar"); - } - - @Test - void convertsExcludeClassNamePatternOption() { - options.setScanClasspath(true); - options.setExcludedClassNamePatterns(List.of("Foo.*Bar", "Bar.*Foo")); - - var request = convert(); - - var filters = request.getFiltersByType(ClassNameFilter.class); - assertThat(filters).hasSize(2); - assertExcludes(filters.get(1), "Foo.*Bar"); - assertExcludes(filters.get(1), "Bar.*Foo"); - } - - @Test - void convertsPackageOptions() { - options.setScanClasspath(true); - options.setIncludedPackages(List.of("org.junit.included1", "org.junit.included2", "org.junit.included3")); - options.setExcludedPackages(List.of("org.junit.excluded1")); - - var request = convert(); - var packageNameFilters = request.getFiltersByType(PackageNameFilter.class); - - assertThat(packageNameFilters).hasSize(2); - assertIncludes(packageNameFilters.get(0), "org.junit.included1"); - assertIncludes(packageNameFilters.get(0), "org.junit.included2"); - assertIncludes(packageNameFilters.get(0), "org.junit.included3"); - assertExcludes(packageNameFilters.get(1), "org.junit.excluded1"); - } - - @Test - void convertsTagOptions() { - options.setScanClasspath(true); - options.setIncludedTagExpressions(List.of("fast", "medium", "slow")); - options.setExcludedTagExpressions(List.of("slow")); - - var request = convert(); - var postDiscoveryFilters = request.getPostDiscoveryFilters(); - - assertThat(postDiscoveryFilters).hasSize(2); - assertThat(postDiscoveryFilters.get(0).toString()).contains("TagFilter"); - assertThat(postDiscoveryFilters.get(1).toString()).contains("TagFilter"); - } - - @Test - void convertsEngineOptions() { - options.setScanClasspath(true); - options.setIncludedEngines(List.of("engine1", "engine2", "engine3")); - options.setExcludedEngines(List.of("engine2")); - - var request = convert(); - var engineFilters = request.getEngineFilters(); - - assertThat(engineFilters).hasSize(2); - assertThat(engineFilters.get(0).toString()).contains("includes", "[engine1, engine2, engine3]"); - assertThat(engineFilters.get(1).toString()).contains("excludes", "[engine2]"); - } - - @Test - void propagatesUriSelectors() { - options.setSelectedUris(List.of(selectUri("a"), selectUri("b"))); - - var request = convert(); - var uriSelectors = request.getSelectorsByType(UriSelector.class); - - assertThat(uriSelectors).extracting(UriSelector::getUri).containsExactly(URI.create("a"), URI.create("b")); - } - - @Test - void propagatesFileSelectors() { - options.setSelectedFiles(List.of(selectFile("foo.txt"), selectFile("bar.csv"))); - - var request = convert(); - var fileSelectors = request.getSelectorsByType(FileSelector.class); - - assertThat(fileSelectors).extracting(FileSelector::getRawPath).containsExactly("foo.txt", "bar.csv"); - } - - @Test - void propagatesDirectorySelectors() { - options.setSelectedDirectories(List.of(selectDirectory("foo/bar"), selectDirectory("bar/qux"))); - - var request = convert(); - var directorySelectors = request.getSelectorsByType(DirectorySelector.class); - - assertThat(directorySelectors).extracting(DirectorySelector::getRawPath).containsExactly("foo/bar", "bar/qux"); - } - - @Test - void propagatesPackageSelectors() { - options.setSelectedPackages(List.of(selectPackage("com.acme.foo"), selectPackage("com.example.bar"))); - - var request = convert(); - var packageSelectors = request.getSelectorsByType(PackageSelector.class); - - assertThat(packageSelectors).extracting(PackageSelector::getPackageName).containsExactly("com.acme.foo", - "com.example.bar"); - } - - @Test - void propagatesClassSelectors() { - options.setSelectedClasses(List.of(selectClass("com.acme.Foo"), selectClass("com.example.Bar"))); - - var request = convert(); - var classSelectors = request.getSelectorsByType(ClassSelector.class); - - assertThat(classSelectors).extracting(ClassSelector::getClassName).containsExactly("com.acme.Foo", - "com.example.Bar"); - } - - @Test - void propagatesMethodSelectors() { - options.setSelectedMethods( - List.of(selectMethod("com.acme.Foo#m()"), selectMethod("com.example.Bar#method(java.lang.Object)"))); - - var request = convert(); - var methodSelectors = request.getSelectorsByType(MethodSelector.class); - - assertThat(methodSelectors).hasSize(2); - assertThat(methodSelectors.get(0).getClassName()).isEqualTo("com.acme.Foo"); - assertThat(methodSelectors.get(0).getMethodName()).isEqualTo("m"); - assertThat(methodSelectors.get(0).getParameterTypeNames()).isEmpty(); - assertThat(methodSelectors.get(1).getClassName()).isEqualTo("com.example.Bar"); - assertThat(methodSelectors.get(1).getMethodName()).isEqualTo("method"); - assertThat(methodSelectors.get(1).getParameterTypeNames()).isEqualTo("java.lang.Object"); - } - - @Test - void propagatesClasspathResourceSelectors() { - options.setSelectedClasspathResources( - List.of(selectClasspathResource("foo.csv"), selectClasspathResource("com/example/bar.json"))); - - var request = convert(); - var classpathResourceSelectors = request.getSelectorsByType(ClasspathResourceSelector.class); - - assertThat(classpathResourceSelectors).extracting( - ClasspathResourceSelector::getClasspathResourceName).containsExactly("foo.csv", "com/example/bar.json"); - } - - @Test - void propagatesIterationSelectors() { - var methodSelector = selectMethod("com.acme.Foo#m()"); - var classSelector = selectClass("com.example.Bar"); - options.setSelectedIterations(List.of(selectIteration(methodSelector, 1), selectIteration(classSelector, 2))); - - var request = convert(); - var iterationSelectors = request.getSelectorsByType(IterationSelector.class); - - assertThat(iterationSelectors).hasSize(2); - assertThat(iterationSelectors.get(0).getParentSelector()).isEqualTo(methodSelector); - assertThat(iterationSelectors.get(0).getIterationIndices()).containsExactly(1); - assertThat(iterationSelectors.get(1).getParentSelector()).isEqualTo(classSelector); - assertThat(iterationSelectors.get(1).getIterationIndices()).containsExactly(2); - } - - @Test - void propagatesSelectorIdentifiers() { - var methodSelector = selectMethod("com.acme.Foo#m()"); - var classSelector = selectClass("com.example.Bar"); - options.setSelectorIdentifiers( - List.of(methodSelector.toIdentifier().orElseThrow(), classSelector.toIdentifier().orElseThrow())); - - var request = convert(); - - assertThat(request.getSelectorsByType(MethodSelector.class)).containsExactly(methodSelector); - assertThat(request.getSelectorsByType(ClassSelector.class)).containsExactly(classSelector); - } - - @Test - @SuppressWarnings("deprecation") - void convertsConfigurationParameters() { - options.setScanClasspath(true); - options.setConfigurationParameters(mapOf(entry("foo", "bar"), entry("baz", "true"))); - - var request = convert(); - var configurationParameters = request.getConfigurationParameters(); - - assertThat(configurationParameters.size()).isEqualTo(2); - assertThat(configurationParameters.get("foo")).contains("bar"); - assertThat(configurationParameters.getBoolean("baz")).contains(true); - } - - @Test - @SuppressWarnings("deprecation") - void convertsConfigurationParametersResources() { - options.setScanClasspath(true); - options.setConfigurationParameters(mapOf(entry("foo", "bar"), entry("com.example.prop.first", "baz"))); - options.setConfigurationParametersResources(List.of("config-test.properties")); - - var request = convert(); - var configurationParameters = request.getConfigurationParameters(); - - assertThat(configurationParameters.size()).isEqualTo(2); - assertThat(configurationParameters.get("foo")).contains("bar"); - assertThat(configurationParameters.get("com.example.prop.first")).contains("baz"); - assertThat(configurationParameters.get("com.example.prop.second")).contains("second value"); - } - - private LauncherDiscoveryRequest convert() { - var creator = new DiscoveryRequestCreator(); - return creator.toDiscoveryRequest(options); - } - - private void assertIncludes(Filter filter, String included) { - assertThat(filter.apply(included).included()).isTrue(); - } - - private void assertExcludes(Filter filter, String excluded) { - assertThat(filter.apply(excluded).excluded()).isTrue(); - } - - @SafeVarargs - @SuppressWarnings("varargs") - private static Map mapOf(Entry... entries) { - return Stream.of(entries).collect(toMap(Entry::getKey, Entry::getValue)); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/FlatPrintingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/FlatPrintingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/FlatPrintingListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/FlatPrintingListenerTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.platform.console.tasks.FlatPrintingListener.INDENTATION; -import static org.junit.platform.engine.TestExecutionResult.failed; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.assertj.core.util.Maps; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.fakes.TestDescriptorStub; -import org.junit.platform.launcher.TestIdentifier; - -/** - * @since 1.0 - */ -class FlatPrintingListenerTests { - - private static final String EOL = System.lineSeparator(); - - @Test - void executionSkipped() { - var stringWriter = new StringWriter(); - listener(stringWriter).executionSkipped(newTestIdentifier(), "Test" + EOL + "disabled"); - var lines = lines(stringWriter); - - assertEquals(3, lines.length); - assertAll("lines in the output", // - () -> assertEquals("Skipped: demo-test ([engine:demo-engine])", lines[0]), // - () -> assertEquals(INDENTATION + "=> Reason: Test", lines[1]), // - () -> assertEquals(INDENTATION + "disabled", lines[2])); - } - - @Test - void reportingEntryPublished() { - var stringWriter = new StringWriter(); - listener(stringWriter).reportingEntryPublished(newTestIdentifier(), ReportEntry.from("foo", "bar")); - var lines = lines(stringWriter); - - assertEquals(2, lines.length); - assertAll("lines in the output", // - () -> assertEquals("Reported: demo-test ([engine:demo-engine])", lines[0]), // - () -> assertTrue(lines[1].startsWith(INDENTATION + "=> Reported values: ReportEntry [timestamp =")), // - () -> assertTrue(lines[1].endsWith(", foo = 'bar']"))); - } - - @Test - void executionFinishedWithFailure() { - var stringWriter = new StringWriter(); - listener(stringWriter).executionFinished(newTestIdentifier(), failed(new AssertionError("Boom!"))); - var lines = lines(stringWriter); - - assertAll("lines in the output", // - () -> assertEquals("Finished: demo-test ([engine:demo-engine])", lines[0]), // - () -> assertEquals(INDENTATION + "=> Exception: java.lang.AssertionError: Boom!", lines[1])); - } - - @Nested - class ColorPaletteTests { - - @Nested - class DefaultColorPaletteTests { - - @Test - void executionSkipped() { - var stringWriter = new StringWriter(); - new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.DEFAULT).executionSkipped( - newTestIdentifier(), "Test" + EOL + "disabled"); - var lines = lines(stringWriter); - - assertEquals(3, lines.length); - assertAll("lines in the output", // - () -> assertEquals("\u001B[35mSkipped: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // - () -> assertEquals("\u001B[35m" + INDENTATION + "=> Reason: Test", lines[1]), // - () -> assertEquals(INDENTATION + "disabled\u001B[0m", lines[2])); - } - - @Test - void reportingEntryPublished() { - var stringWriter = new StringWriter(); - new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.DEFAULT).reportingEntryPublished( - newTestIdentifier(), ReportEntry.from("foo", "bar")); - var lines = lines(stringWriter); - - assertEquals(2, lines.length); - assertAll("lines in the output", // - () -> assertEquals("\u001B[37mReported: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // - () -> assertTrue(lines[1].startsWith( - "\u001B[37m" + INDENTATION + "=> Reported values: ReportEntry [timestamp =")), // - () -> assertTrue(lines[1].endsWith(", foo = 'bar']\u001B[0m"))); - } - - @Test - void executionFinishedWithFailure() { - var stringWriter = new StringWriter(); - new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.DEFAULT).executionFinished( - newTestIdentifier(), failed(new AssertionError("Boom!"))); - var lines = lines(stringWriter); - - assertAll("lines in the output", // - () -> assertEquals("\u001B[31mFinished: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // - () -> assertEquals("\u001B[31m" + INDENTATION + "=> Exception: java.lang.AssertionError: Boom!", - lines[1]), - () -> assertTrue(lines[lines.length - 1].endsWith("\u001B[0m"))); - } - - } - - @Nested - class ColorPaletteOverrideTests { - - @Test - void overridingSkipped() { - var stringWriter = new StringWriter(); - ColorPalette colorPalette = new ColorPalette(Maps.newHashMap(Style.SKIPPED, "36;7")); - new FlatPrintingListener(new PrintWriter(stringWriter), colorPalette).executionSkipped( - newTestIdentifier(), "Test" + EOL + "disabled"); - var lines = lines(stringWriter); - - assertEquals(3, lines.length); - assertAll("lines in the output", // - () -> assertEquals("\u001B[36;7mSkipped: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // - () -> assertEquals("\u001B[36;7m" + INDENTATION + "=> Reason: Test", lines[1]), // - () -> assertEquals(INDENTATION + "disabled\u001B[0m", lines[2])); - } - - @Test - void overridingUnusedStyle() { - var stringWriter = new StringWriter(); - ColorPalette colorPalette = new ColorPalette(Maps.newHashMap(Style.FAILED, "36;7")); - new FlatPrintingListener(new PrintWriter(stringWriter), colorPalette).executionSkipped( - newTestIdentifier(), "Test" + EOL + "disabled"); - var lines = lines(stringWriter); - - assertEquals(3, lines.length); - assertAll("lines in the output", // - () -> assertEquals("\u001B[35mSkipped: demo-test ([engine:demo-engine])\u001B[0m", lines[0]), // - () -> assertEquals("\u001B[35m" + INDENTATION + "=> Reason: Test", lines[1]), // - () -> assertEquals(INDENTATION + "disabled\u001B[0m", lines[2])); - } - - } - - } - - private FlatPrintingListener listener(StringWriter stringWriter) { - return new FlatPrintingListener(new PrintWriter(stringWriter), ColorPalette.NONE); - } - - private static TestIdentifier newTestIdentifier() { - var testDescriptor = new TestDescriptorStub(UniqueId.forEngine("demo-engine"), "demo-test"); - return TestIdentifier.from(testDescriptor); - } - - private String[] lines(StringWriter stringWriter) { - return stringWriter.toString().split(EOL); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TestFeedPrintingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TestFeedPrintingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TestFeedPrintingListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TestFeedPrintingListenerTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.jupiter.api.Assertions.assertLinesMatch; -import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; -import static org.mockito.Mockito.mock; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Collections; -import java.util.stream.Stream; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.support.descriptor.EngineDescriptor; -import org.junit.platform.fakes.TestDescriptorStub; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.launcher.TestPlan; -import org.opentest4j.TestAbortedException; - -public class TestFeedPrintingListenerTests { - - TestPlan testPlan; - TestIdentifier testIdentifier; - - StringWriter stringWriter = new StringWriter(); - TestFeedPrintingListener listener = new TestFeedPrintingListener(new PrintWriter(stringWriter), ColorPalette.NONE); - - @BeforeEach - void prepareListener() { - var engineDescriptor = new EngineDescriptor(UniqueId.forEngine("demo-engine"), "Demo Engine"); - var testDescriptor = new TestDescriptorStub(engineDescriptor.getUniqueId().append("type", "test"), - "%c ool test"); - engineDescriptor.addChild(testDescriptor); - - testPlan = TestPlan.from(Collections.singleton(engineDescriptor), mock()); - testIdentifier = testPlan.getTestIdentifier(testDescriptor.getUniqueId()); - - listener.testPlanExecutionStarted(testPlan); - } - - @Test - public void testExecutionSkipped() { - listener.executionSkipped(testIdentifier, "Test disabled"); - assertLinesMatch( // - """ - Demo Engine > %c ool test :: SKIPPED - \tReason: Test disabled - """.lines(), // - actualLines() // - ); - } - - @Test - public void testExecutionFailed() { - listener.executionFinished(testIdentifier, TestExecutionResult.failed(new AssertionError("Boom!"))); - assertLinesMatch( // - """ - Demo Engine > %c ool test :: FAILED - \tjava.lang.AssertionError: Boom! - >>>> - """.lines(), // - actualLines() // - ); - } - - @Test - public void testExecutionAborted() { - listener.executionFinished(testIdentifier, TestExecutionResult.aborted(new TestAbortedException("Boom!"))); - assertLinesMatch( // - """ - Demo Engine > %c ool test :: ABORTED - \torg.opentest4j.TestAbortedException: Boom! - >>>> - """.lines(), // - actualLines() // - ); - } - - @Test - public void testExecutionSucceeded() { - listener.executionFinished(testIdentifier, TestExecutionResult.successful()); - assertLinesMatch(Stream.of("Demo Engine > %c ool test :: SUCCESSFUL"), actualLines()); - } - - @Test - public void testExecutionFailedOfContainer() { - var engineIdentifier = getOnlyElement(testPlan.getRoots()); - listener.executionFinished(engineIdentifier, TestExecutionResult.failed(new AssertionError("Boom!"))); - assertLinesMatch( // - """ - Demo Engine :: FAILED - \tjava.lang.AssertionError: Boom! - >>>> - """.lines(), // - actualLines() // - ); - } - - private Stream actualLines() { - return stringWriter.toString().lines(); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadPoolExecutor; - -import org.junit.jupiter.api.Test; -import org.junit.platform.engine.reporting.ReportEntry; - -class TreeNodeTests { - - private static final int NUM_THREADS = 2; - private static final int ITEMS_PER_THREAD = 1000; - - @Test - void caption() { - assertEquals("", TreeNode.createCaption("")); - assertEquals("[@@]", TreeNode.createCaption("[@@]")); - assertEquals("[@ @]", TreeNode.createCaption("[@ @]")); - assertEquals("[@ @]", TreeNode.createCaption("[@\u000B@]")); - assertEquals("[@ @]", TreeNode.createCaption("[@\t@]")); - assertEquals("[@ @]", TreeNode.createCaption("[@\t\n@]")); - assertEquals("[@ @]", TreeNode.createCaption("[@\t\n\r@]")); - assertEquals("[@ @]", TreeNode.createCaption("[@\t\n\r\f@]")); - assertEquals("@".repeat(80) + "...", TreeNode.createCaption("@".repeat(1000) + "!")); - } - - @Test - void childrenCanBeAddedConcurrently() throws Exception { - var treeNode = new TreeNode("root"); - - runConcurrently(() -> { - for (long i = 0; i < ITEMS_PER_THREAD; i++) { - treeNode.addChild(new TreeNode(String.valueOf(i))); - } - }); - - assertThat(treeNode.children).hasSize(NUM_THREADS * ITEMS_PER_THREAD); - } - - @Test - void reportEntriesCanBeAddedConcurrently() throws Exception { - var treeNode = new TreeNode("root"); - - runConcurrently(() -> { - for (long i = 0; i < ITEMS_PER_THREAD; i++) { - treeNode.addReportEntry(ReportEntry.from("index", String.valueOf(i))); - } - }); - - assertThat(treeNode.reports).hasSize(NUM_THREADS * ITEMS_PER_THREAD); - } - - @SuppressWarnings("resource") - private void runConcurrently(Runnable action) throws InterruptedException { - ExecutorService executor = new ThreadPoolExecutor(NUM_THREADS, NUM_THREADS, 10, SECONDS, - new ArrayBlockingQueue<>(NUM_THREADS)); - try { - var barrier = new CyclicBarrier(NUM_THREADS); - for (long i = 0; i < NUM_THREADS; i++) { - executor.submit(() -> { - await(barrier); - action.run(); - }); - } - } - finally { - executor.shutdown(); - var terminated = executor.awaitTermination(10, SECONDS); - assertTrue(terminated, "Executor was not terminated"); - } - } - - private void await(CyclicBarrier barrier) { - try { - barrier.await(); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreePrinterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreePrinterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreePrinterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/TreePrinterTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.jupiter.api.Assertions.assertIterableEquals; -import static org.junit.jupiter.api.Assertions.assertLinesMatch; -import static org.junit.platform.engine.TestExecutionResult.aborted; -import static org.junit.platform.engine.TestExecutionResult.failed; -import static org.junit.platform.engine.TestExecutionResult.successful; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.List; - -import org.junit.jupiter.api.Test; -import org.junit.platform.console.options.Theme; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.fakes.TestDescriptorStub; -import org.junit.platform.launcher.TestIdentifier; - -class TreePrinterTests { - - private final Charset charset = StandardCharsets.UTF_8; - private final ByteArrayOutputStream stream = new ByteArrayOutputStream(1000); - private final PrintWriter out = new PrintWriter(new OutputStreamWriter(stream, charset)); - - private List actual() { - out.flush(); - return List.of(stream.toString(charset).split("\\R")); - } - - @Test - void emptyTree() { - new TreePrinter(out, Theme.UNICODE, ColorPalette.NONE).print(new TreeNode("")); - assertIterableEquals(List.of("╷"), actual()); - } - - @Test - void emptyEngines() { - var root = new TreeNode(""); - root.addChild(new TreeNode(identifier("e-0", "engine zero"), "none")); - root.addChild(new TreeNode(identifier("e-1", "engine one")).setResult(successful())); - root.addChild(new TreeNode(identifier("e-2", "engine two")).setResult(failed(null))); - root.addChild(new TreeNode(identifier("e-3", "engine three")).setResult(aborted(null))); - new TreePrinter(out, Theme.UNICODE, ColorPalette.NONE).print(root); - assertIterableEquals( // - List.of( // - "╷", // - "├─ engine zero ↷ none", // - "├─ engine one ✔", // - "├─ engine two ✘", // - "└─ engine three ■"), // - actual()); - } - - @Test - // https://github.com/junit-team/junit5/issues/786 - void printNodeHandlesNullMessageThrowableGracefully() { - var result = TestExecutionResult.failed(new NullPointerException()); - var node = new TreeNode(identifier("NPE", "test()")).setResult(result); - new TreePrinter(out, Theme.ASCII, ColorPalette.NONE).print(node); - assertLinesMatch(List.of(".", "+-- test() [X] java.lang.NullPointerException"), actual()); - } - - @Test - // https://github.com/junit-team/junit5/issues/1531 - void reportsAreTabbedCorrectly() { - var root = new TreeNode(""); - var e1 = new TreeNode(identifier("e-1", "engine one")).setResult(successful()); - e1.addReportEntry(ReportEntry.from("key", "e-1")); - root.addChild(e1); - - var c1 = new TreeNode(identifier("c-1", "class one")).setResult(successful()); - c1.addReportEntry(ReportEntry.from("key", "c-1")); - e1.addChild(c1); - - var m1 = new TreeNode(identifier("m-1", "method one")).setResult(successful()); - m1.addReportEntry(ReportEntry.from("key", "m-1")); - c1.addChild(m1); - - var m2 = new TreeNode(identifier("m-2", "method two")).setResult(successful()); - m2.addReportEntry(ReportEntry.from("key", "m-2")); - c1.addChild(m2); - - new TreePrinter(out, Theme.UNICODE, ColorPalette.NONE).print(root); - assertLinesMatch(List.of( // - "╷", // - "└─ engine one ✔", // - " │ ....-..-..T..:...* key = `e-1`", // - " └─ class one ✔", // - " │ ....-..-..T..:...* key = `c-1`", // - " ├─ method one ✔", // - " │ ....-..-..T..:...* key = `m-1`", // - " └─ method two ✔", // - " ....-..-..T..:...* key = `m-2`" // - ), // - actual()); - } - - private static TestIdentifier identifier(String id, String displayName) { - var descriptor = new TestDescriptorStub(UniqueId.forEngine(id), displayName); - return TestIdentifier.from(descriptor); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/VerboseTreeListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/VerboseTreeListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/VerboseTreeListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/console/tasks/VerboseTreeListenerTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.console.tasks; - -import static org.junit.jupiter.api.Assertions.assertLinesMatch; -import static org.junit.platform.engine.TestExecutionResult.failed; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; - -import org.junit.jupiter.api.Test; -import org.junit.platform.console.options.Theme; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.reporting.ReportEntry; -import org.junit.platform.fakes.TestDescriptorStub; -import org.junit.platform.launcher.TestIdentifier; - -/** - * @since 1.3.2 - */ -class VerboseTreeListenerTests { - - private static final String EOL = System.lineSeparator(); - - @Test - void executionSkipped() { - var stringWriter = new StringWriter(); - listener(stringWriter).executionSkipped(newTestIdentifier(), "Test" + EOL + "disabled"); - var lines = lines(stringWriter); - - assertLinesMatch(List.of( // - "+-- %c ool test", // - " tags: []", // - " uniqueId: [engine:demo-engine]", // - " parent: []", // - " reason: Test", // - " disabled", // - " status: [S] SKIPPED"), List.of(lines)); - } - - @Test - void reportingEntryPublished() { - var stringWriter = new StringWriter(); - listener(stringWriter).reportingEntryPublished(newTestIdentifier(), ReportEntry.from("foo", "bar")); - var lines = lines(stringWriter); - - assertLinesMatch(List.of(" reports: ReportEntry \\[timestamp = .+, foo = 'bar'\\]"), List.of(lines)); - } - - @Test - void executionFinishedWithFailure() { - var stringWriter = new StringWriter(); - listener(stringWriter).executionFinished(newTestIdentifier(), failed(new AssertionError("Boom!"))); - var lines = lines(stringWriter); - - assertLinesMatch(List.of(" caught: java.lang.AssertionError: Boom!", // - ">> STACKTRACE >>", // - " duration: \\d+ ms", // - " status: [X] FAILED"), List.of(lines)); - } - - @Test - void failureMessageWithFormatSpecifier() { - var stringWriter = new StringWriter(); - listener(stringWriter).executionFinished(newTestIdentifier(), failed(new AssertionError("%crash"))); - var lines = lines(stringWriter); - - assertLinesMatch(List.of(" caught: java.lang.AssertionError: %crash", // - ">> STACKTRACE >>", // - " duration: \\d+ ms", // - " status: [X] FAILED"), List.of(lines)); - } - - private VerboseTreePrintingListener listener(StringWriter stringWriter) { - return new VerboseTreePrintingListener(new PrintWriter(stringWriter), ColorPalette.NONE, 16, Theme.ASCII); - } - - private static TestIdentifier newTestIdentifier() { - var testDescriptor = new TestDescriptorStub(UniqueId.forEngine("demo-engine"), "%c ool test"); - return TestIdentifier.from(testDescriptor); - } - - private String[] lines(StringWriter stringWriter) { - return stringWriter.toString().split(EOL); - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/CompositeTestDescriptorVisitorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/CompositeTestDescriptorVisitorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/CompositeTestDescriptorVisitorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/CompositeTestDescriptorVisitorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.engine.TestDescriptor.Visitor; +import org.mockito.InOrder; + +class CompositeTestDescriptorVisitorTests { + + @Test + void checksPreconditions() { + assertThrows(PreconditionViolationException.class, Visitor::composite); + assertThrows(PreconditionViolationException.class, () -> Visitor.composite((Visitor[]) null)); + assertThrows(PreconditionViolationException.class, () -> Visitor.composite((Visitor) null)); + } + + @Test + void optimizesForSingleVisitor() { + Visitor visitor = mock(); + + assertSame(visitor, Visitor.composite(visitor)); + } + + @Test + void callsAllVisitorsInOrder() { + Visitor visitor1 = mock("visitor1"); + Visitor visitor2 = mock("visitor2"); + TestDescriptor testDescriptor = mock(); + + var composite = Visitor.composite(visitor1, visitor2); + composite.visit(testDescriptor); + + InOrder inOrder = inOrder(visitor1, visitor2); + inOrder.verify(visitor1).visit(testDescriptor); + inOrder.verify(visitor2).visit(testDescriptor); + inOrder.verifyNoMoreInteractions(); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/DiscoveryIssueTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/DiscoveryIssueTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/DiscoveryIssueTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/DiscoveryIssueTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; +import static org.mockito.Mockito.mock; + +import java.util.Optional; +import java.util.function.UnaryOperator; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.support.descriptor.ClassSource; + +public class DiscoveryIssueTests { + + @Test + void create() { + var issue = DiscoveryIssue.create(Severity.ERROR, "message"); + + assertThat(issue.severity()).isEqualTo(Severity.ERROR); + assertThat(issue.message()).isEqualTo("message"); + assertThat(issue.source()).isEmpty(); + assertThat(issue.cause()).isEmpty(); + } + + @Test + void builder() { + var source = mock(TestSource.class); + var cause = new RuntimeException("boom"); + + var issue = DiscoveryIssue.builder(Severity.WARNING, "message") // + .source(source) // + .cause(cause) // + .build(); + + assertThat(issue.severity()).isEqualTo(Severity.WARNING); + assertThat(issue.message()).isEqualTo("message"); + assertThat(issue.source()).containsSame(source); + assertThat(issue.cause()).containsSame(cause); + } + + @Test + void equalsAndHashCode() { + assertEqualsAndHashCode( // + DiscoveryIssue.create(Severity.ERROR, "message"), // + DiscoveryIssue.builder(Severity.ERROR, "message").build(), // + DiscoveryIssue.create(Severity.WARNING, "message") // + ); + assertEqualsAndHashCode( // + DiscoveryIssue.create(Severity.ERROR, "message"), // + DiscoveryIssue.builder(Severity.ERROR, "message").build(), // + DiscoveryIssue.create(Severity.ERROR, "anotherMessage") // + ); + assertEqualsAndHashCode( // + DiscoveryIssue.builder(Severity.ERROR, "message") // + .source(ClassSource.from(DiscoveryIssue.class)).build(), // + DiscoveryIssue.builder(Severity.ERROR, "message") // + .source(Optional.of(ClassSource.from(DiscoveryIssue.class))).build(), // + DiscoveryIssue.builder(Severity.ERROR, "message") // + .source(ClassSource.from(DefaultDiscoveryIssue.class)).build() // + ); + var cause = new RuntimeException("boom"); + assertEqualsAndHashCode( // + DiscoveryIssue.builder(Severity.ERROR, "message").cause(cause).build(), // + DiscoveryIssue.builder(Severity.ERROR, "message").cause(Optional.of(cause)).build(), // + DiscoveryIssue.builder(Severity.ERROR, "message").cause(new RuntimeException("boom")).build() // + ); + } + + @Test + void stringRepresentationWithoutAttributes() { + var issue = DiscoveryIssue.create(Severity.WARNING, "message"); + + assertThat(issue.toString()) // + .isEqualTo("DiscoveryIssue [severity = WARNING, message = 'message']"); + } + + @Test + void stringRepresentationWithOptionalAttributes() { + var issue = DiscoveryIssue.builder(Severity.WARNING, "message") // + .source(ClassSource.from(DiscoveryIssue.class)) // + .cause(new RuntimeException("boom")) // + .build(); + + assertThat(issue.toString()) // + .isEqualTo( + "DiscoveryIssue [severity = WARNING, message = 'message', source = ClassSource [className = 'org.junit.platform.engine.DiscoveryIssue', filePosition = null], cause = java.lang.RuntimeException: boom]"); + } + + @Test + void withNewMessage() { + var issue = DiscoveryIssue.builder(Severity.WARNING, "message") // + .source(ClassSource.from(DiscoveryIssue.class)) // + .cause(new RuntimeException("boom")) // + .build(); + + var newIssue = issue.withMessage(__ -> "new message"); + + assertThat(newIssue.severity()).isEqualTo(Severity.WARNING); + assertThat(newIssue.message()).isEqualTo("new message"); + assertThat(newIssue.source()).containsSame(issue.source().orElseThrow()); + assertThat(newIssue.cause()).containsSame(issue.cause().orElseThrow()); + } + + @Test + void withSameMessage() { + var issue = DiscoveryIssue.builder(Severity.WARNING, "message") // + .source(ClassSource.from(DiscoveryIssue.class)) // + .cause(new RuntimeException("boom")) // + .build(); + + var newIssue = issue.withMessage(UnaryOperator.identity()); + + assertThat(newIssue).isSameAs(issue); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/FilterCompositionTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/FilterCompositionTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/FilterCompositionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/FilterCompositionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestTagTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestTagTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestTagTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/TestTagTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdFormatTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdFormatTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdFormatTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdFormatTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -121,7 +121,7 @@ @Test default void parseEngineUid() { var parsedId = getFormat().parse(getEngineUid()); - assertSegment(parsedId.getSegments().get(0), "engine", "junit-jupiter"); + assertSegment(parsedId.getSegments().getFirst(), "engine", "junit-jupiter"); assertEquals(getEngineUid(), getFormat().format(parsedId)); assertEquals(getEngineUid(), parsedId.toString()); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/UniqueIdTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -46,7 +46,7 @@ var uniqueId = UniqueId.forEngine(ENGINE_ID); assertEquals("[engine:junit-jupiter]", uniqueId.toString()); - assertSegment(uniqueId.getSegments().get(0), "engine", "junit-jupiter"); + assertSegment(uniqueId.getSegments().getFirst(), "engine", "junit-jupiter"); } @Test @@ -61,7 +61,7 @@ var uniqueIdWithEngine = UniqueId.forEngine(ENGINE_ID); assertThat(uniqueIdWithEngine.getEngineId()).contains("junit-jupiter"); - var uniqueIdWithoutEngine = UniqueId.root("root", "avalue"); + var uniqueIdWithoutEngine = UniqueId.root("root", "aValue"); assertEquals(Optional.empty(), uniqueIdWithoutEngine.getEngineId()); } @@ -70,7 +70,7 @@ var uniqueId = UniqueId.root("aType", "aValue"); assertEquals("[aType:aValue]", uniqueId.toString()); - assertSegment(uniqueId.getSegments().get(0), "aType", "aValue"); + assertSegment(uniqueId.getSegments().getFirst(), "aType", "aValue"); } @Test @@ -96,7 +96,7 @@ uniqueId.append("class", "org.junit.MyClass"); assertThat(uniqueId.getSegments()).hasSize(1); - assertSegment(uniqueId.getSegments().get(0), "engine", ENGINE_ID); + assertSegment(uniqueId.getSegments().getFirst(), "engine", ENGINE_ID); } @Test @@ -153,7 +153,7 @@ @Test void ensureDefaultUniqueIdFormatDecodingEncodesSegmentParts() { - var segment = UniqueId.parse("[%5B+%25+%5D):(%3A+%2B+%2F]").getSegments().get(0); + var segment = UniqueId.parse("[%5B+%25+%5D):(%3A+%2B+%2F]").getSegments().getFirst(); assertEquals("[ % ])", segment.getType()); assertEquals("(: + /", segment.getValue()); } @@ -163,7 +163,7 @@ for (char c = 0; c < Character.MAX_VALUE; c++) { var value = "foo " + c + " bar"; var uniqueId = UniqueId.parse(UniqueId.root("type", value).toString()); - var segment = uniqueId.getSegments().get(0); + var segment = uniqueId.getSegments().getFirst(); assertEquals(value, segment.getValue()); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassNameFilterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassNameFilterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassNameFilterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassNameFilterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClassSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,9 +12,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; import org.junit.platform.commons.PreconditionViolationException; /** @@ -23,7 +23,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class ClassSelectorTests extends AbstractEqualsAndHashCodeTests { +class ClassSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathResourceSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathResourceSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathResourceSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathResourceSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,8 +10,9 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; /** * Unit tests for {@link ClasspathResourceSelector}. @@ -19,7 +20,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class ClasspathResourceSelectorTests extends AbstractEqualsAndHashCodeTests { +class ClasspathResourceSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathRootSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathRootSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathRootSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ClasspathRootSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,11 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import java.net.URI; import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; /** * Unit tests for {@link ClasspathRootSelector}. @@ -21,7 +22,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class ClasspathRootSelectorTests extends AbstractEqualsAndHashCodeTests { +class ClasspathRootSelectorTests { @Test void equalsAndHashCode() throws Exception { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DirectorySelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DirectorySelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DirectorySelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DirectorySelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,8 +10,9 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; /** * Unit tests for {@link DirectorySelector}. @@ -19,7 +20,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class DirectorySelectorTests extends AbstractEqualsAndHashCodeTests { +class DirectorySelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,12 +14,14 @@ import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.InstanceOfAssertFactories.type; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForMethod; import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResource; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResourceByName; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathRoots; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectDirectory; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectFile; @@ -38,6 +40,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; @@ -53,6 +56,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.io.Resource; import org.junit.platform.commons.test.TestClassLoader; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.engine.DiscoverySelector; @@ -286,12 +290,25 @@ } @Test - void selectClasspathResources() { - assertViolatesPrecondition(() -> selectClasspathResource(null)); + void selectClasspathResourcesPreconditions() { + assertViolatesPrecondition(() -> selectClasspathResource((String) null)); assertViolatesPrecondition(() -> selectClasspathResource("")); + assertViolatesPrecondition(() -> selectClasspathResource("/")); assertViolatesPrecondition(() -> selectClasspathResource(" ")); + assertViolatesPrecondition(() -> selectClasspathResource("/ ")); assertViolatesPrecondition(() -> selectClasspathResource("\t")); + assertViolatesPrecondition(() -> selectClasspathResource("/\t")); + assertViolatesPrecondition(() -> selectClasspathResourceByName(null)); + assertViolatesPrecondition(() -> selectClasspathResourceByName(Collections.emptySet())); + assertViolatesPrecondition(() -> selectClasspathResourceByName(Collections.singleton(null))); + assertViolatesPrecondition(() -> selectClasspathResourceByName(Set.of(new StubResource(null)))); + assertViolatesPrecondition(() -> selectClasspathResourceByName(Set.of(new StubResource("")))); + assertViolatesPrecondition( + () -> selectClasspathResourceByName(Set.of(new StubResource("a"), new StubResource("b")))); + } + @Test + void selectIndividualClasspathResources() { // with unnecessary "/" prefix var selector = selectClasspathResource("/foo/bar/spec.xml"); assertEquals("foo/bar/spec.xml", selector.getClasspathResourceName()); @@ -302,6 +319,23 @@ } @Test + void getSelectedClasspathResources() { + var selector = selectClasspathResource("org/junit/platform/commons/example.resource"); + var classpathResources = selector.getResources(); + assertAll(() -> assertThat(classpathResources).hasSize(1), // + () -> assertThat(classpathResources) // + .extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource") // + ); + } + + @Test + void getMissingClasspathResources() { + var selector = selectClasspathResource("org/junit/platform/commons/no-such-example.resource"); + assertViolatesPrecondition(selector::getResources); + } + + @Test void selectClasspathResourcesWithFilePosition() { var filePosition = FilePosition.from(12, 34); assertViolatesPrecondition(() -> selectClasspathResource(null, filePosition)); @@ -359,6 +393,18 @@ .containsExactly("A/B/C/spec.json", Optional.of(filePosition)); } + private record StubResource(String name) implements Resource { + + @Override + public String getName() { + return name(); + } + + @Override + public URI getUri() { + return null; + } + } } @Nested diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FilePositionTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FilePositionTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FilePositionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FilePositionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import static org.junit.jupiter.params.provider.Arguments.arguments; import java.util.stream.Stream; @@ -22,7 +23,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.junit.platform.AbstractEqualsAndHashCodeTests; import org.junit.platform.commons.PreconditionViolationException; /** @@ -31,7 +31,7 @@ * @since 1.7 */ @DisplayName("FilePosition unit tests") -class FilePositionTests extends AbstractEqualsAndHashCodeTests { +class FilePositionTests { @Test @DisplayName("factory method preconditions") diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FileSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FileSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FileSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/FileSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,8 +10,9 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; /** * Unit tests for {@link FileSelector}. @@ -19,7 +20,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class FileSelectorTests extends AbstractEqualsAndHashCodeTests { +class FileSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/IterationSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/IterationSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/IterationSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/IterationSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,12 +19,12 @@ import java.util.Optional; import java.util.stream.IntStream; -import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.AnnotatedElementContext; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.aggregator.AggregateWith; import org.junit.jupiter.params.aggregator.ArgumentsAccessor; import org.junit.jupiter.params.aggregator.ArgumentsAggregationException; -import org.junit.jupiter.params.aggregator.ArgumentsAggregator; +import org.junit.jupiter.params.aggregator.SimpleArgumentsAggregator; import org.junit.jupiter.params.provider.CsvSource; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.DiscoverySelector; @@ -61,14 +61,14 @@ return parent; } - private static class VarargsAggregator implements ArgumentsAggregator { + private static class VarargsAggregator extends SimpleArgumentsAggregator { @Override - public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) - throws ArgumentsAggregationException { - Class parameterType = context.getParameter().getType(); - Preconditions.condition(parameterType.isArray(), () -> "must be an array type, but was " + parameterType); - Class componentType = parameterType.getComponentType(); - IntStream indices = IntStream.range(context.getIndex(), accessor.size()); + protected Object aggregateArguments(ArgumentsAccessor accessor, Class targetType, + AnnotatedElementContext context, int parameterIndex) throws ArgumentsAggregationException { + + Preconditions.condition(targetType.isArray(), () -> "must be an array type, but was " + targetType); + Class componentType = targetType.getComponentType(); + IntStream indices = IntStream.range(parameterIndex, accessor.size()); if (componentType == int.class) { return indices.map(accessor::getInteger).toArray(); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/MethodSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/MethodSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/MethodSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/MethodSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,13 +12,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import java.util.stream.Stream; import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.PreconditionViolationException; /** * Unit tests for {@link MethodSelector}. @@ -26,7 +26,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class MethodSelectorTests extends AbstractEqualsAndHashCodeTests { +class MethodSelectorTests { private static final String TEST_CASE_NAME = TestCase.class.getName(); @@ -55,8 +55,7 @@ assertThat(selector.getMethodName()).isEqualTo("method"); assertThat(selector.getParameterTypeNames()).isEqualTo("int, boolean"); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(selector::getJavaClass)// + assertPreconditionViolationFor(selector::getJavaClass)// .withMessage("Could not load class with name: org.example.BogusClass")// .withCauseInstanceOf(ClassNotFoundException.class); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ModuleSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ModuleSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ModuleSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/ModuleSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,8 +10,9 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; /** * Unit tests for {@link ModuleSelector}. @@ -19,7 +20,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class ModuleSelectorTests extends AbstractEqualsAndHashCodeTests { +class ModuleSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedClassSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedClassSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedClassSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedClassSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,11 +12,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.util.List; import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; import org.junit.platform.commons.PreconditionViolationException; /** @@ -25,7 +25,7 @@ * @since 1.6 * @see DiscoverySelectorsTests */ -class NestedClassSelectorTests extends AbstractEqualsAndHashCodeTests { +class NestedClassSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedMethodSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedMethodSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedMethodSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/NestedMethodSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,11 +12,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.util.List; import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; import org.junit.platform.commons.PreconditionViolationException; /** @@ -25,7 +25,7 @@ * @since 1.6 * @see DiscoverySelectorsTests */ -class NestedMethodSelectorTests extends AbstractEqualsAndHashCodeTests { +class NestedMethodSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageNameFilterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageNameFilterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageNameFilterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageNameFilterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/PackageSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,8 +10,9 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; /** * Unit tests for {@link PackageSelector}. @@ -19,7 +20,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class PackageSelectorTests extends AbstractEqualsAndHashCodeTests { +class PackageSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UniqueIdSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UniqueIdSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UniqueIdSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UniqueIdSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,8 +10,9 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; import org.junit.platform.engine.UniqueId; /** @@ -20,7 +21,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class UniqueIdSelectorTests extends AbstractEqualsAndHashCodeTests { +class UniqueIdSelectorTests { @Test void equalsAndHashCode() { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UriSelectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UriSelectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UriSelectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/discovery/UriSelectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,10 +10,11 @@ package org.junit.platform.engine.discovery; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + import java.net.URI; import org.junit.jupiter.api.Test; -import org.junit.platform.AbstractEqualsAndHashCodeTests; /** * Unit tests for {@link UriSelector}. @@ -21,7 +22,7 @@ * @since 1.3 * @see DiscoverySelectorsTests */ -class UriSelectorTests extends AbstractEqualsAndHashCodeTests { +class UriSelectorTests { @Test void equalsAndHashCode() throws Exception { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/config/PrefixedConfigurationParametersTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/config/PrefixedConfigurationParametersTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/config/PrefixedConfigurationParametersTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/config/PrefixedConfigurationParametersTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -32,7 +32,7 @@ * * @since 1.0 */ -class AbstractTestDescriptorTests { +class AbstractTestDescriptorTests implements TestDescriptorOrderChildrenTests { private EngineDescriptor engineDescriptor; private GroupDescriptor group1; @@ -58,6 +58,11 @@ group11.addChild(leaf111); } + @Override + public TestDescriptor createEmptyTestDescriptor() { + return new GroupDescriptor(UniqueId.root("group", "1")); + } + @Test void removeRootFromHierarchyFails() { var e = assertThrows(JUnitException.class, () -> engineDescriptor.removeFromHierarchy()); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/AbstractTestSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -25,7 +25,6 @@ import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; -import org.junit.platform.AbstractEqualsAndHashCodeTests; import org.junit.platform.engine.TestSource; /** @@ -34,7 +33,7 @@ * * @since 1.0 */ -abstract class AbstractTestSourceTests extends AbstractEqualsAndHashCodeTests { +abstract class AbstractTestSourceTests { abstract Stream createSerializableInstances() throws Exception; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClassSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClassSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClassSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClassSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.io.Serializable; import java.net.URI; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/ClasspathResourceSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import static org.junit.platform.engine.support.descriptor.ClasspathResourceSource.CLASSPATH_SCHEME; import java.net.URI; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/CompositeTestSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/CompositeTestSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/CompositeTestSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/CompositeTestSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.io.File; import java.util.ArrayList; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DefaultUriSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DefaultUriSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DefaultUriSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DefaultUriSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.net.URI; import java.util.stream.Stream; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoClassTestDescriptor.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoClassTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoClassTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoClassTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,14 +11,12 @@ package org.junit.platform.engine.support.descriptor; import static java.util.stream.Collectors.toCollection; -import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; import java.util.LinkedHashSet; import java.util.Set; import org.junit.jupiter.api.Tag; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; @@ -28,8 +26,6 @@ */ public class DemoClassTestDescriptor extends AbstractTestDescriptor { - private static final Logger logger = LoggerFactory.getLogger(DemoClassTestDescriptor.class); - private final Class testClass; public DemoClassTestDescriptor(UniqueId uniqueId, Class testClass) { @@ -40,27 +36,11 @@ @Override public Set getTags() { - // Copied from org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.getTags(AnnotatedElement) - // @formatter:off - return findRepeatableAnnotations(this.testClass, Tag.class).stream() - .map(Tag::value) - .filter(tag -> { - var isValid = TestTag.isValid(tag); - if (!isValid) { - // TODO [#242] Replace logging with precondition check once we have a proper mechanism for - // handling validation exceptions during the TestEngine discovery phase. - // - // As an alternative to a precondition check here, we could catch any - // PreconditionViolationException thrown by TestTag::create. - logger.warn(() -> String.format( - "Configuration error: invalid tag syntax in @Tag(\"%s\") declaration on [%s]. Tag will be ignored.", - tag, this.testClass)); - } - return isValid; - }) - .map(TestTag::create) + return findRepeatableAnnotations(this.testClass, Tag.class).stream() // + .map(Tag::value) // + .filter(TestTag::isValid) // + .map(TestTag::create) // .collect(toCollection(LinkedHashSet::new)); - // @formatter:on } @Override diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoMethodTestDescriptor.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoMethodTestDescriptor.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoMethodTestDescriptor.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/DemoMethodTestDescriptor.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,15 +11,13 @@ package org.junit.platform.engine.support.descriptor; import static java.util.stream.Collectors.toCollection; -import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; +import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; import java.lang.reflect.Method; import java.util.LinkedHashSet; import java.util.Set; import org.junit.jupiter.api.Tag; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.TestTag; @@ -30,57 +28,29 @@ */ public class DemoMethodTestDescriptor extends AbstractTestDescriptor { - private static final Logger logger = LoggerFactory.getLogger(DemoMethodTestDescriptor.class); - - private final Class testClass; private final Method testMethod; - public DemoMethodTestDescriptor(UniqueId uniqueId, Class testClass, Method testMethod) { + public DemoMethodTestDescriptor(UniqueId uniqueId, Method testMethod) { super(uniqueId, String.format("%s(%s)", Preconditions.notNull(testMethod, "Method must not be null").getName(), ClassUtils.nullSafeToString(Class::getSimpleName, testMethod.getParameterTypes())), MethodSource.from(testMethod)); - this.testClass = Preconditions.notNull(testClass, "Class must not be null"); this.testMethod = testMethod; } @Override public Set getTags() { - // Copied from org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.getTags(AnnotatedElement) - // @formatter:off - Set methodTags = findRepeatableAnnotations(this.testMethod, Tag.class).stream() - .map(Tag::value) - .filter(tag -> { - var isValid = TestTag.isValid(tag); - if (!isValid) { - // TODO [#242] Replace logging with precondition check once we have a proper mechanism for - // handling validation exceptions during the TestEngine discovery phase. - // - // As an alternative to a precondition check here, we could catch any - // PreconditionViolationException thrown by TestTag::create. - logger.warn(() -> String.format( - "Configuration error: invalid tag syntax in @Tag(\"%s\") declaration on [%s]. Tag will be ignored.", - tag, this.testMethod)); - } - return isValid; - }) - .map(TestTag::create) + Set methodTags = findRepeatableAnnotations(this.testMethod, Tag.class).stream() // + .map(Tag::value) // + .filter(TestTag::isValid) // + .map(TestTag::create) // .collect(toCollection(LinkedHashSet::new)); - // @formatter:on getParent().ifPresent(parentDescriptor -> methodTags.addAll(parentDescriptor.getTags())); return methodTags; } - public final Class getTestClass() { - return this.testClass; - } - - public final Method getTestMethod() { - return this.testMethod; - } - @Override public Type getType() { return Type.TEST; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FilePositionTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FilePositionTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FilePositionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FilePositionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import static org.junit.jupiter.params.provider.Arguments.arguments; import java.util.stream.Stream; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.io.File; import java.util.stream.Stream; @@ -75,6 +76,27 @@ } @Test + void fileReuseWithPosition() { + var file = new File("test.txt"); + var position = FilePosition.from(42, 23); + var source = FileSource.from(file); + var sourceWithPosition = source.withPosition(position); + + assertThat(source.getUri()).isEqualTo(file.getAbsoluteFile().toURI()); + assertThat(source.getFile()).isEqualTo(file.getAbsoluteFile()); + assertThat(source.getPosition()).isEmpty(); + + assertThat(source).isNotSameAs(sourceWithPosition); + assertThat(source.getFile()).isSameAs(sourceWithPosition.getFile()); + assertThat(sourceWithPosition.getPosition()).hasValue(position); + + assertThat(sourceWithPosition.withPosition(null).getPosition()).isEmpty(); + + assertThat(source.withPosition(null)).isSameAs(source); + assertThat(sourceWithPosition.withPosition(position)).isSameAs(sourceWithPosition); + } + + @Test void equalsAndHashCodeForFileSource() { var file1 = new File("foo.txt"); var file2 = new File("bar.txt"); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/MethodSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/MethodSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/MethodSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/MethodSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.io.Serializable; import java.lang.reflect.Method; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/PackageSourceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/PackageSourceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/PackageSourceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/PackageSourceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,11 +12,14 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; import java.io.Serializable; import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.PreconditionViolationException; /** @@ -46,9 +49,11 @@ assertThrows(PreconditionViolationException.class, () -> PackageSource.from((Package) null)); } - @Test - void packageSourceFromPackageName() { - var testPackage = getClass().getPackage().getName(); + @ParameterizedTest + @ValueSource(classes = PackageSourceTests.class) + @ValueSource(strings = "DefaultPackageTestCase") + void packageSourceFromPackageName(Class testClass) { + var testPackage = testClass.getPackage().getName(); var source = PackageSource.from(testPackage); assertThat(source.getPackageName()).isEqualTo(testPackage); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorOrderChildrenTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorOrderChildrenTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorOrderChildrenTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorOrderChildrenTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,150 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.descriptor; + +import static java.util.Collections.emptyList; +import static java.util.Comparator.comparing; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId; + +public interface TestDescriptorOrderChildrenTests { + + /** + * @return a test descriptor without any children. + */ + TestDescriptor createEmptyTestDescriptor(); + + default TestDescriptor createTestDescriptorWithChildren() { + var testDescriptor = createEmptyTestDescriptor(); + testDescriptor.addChild(new StubTestDescriptor(UniqueId.root("child", "0"))); + testDescriptor.addChild(new StubTestDescriptor(UniqueId.root("child", "1"))); + testDescriptor.addChild(new StubTestDescriptor(UniqueId.root("child", "2"))); + return testDescriptor; + } + + @Test + default void orderChildrenInReverseOrder() { + var testDescriptor = createTestDescriptorWithChildren(); + var childrenInOriginalOrder = new ArrayList<>(testDescriptor.getChildren()); + testDescriptor.orderChildren(children -> { + children.sort(comparing((TestDescriptor o) -> childrenInOriginalOrder.indexOf(o)).reversed()); + return children; + }); + List children = new ArrayList<>(testDescriptor.getChildren()); + assertThat(children).isEqualTo(childrenInOriginalOrder.reversed()); + } + + @Test + default void orderChildrenEmptyList() { + var testDescriptor = createTestDescriptorWithChildren(); + var exception = assertThrows(PreconditionViolationException.class, + () -> testDescriptor.orderChildren(children -> emptyList())); + assertThat(exception).hasMessage("orderer may not add or remove test descriptors"); + } + + @Test + default void orderChildrenInSameOrder() { + var testDescriptor = createTestDescriptorWithChildren(); + var childrenInOriginalOrder = new ArrayList<>(testDescriptor.getChildren()); + testDescriptor.orderChildren(children -> { + children.sort(comparing(childrenInOriginalOrder::indexOf)); + return children; + }); + List children = new ArrayList<>(testDescriptor.getChildren()); + assertThat(children).isEqualTo(childrenInOriginalOrder); + } + + @Test + default void orderChildrenRemovesDescriptor() { + var testDescriptor = createTestDescriptorWithChildren(); + UnaryOperator> orderer = children -> { + children.remove(1); + return children; + }; + var exception = assertThrows(PreconditionViolationException.class, () -> testDescriptor.orderChildren(orderer)); + assertThat(exception).hasMessage("orderer may not add or remove test descriptors"); + } + + @Test + default void orderChildrenAddsDescriptor() { + var testDescriptor = createTestDescriptorWithChildren(); + UnaryOperator> orderer = children -> { + children.add(1, new StubTestDescriptor(UniqueId.root("extra", "extra1"))); + return children; + }; + var exception = assertThrows(PreconditionViolationException.class, () -> testDescriptor.orderChildren(orderer)); + assertThat(exception).hasMessage("orderer may not add or remove test descriptors"); + } + + @Test + default void orderChildrenReplacesDescriptor() { + var testDescriptor = createTestDescriptorWithChildren(); + UnaryOperator> orderer = children -> { + children.set(1, new StubTestDescriptor(UniqueId.root("replaced", "replaced1"))); + return children; + }; + var exception = assertThrows(PreconditionViolationException.class, () -> testDescriptor.orderChildren(orderer)); + assertThat(exception).hasMessage("orderer may not add or remove test descriptors"); + } + + @Test + default void orderChildrenDuplicatesDescriptor() { + var testDescriptor = createTestDescriptorWithChildren(); + UnaryOperator> orderer = children -> { + children.add(1, children.getLast()); + return children; + }; + var exception = assertThrows(PreconditionViolationException.class, () -> testDescriptor.orderChildren(orderer)); + assertThat(exception).hasMessage("orderer may not add or remove test descriptors"); + } + + @Test + default void orderChildrenOrdererReturnsNull() { + var testDescriptor = createTestDescriptorWithChildren(); + var exception = assertThrows(PreconditionViolationException.class, + () -> testDescriptor.orderChildren(children -> null)); + assertThat(exception).hasMessage("orderer may not return null"); + } + + @Test + default void orderChildrenProvidedChildrenAreModifiable() { + var testDescriptor = createTestDescriptorWithChildren(); + AtomicReference> childrenRef = new AtomicReference<>(); + testDescriptor.orderChildren(children -> { + childrenRef.set(children); + return children; + }); + assertThat(childrenRef.get()).isInstanceOf(ArrayList.class); + } +} + +class StubTestDescriptor extends AbstractTestDescriptor { + + StubTestDescriptor(UniqueId uniqueId) { + super(uniqueId, "stub: " + uniqueId); + } + + @Override + public Type getType() { + return Type.TEST; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/TestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.descriptor; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Optional; +import java.util.Set; + +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.TestTag; +import org.junit.platform.engine.UniqueId; + +class TestDescriptorTests implements TestDescriptorOrderChildrenTests { + + @Override + public TestDescriptor createEmptyTestDescriptor() { + return new MinimalTestDescriptorImplementation(); + } + + private static class MinimalTestDescriptorImplementation implements TestDescriptor { + + private final Set children = Collections.synchronizedSet(new LinkedHashSet<>()); + + @Override + public UniqueId getUniqueId() { + return UniqueId.root("root", "value"); + } + + @Override + public String getDisplayName() { + return "TestDescriptorImplementation"; + } + + @Override + public Set getTags() { + return Set.of(); + } + + @Override + public Optional getSource() { + return Optional.empty(); + } + + @Override + public Optional getParent() { + return Optional.empty(); + } + + @Override + public void setParent(TestDescriptor parent) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public Set getChildren() { + return Collections.unmodifiableSet(children); + } + + @Override + public void addChild(TestDescriptor descriptor) { + children.add(descriptor); + } + + @Override + public void removeChild(TestDescriptor descriptor) { + children.remove(descriptor); + } + + @Override + public void removeFromHierarchy() { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public Type getType() { + return Type.CONTAINER; + } + + @Override + public Optional findByUniqueId(UniqueId uniqueId) { + throw new UnsupportedOperationException("Not implemented"); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolverTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolverTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolverTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolverTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import static org.junit.platform.engine.DiscoveryIssue.Severity.INFO; +import static org.junit.platform.engine.DiscoveryIssue.Severity.WARNING; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; +import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.discovery.ClassSelector; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.descriptor.EngineDescriptor; +import org.junit.platform.launcher.LauncherDiscoveryListener; + +public class EngineDiscoveryRequestResolverTests { + + @Test + void allowsSelectorResolversToReportDiscoveryIssues() { + var resolver = EngineDiscoveryRequestResolver.builder() // + .addSelectorResolver(ctx -> new SelectorResolver() { + @Override + public Resolution resolve(ClassSelector selector, Context context) { + ctx.getIssueReporter() // + .reportIssue(DiscoveryIssue.builder(INFO, "test") // + .source(ClassSource.from(selector.getClassName()))); + return unresolved(); + } + }) // + .build(); + + var engineId = UniqueId.forEngine("engine"); + var engineDescriptor = new EngineDescriptor(engineId, "Engine"); + var listener = mock(LauncherDiscoveryListener.class); + var request = request() // + .selectors(selectClass(EngineDiscoveryRequestResolverTests.class)) // + .listeners(listener) // + .build(); + + resolver.resolve(request, engineDescriptor); + + var issue = DiscoveryIssue.builder(INFO, "test") // + .source(ClassSource.from(EngineDiscoveryRequestResolverTests.class)) // + .build(); + verify(listener).issueEncountered(engineId, issue); + } + + @Test + void allowsVisitorsToReportDiscoveryIssues() { + var resolver = EngineDiscoveryRequestResolver.builder() // + .addTestDescriptorVisitor(ctx -> // + descriptor -> ctx.getIssueReporter() // + .reportIssue(DiscoveryIssue.create(WARNING, descriptor.getDisplayName()))) // + .build(); + + var engineId = UniqueId.forEngine("engine"); + var engineDescriptor = new EngineDescriptor(engineId, "Engine"); + var listener = mock(LauncherDiscoveryListener.class); + var request = request() // + .selectors(selectClass(EngineDiscoveryRequestResolverTests.class)) // + .listeners(listener) // + .build(); + + resolver.resolve(request, engineDescriptor); + + verify(listener).issueEncountered(engineId, DiscoveryIssue.create(WARNING, "Engine")); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathRoots; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; +import static org.junit.platform.engine.discovery.PackageNameFilter.includePackageNames; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Match.exact; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.match; + +import java.net.URI; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.io.ResourceFilter; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; +import org.junit.platform.engine.support.descriptor.EngineDescriptor; +import org.junit.platform.fakes.TestDescriptorStub; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; + +class ResourceContainerSelectorResolverTest { + + final TestDescriptor engineDescriptor = new EngineDescriptor(UniqueId.forEngine("resource-engine"), + "Resource Engine"); + final ResourceFilter resourceFilter = ResourceFilter.of(resource -> resource.getName().endsWith(".resource")); + + final EngineDiscoveryRequestResolver resolver = EngineDiscoveryRequestResolver.builder() // + .addResourceContainerSelectorResolver(resourceFilter) // + .addSelectorResolver(new ResourceSelectorResolver()) // + .build(); + + @Test + void shouldDiscoverAllResourcesInPackage() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectPackage("org.junit.platform.commons")) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + } + + @Test + void shouldDiscoverAllResourcesInRootPackage() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectPackage("")) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "default-package.resource", + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + } + + @Test + void shouldFilterPackages() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectPackage("")) // + .filters(includePackageNames("org.junit.platform")) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + } + + @Test + void shouldDiscoverAllResourcesInClasspathRoot() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectClasspathRoots(getTestClasspathResourceRoot())) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "default-package.resource", + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + } + + private Set getTestClasspathResourceRoot() { + // Gradle puts classes and resources in different roots. + var defaultPackageResource = "/default-package.resource"; + var resourceUri = getClass().getResource(defaultPackageResource).toString(); + var uri = URI.create(resourceUri.substring(0, resourceUri.length() - defaultPackageResource.length())); + return Collections.singleton(Path.of(uri)); + } + + private static class ResourceSelectorResolver implements SelectorResolver { + @Override + public Resolution resolve(ClasspathResourceSelector selector, Context context) { + return context.addToParent(parent -> createTestDescriptor(parent, selector.getClasspathResourceName())) // + .map(testDescriptor -> match(exact(testDescriptor))) // + .orElseGet(Resolution::unresolved); + } + + private static Optional createTestDescriptor(TestDescriptor parent, + String classpathResourceName) { + var uniqueId = parent.getUniqueId().append("resource", classpathResourceName); + var descriptor = new TestDescriptorStub(uniqueId, classpathResourceName); + return Optional.of(descriptor); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/CompositeLockTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/CompositeLockTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/CompositeLockTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/CompositeLockTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinDeadLockTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinDeadLockTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinDeadLockTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinDeadLockTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -36,7 +36,7 @@ import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.testkit.engine.EngineTestKit; -// https://github.com/junit-team/junit5/issues/3945 +// https://github.com/junit-team/junit-framework/issues/3945 @Timeout(10) public class ForkJoinDeadLockTests { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorServiceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorServiceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorServiceTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorServiceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/HierarchicalTestExecutorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -18,6 +18,8 @@ import static org.junit.platform.engine.TestExecutionResult.Status.FAILED; import static org.junit.platform.engine.TestExecutionResult.Status.SUCCESSFUL; import static org.junit.platform.engine.TestExecutionResult.successful; +import static org.junit.platform.launcher.core.NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStore; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; @@ -37,6 +39,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.function.ThrowingConsumer; +import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.ExecutionRequest; import org.junit.platform.engine.TestDescriptor; @@ -77,7 +80,8 @@ private HierarchicalTestExecutor createExecutor( HierarchicalTestExecutorService executorService) { - var request = new ExecutionRequest(root, listener, null); + var request = ExecutionRequest.create(root, listener, mock(ConfigurationParameters.class), + dummyOutputDirectoryCreator(), dummyNamespacedHierarchicalStore()); return new HierarchicalTestExecutor<>(request, rootContext, executorService, OpenTest4JAwareThrowableCollector::new); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/LockManagerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/LockManagerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/LockManagerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/LockManagerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/MemoryLeakTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/MemoryLeakTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/MemoryLeakTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/MemoryLeakTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,7 +19,7 @@ * exist with regard to the "context" held by {@link NodeTestTask}. * * @since 5.3.1 - * @see GitHub issue #1578 + * @see GitHub issue #1578 */ // Explicitly specifying Lifecycle.PER_METHOD to be certain that the // test instance state is recreated for every test method executed. diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalkerIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalkerIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalkerIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/NodeTreeWalkerIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -192,6 +192,7 @@ return new JupiterTestEngine().discover(discoveryRequest, UniqueId.forEngine("junit-jupiter")); } + @SuppressWarnings("JUnitMalformedDeclaration") @ResourceLock("a") static class TestCaseWithResourceLock { @Test @@ -200,6 +201,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCaseWithoutResourceLock { @Test @ResourceLock("a") @@ -227,6 +229,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ResourceLock("a") static class TestCaseWithResourceWriteLockOnClass { @Test @@ -234,6 +237,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ResourceLock(value = "a", mode = ResourceAccessMode.READ) static class TestCaseWithResourceReadLockOnClass { @Test @@ -241,6 +245,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ResourceLock(value = "a", mode = ResourceAccessMode.READ) static class TestCaseWithResourceReadLockOnClassAndWriteClockOnTestCase { @Test @@ -249,6 +254,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ResourceLock(value = "a", mode = ResourceAccessMode.READ) static class TestCaseWithResourceReadLockOnClassAndReadClockOnTestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,6 @@ package org.junit.platform.engine.support.hierarchical; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -177,7 +176,7 @@ /** * @since 1.4 - * @see gh-1688 + * @see gh-1688 */ @Test void threadInterruptedByUserCode() { @@ -522,7 +521,7 @@ private List getEventsOfChildren(EngineExecutionResults results, TestDescriptor container) { return results.testEvents().filter( - event -> event.getTestDescriptor().getParent().orElseThrow().equals(container)).collect(toList()); + event -> event.getTestDescriptor().getParent().orElseThrow().equals(container)).toList(); } private TestDescriptor findFirstTestDescriptor(EngineExecutionResults results, Condition condition) { @@ -534,7 +533,7 @@ return events.stream() .filter(condition::matches) .map(Event::getTimestamp) - .collect(toList()); + .toList(); // @formatter:on } @@ -958,7 +957,7 @@ throws InterruptedException { var value = sharedResource.incrementAndGet(); countDownLatch.countDown(); - countDownLatch.await(estimateSimulatedTestDurationInMiliseconds(), MILLISECONDS); + countDownLatch.await(estimateSimulatedTestDurationInMilliseconds(), MILLISECONDS); return value; } @@ -967,7 +966,7 @@ throws InterruptedException { var value = sharedResource.get(); countDownLatch.countDown(); - countDownLatch.await(estimateSimulatedTestDurationInMiliseconds(), MILLISECONDS); + countDownLatch.await(estimateSimulatedTestDurationInMilliseconds(), MILLISECONDS); assertEquals(value, sharedResource.get()); } @@ -981,7 +980,7 @@ * * Currently, CI is known to be slow. */ - private static long estimateSimulatedTestDurationInMiliseconds() { + private static long estimateSimulatedTestDurationInMilliseconds() { var runningInCi = Boolean.parseBoolean(System.getenv("CI")); return runningInCi ? 1000 : 100; } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockSupport.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockSupport.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockSupport.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockSupport.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ResourceLockTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -29,7 +29,7 @@ class SameThreadExecutionIntegrationTests { /** - * @see gh-1688 + * @see gh-1688 */ @Test void threadInterruptedByUserCode(@TrackLogRecords LogRecordListener listener) { @@ -53,6 +53,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") @TestMethodOrder(MethodName.class) static class InterruptedThreadTestCase { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleLockTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleLockTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleLockTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleLockTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SingleTestExecutorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ThrowableCollectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ThrowableCollectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ThrowableCollectorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ThrowableCollectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespaceTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespaceTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespaceTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespaceTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.store; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.EqualsAndHashCodeAssertions.assertEqualsAndHashCode; + +import org.junit.jupiter.api.Test; + +public class NamespaceTests { + + @Test + void namespacesEqualForSamePartsSequence() { + Namespace ns1 = Namespace.create("part1", "part2"); + Namespace ns2 = Namespace.create("part1", "part2"); + Namespace ns3 = Namespace.create("part2", "part1"); + + assertEqualsAndHashCode(ns1, ns2, ns3); + } + + @Test + void orderOfNamespacePartsDoesMatter() { + Namespace ns1 = Namespace.create("part1", "part2"); + Namespace ns2 = Namespace.create("part2", "part1"); + + assertNotEquals(ns1, ns2); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -520,7 +520,7 @@ } /** - * @see #3944 + * @see #3944 */ @Test void acceptsQueryAfterClose() { @@ -569,5 +569,4 @@ } }; } - } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingDiscoveryListenerIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingDiscoveryListenerIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingDiscoveryListenerIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingDiscoveryListenerIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,6 +10,7 @@ package org.junit.platform.jfr; +import static org.junit.platform.commons.util.ExceptionUtils.readStackTrace; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.moditect.jfrunit.ExpectedEvent.event; @@ -17,8 +18,14 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.DisabledOnOpenJ9; -import org.junit.jupiter.engine.JupiterTestEngine; -import org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.EngineDiscoveryRequest; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.fakes.TestEngineStub; +import org.junit.platform.testkit.engine.EngineTestKit; import org.moditect.jfrunit.EnableEvent; import org.moditect.jfrunit.JfrEventTest; import org.moditect.jfrunit.JfrEvents; @@ -32,22 +39,40 @@ @Test @EnableEvent("org.junit.*") void reportsEvents() { - var launcher = LauncherFactoryForTestingPurposesOnly.createLauncher(new JupiterTestEngine()); - var request = request() // + var source = ClassSource.from(FlightRecordingDiscoveryListenerIntegrationTests.class); + var cause = new RuntimeException("boom"); + var issue = DiscoveryIssue.builder(Severity.WARNING, "some message") // + .source(source) // + .cause(cause) // + .build(); + + var testEngine = new TestEngineStub() { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + discoveryRequest.getDiscoveryListener().issueEncountered(uniqueId, issue); + return super.discover(discoveryRequest, uniqueId); + } + }; + + EngineTestKit.discover(testEngine, request() // .selectors(selectClass(FlightRecordingDiscoveryListenerIntegrationTests.class)) // .listeners(new FlightRecordingDiscoveryListener()) // - .build(); + .enableImplicitConfigurationParameters(false) // + .build()); - launcher.discover(request); jfrEvents.awaitEvents(); assertThat(jfrEvents) // .contains(event("org.junit.LauncherDiscovery") // - // TODO JfrUnit does not yey support checking int values - // .with("selectors", 1) // - // .with("filters", 0) // - ) // + .with("selectors", 1) // + .with("filters", 0)) // .contains(event("org.junit.EngineDiscovery") // - .with("uniqueId", "[engine:junit-jupiter]")); + .with("uniqueId", "[engine:TestEngineStub]")) // + .contains(event("org.junit.DiscoveryIssue") // + .with("engineId", "[engine:TestEngineStub]") // + .with("severity", "WARNING") // + .with("message", "some message") // + .with("source", source.toString()) // + .with("cause", readStackTrace(cause))); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingExecutionListenerIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingExecutionListenerIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingExecutionListenerIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/jfr/FlightRecordingExecutionListenerIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,13 +12,20 @@ import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.hierarchicalOutputDirectoryCreator; +import static org.junit.platform.reporting.testutil.FileUtils.findPath; import static org.moditect.jfrunit.ExpectedEvent.event; import static org.moditect.jfrunit.JfrEventsAssert.assertThat; +import java.nio.file.Files; +import java.nio.file.Path; + import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.MediaType; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestReporter; import org.junit.jupiter.api.extension.DisabledOnOpenJ9; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.engine.JupiterTestEngine; import org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly; import org.moditect.jfrunit.EnableEvent; @@ -33,15 +40,18 @@ @Test @EnableEvent("org.junit.*") - void reportsEvents() { + void reportsEvents(@TempDir Path tempDir) { var launcher = LauncherFactoryForTestingPurposesOnly.createLauncher(new JupiterTestEngine()); var request = request() // .selectors(selectClass(TestCase.class)) // + .outputDirectoryCreator(hierarchicalOutputDirectoryCreator(tempDir)) // .build(); launcher.execute(request, new FlightRecordingExecutionListener()); jfrEvents.awaitEvents(); + var testFile = findPath(tempDir, "glob:**/test.txt"); + assertThat(jfrEvents) // .contains(event("org.junit.TestPlanExecution") // .with("engineNames", "JUnit Jupiter")) // @@ -59,16 +69,20 @@ .contains(event("org.junit.ReportEntry") // .with("key", "message") // .with("value", "Hello JFR!")) // + .contains(event("org.junit.FileEntry") // + .with("path", testFile.toAbsolutePath().toString())) // .contains(event("org.junit.SkippedTest") // .with("displayName", "skipped()") // .with("type", "TEST") // .with("reason", "for demonstration purposes")); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase { @Test void test(TestReporter reporter) { reporter.publishEntry("message", "Hello JFR!"); + reporter.publishFile("test.txt", MediaType.TEXT_PLAIN_UTF_8, file -> Files.writeString(file, "test")); } @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/DiscoveryFilterStub.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/DiscoveryFilterStub.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/DiscoveryFilterStub.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/DiscoveryFilterStub.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/FilterStub.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/FilterStub.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/FilterStub.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/FilterStub.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptedTestEngine.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptedTestEngine.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptedTestEngine.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptedTestEngine.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptorInjectedLauncherSessionListener.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptorInjectedLauncherSessionListener.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptorInjectedLauncherSessionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/InterceptorInjectedLauncherSessionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/MethodFilterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/MethodFilterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/MethodFilterTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/MethodFilterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,174 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.launcher.MethodFilter.excludeMethodNamePatterns; +import static org.junit.platform.launcher.MethodFilter.includeMethodNamePatterns; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.engine.FilterResult; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.DemoMethodTestDescriptor; + +/** + * Unit tests for {@link MethodFilter}. + * + * @since 1.12 + */ +class MethodFilterTests { + private static final String CLASS1_TEST1_NAME = "org.junit.platform.launcher.MethodFilterTests$Class1#test1"; + private static final String CLASS1_TEST2_NAME = "org.junit.platform.launcher.MethodFilterTests$Class1#test2"; + private static final String CLASS2_TEST1_NAME = "org.junit.platform.launcher.MethodFilterTests$Class2#test1"; + private static final String CLASS2_TEST2_NAME = "org.junit.platform.launcher.MethodFilterTests$Class2#test2"; + private static final TestDescriptor CLASS1_TEST1 = methodTestDescriptor("class1", Class1.class, "test1"); + private static final TestDescriptor CLASS1_TEST2 = methodTestDescriptor("class1", Class1.class, "test2"); + private static final TestDescriptor CLASS2_TEST1 = methodTestDescriptor("class2", Class2.class, "test1"); + private static final TestDescriptor CLASS2_TEST2 = methodTestDescriptor("class2", Class2.class, "test2"); + + @Test + void includeMethodNamePatternsChecksPreconditions() { + assertThatThrownBy(() -> includeMethodNamePatterns((String[]) null)) // + .isInstanceOf(PreconditionViolationException.class) // + .hasMessage("patterns array must not be null or empty"); + assertThatThrownBy(() -> includeMethodNamePatterns(new String[0])) // + .isInstanceOf(PreconditionViolationException.class) // + .hasMessage("patterns array must not be null or empty"); + assertThatThrownBy(() -> includeMethodNamePatterns(new String[] { null })) // + .isInstanceOf(PreconditionViolationException.class) // + .hasMessage("patterns array must not contain null elements"); + } + + @Test + void includeSingleMethodNamePattern() { + var regex = "^org\\.junit\\.platform\\.launcher\\.MethodFilterTests\\$Class1#test.*"; + var filter = includeMethodNamePatterns(regex); + + assertIncluded(filter.apply(CLASS1_TEST1), + String.format("Method name [%s] matches included pattern: '%s'", CLASS1_TEST1_NAME, regex)); + assertIncluded(filter.apply(CLASS1_TEST2), + String.format("Method name [%s] matches included pattern: '%s'", CLASS1_TEST2_NAME, regex)); + + assertExcluded(filter.apply(CLASS2_TEST1), + String.format("Method name [%s] does not match any included pattern: '%s'", CLASS2_TEST1_NAME, regex)); + assertExcluded(filter.apply(CLASS2_TEST2), + String.format("Method name [%s] does not match any included pattern: '%s'", CLASS2_TEST2_NAME, regex)); + } + + @Test + void includeMultipleMethodNamePatterns() { + var firstRegex = "^org\\.junit\\.platform\\.launcher\\.MethodFilterTests\\$Class1#test.*"; + var secondRegex = ".+Class.+#test1"; + var filter = includeMethodNamePatterns(firstRegex, secondRegex); + + assertIncluded(filter.apply(CLASS1_TEST1), + String.format("Method name [%s] matches included pattern: '%s'", CLASS1_TEST1_NAME, firstRegex)); + assertIncluded(filter.apply(CLASS1_TEST2), + String.format("Method name [%s] matches included pattern: '%s'", CLASS1_TEST2_NAME, firstRegex)); + assertIncluded(filter.apply(CLASS2_TEST1), + String.format("Method name [%s] matches included pattern: '%s'", CLASS2_TEST1_NAME, secondRegex)); + + assertExcluded(filter.apply(CLASS2_TEST2), + String.format("Method name [%s] does not match any included pattern: '%s' OR '%s'", CLASS2_TEST2_NAME, + firstRegex, secondRegex)); + } + + @Test + void excludeMethodNamePatternsChecksPreconditions() { + assertThatThrownBy(() -> excludeMethodNamePatterns((String[]) null)) // + .isInstanceOf(PreconditionViolationException.class) // + .hasMessage("patterns array must not be null or empty"); + assertThatThrownBy(() -> excludeMethodNamePatterns(new String[0])) // + .isInstanceOf(PreconditionViolationException.class) // + .hasMessage("patterns array must not be null or empty"); + assertThatThrownBy(() -> excludeMethodNamePatterns(new String[] { null })) // + .isInstanceOf(PreconditionViolationException.class) // + .hasMessage("patterns array must not contain null elements"); + } + + @Test + void excludeSingleMethodNamePattern() { + var regex = "^org\\.junit\\.platform\\.launcher\\.MethodFilterTests\\$Class1#test.*"; + var filter = excludeMethodNamePatterns(regex); + + assertExcluded(filter.apply(CLASS1_TEST1), + String.format("Method name [%s] matches excluded pattern: '%s'", CLASS1_TEST1_NAME, regex)); + assertExcluded(filter.apply(CLASS1_TEST2), + String.format("Method name [%s] matches excluded pattern: '%s'", CLASS1_TEST2_NAME, regex)); + + assertIncluded(filter.apply(CLASS2_TEST1), + String.format("Method name [%s] does not match any excluded pattern: '%s'", CLASS2_TEST1_NAME, regex)); + assertIncluded(filter.apply(CLASS2_TEST2), + String.format("Method name [%s] does not match any excluded pattern: '%s'", CLASS2_TEST2_NAME, regex)); + } + + @Test + void excludeMultipleMethodNamePatterns() { + var firstRegex = "^org\\.junit\\.platform\\.launcher\\.MethodFilterTests\\$Class1#test.*"; + var secondRegex = ".+Class.+#test1"; + var filter = excludeMethodNamePatterns(firstRegex, secondRegex); + + assertExcluded(filter.apply(CLASS1_TEST1), + String.format("Method name [%s] matches excluded pattern: '%s'", CLASS1_TEST1_NAME, firstRegex)); + assertExcluded(filter.apply(CLASS1_TEST2), + String.format("Method name [%s] matches excluded pattern: '%s'", CLASS1_TEST2_NAME, firstRegex)); + assertExcluded(filter.apply(CLASS2_TEST1), + String.format("Method name [%s] matches excluded pattern: '%s'", CLASS2_TEST1_NAME, secondRegex)); + + assertIncluded(filter.apply(CLASS2_TEST2), + String.format("Method name [%s] does not match any excluded pattern: '%s' OR '%s'", CLASS2_TEST2_NAME, + firstRegex, secondRegex)); + } + + private void assertIncluded(FilterResult filterResult, String expectedReason) { + assertTrue(filterResult.included()); + assertThat(filterResult.getReason()).isPresent().contains(expectedReason); + } + + private void assertExcluded(FilterResult filterResult, String excludedPattern) { + assertTrue(filterResult.excluded()); + assertThat(filterResult.getReason()).isPresent().contains(excludedPattern); + } + + private static TestDescriptor methodTestDescriptor(String uniqueId, Class testClass, String methodName) { + var method = ReflectionUtils.findMethod(testClass, methodName, new Class[0]).orElseThrow(); + return new DemoMethodTestDescriptor(UniqueId.root("method", uniqueId), method); + } + + // ------------------------------------------------------------------------- + + @SuppressWarnings("JUnitMalformedDeclaration") + private static class Class1 { + @Test + void test1() { + } + + @Test + void test2() { + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + private static class Class2 { + @Test + void test1() { + } + + @Test + void test2() { + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/PostDiscoveryFilterStub.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/PostDiscoveryFilterStub.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/PostDiscoveryFilterStub.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/PostDiscoveryFilterStub.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagFilterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagFilterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagFilterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagFilterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TagIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -85,6 +85,7 @@ .execute(); } + @SuppressWarnings("JUnitMalformedDeclaration") static class TaggedTestCase { static boolean tag1WasExecuted = false; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherDiscoveryListener.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherDiscoveryListener.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherDiscoveryListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherDiscoveryListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor1.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor1.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor1.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor1.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor2.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor2.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor2.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherInterceptor2.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherSessionListener.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherSessionListener.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherSessionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestLauncherSessionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,17 +10,15 @@ package org.junit.platform.launcher; -import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import java.util.List; -import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor; import org.junit.platform.engine.support.descriptor.EngineDescriptor; import org.junit.platform.fakes.TestDescriptorStub; @@ -31,56 +29,6 @@ private final EngineDescriptor engineDescriptor = new EngineDescriptor(UniqueId.forEngine("foo"), "Foo"); @Test - void doesNotContainTestsForEmptyContainers() { - engineDescriptor.addChild( - new AbstractTestDescriptor(engineDescriptor.getUniqueId().append("test", "bar"), "Bar") { - @Override - public Type getType() { - return Type.CONTAINER; - } - }); - - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); - - assertThat(testPlan.containsTests()).as("contains tests").isFalse(); - } - - @Test - void containsTestsForTests() { - engineDescriptor.addChild( - new AbstractTestDescriptor(engineDescriptor.getUniqueId().append("test", "bar"), "Bar") { - @Override - public Type getType() { - return Type.TEST; - } - }); - - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); - - assertThat(testPlan.containsTests()).as("contains tests").isTrue(); - } - - @Test - void containsTestsForContainersThatMayRegisterTests() { - engineDescriptor.addChild( - new AbstractTestDescriptor(engineDescriptor.getUniqueId().append("test", "bar"), "Bar") { - @Override - public Type getType() { - return Type.CONTAINER; - } - - @Override - public boolean mayRegisterTests() { - return true; - } - }); - - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); - - assertThat(testPlan.containsTests()).as("contains tests").isTrue(); - } - - @Test void acceptsVisitorsInDepthFirstOrder() { var container = new TestDescriptorStub(engineDescriptor.getUniqueId().append("container", "bar"), "Bar"); var test1 = new TestDescriptorStub(container.getUniqueId().append("test", "bar"), "Bar"); @@ -93,7 +41,8 @@ engineDescriptor2.addChild(test2); engineDescriptor2.addChild(test3); - var testPlan = TestPlan.from(List.of(engineDescriptor, engineDescriptor2), configParams); + var testPlan = TestPlan.from(true, List.of(engineDescriptor, engineDescriptor2), configParams, + dummyOutputDirectoryCreator()); var visitor = mock(TestPlan.Visitor.class); testPlan.accept(visitor); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPostDiscoveryTagFilter.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPostDiscoveryTagFilter.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPostDiscoveryTagFilter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/TestPostDiscoveryTagFilter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckerTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ClasspathAlignmentCheckerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.launcher.core.ClasspathAlignmentChecker.WELL_KNOWN_PACKAGES; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.regex.Pattern; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.PackageInfo; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.DisabledInEclipse; + +class ClasspathAlignmentCheckerTests { + + @Test + void classpathIsAligned() { + assertThat(ClasspathAlignmentChecker.check(new LinkageError())).isEmpty(); + } + + @Test + void wrapsLinkageErrorForUnalignedClasspath() { + var cause = new LinkageError(); + AtomicInteger counter = new AtomicInteger(); + Function packageLookup = name -> { + var pkg = mock(Package.class); + when(pkg.getName()).thenReturn(name); + when(pkg.getImplementationVersion()).thenReturn(counter.incrementAndGet() + ".0.0"); + return pkg; + }; + + var result = ClasspathAlignmentChecker.check(cause, packageLookup); + + assertThat(result).isPresent(); + assertThat(result.get()) // + .hasMessageStartingWith("The wrapped LinkageError is likely caused by the versions of " + + "JUnit jars on the classpath/module path not being properly aligned.") // + .hasMessageContaining("Please ensure consistent versions are used") // + .hasMessageFindingMatch("https://docs\\.junit\\.org/.*/user-guide/#dependency-metadata") // + .hasMessageContaining("The following conflicting versions were detected:") // + .hasMessageContaining("- org.junit.jupiter.api: 1.0.0") // + .hasMessageContaining("- org.junit.jupiter.engine: 2.0.0") // + .cause().isSameAs(cause); + } + + @Test + @DisabledInEclipse + void allRootPackagesAreChecked() { + var allowedFileNames = Pattern.compile("junit-(?:platform|jupiter|vintage)-.+[\\d.]+(?:-SNAPSHOT)?\\.jar"); + var classGraph = new ClassGraph() // + .acceptPackages("org.junit.platform", "org.junit.jupiter", "org.junit.vintage") // + .rejectPackages("org.junit.platform.reporting.shadow", "org.junit.jupiter.params.shadow") // + .filterClasspathElements(e -> { + var path = Path.of(e); + var fileName = path.getFileName().toString(); + return allowedFileNames.matcher(fileName).matches(); + }); + + try (var scanResult = classGraph.scan()) { + var foundPackages = scanResult.getPackageInfo().stream() // + .filter(it -> !it.getClassInfo().isEmpty()) // + .map(PackageInfo::getName) // + .sorted() // + .toList(); + + assertThat(foundPackages) // + .allMatch(name -> WELL_KNOWN_PACKAGES.stream().anyMatch(name::startsWith)); + assertThat(WELL_KNOWN_PACKAGES) // + .allMatch(name -> foundPackages.stream().anyMatch(it -> it.startsWith(name))); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeEngineExecutionListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeEngineExecutionListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeEngineExecutionListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeEngineExecutionListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -28,6 +28,7 @@ import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.descriptor.DemoMethodTestDescriptor; import org.mockito.InOrder; @@ -42,30 +43,28 @@ void shouldNotThrowExceptionButLogIfDynamicTestRegisteredListenerMethodFails(LogRecordListener logRecordListener) { compositeEngineExecutionListener().dynamicTestRegistered(anyTestDescriptor()); - assertThatTestListenerErrorLogged(logRecordListener, ThrowingEngineExecutionListener.class, - "dynamicTestRegistered"); + assertThatTestListenerErrorLogged(logRecordListener, "dynamicTestRegistered"); } @Test void shouldNotThrowExceptionButLogIfExecutionStartedListenerMethodFails(LogRecordListener logRecordListener) { compositeEngineExecutionListener().executionStarted(anyTestDescriptor()); - assertThatTestListenerErrorLogged(logRecordListener, ThrowingEngineExecutionListener.class, "executionStarted"); + assertThatTestListenerErrorLogged(logRecordListener, "executionStarted"); } @Test void shouldNotThrowExceptionButLogIfExecutionSkippedListenerMethodFails(LogRecordListener logRecordListener) { compositeEngineExecutionListener().executionSkipped(anyTestDescriptor(), "deliberately skipped container"); - assertThatTestListenerErrorLogged(logRecordListener, ThrowingEngineExecutionListener.class, "executionSkipped"); + assertThatTestListenerErrorLogged(logRecordListener, "executionSkipped"); } @Test void shouldNotThrowExceptionButLogIfExecutionFinishedListenerMethodFails(LogRecordListener logRecordListener) { compositeEngineExecutionListener().executionFinished(anyTestDescriptor(), anyTestExecutionResult()); - assertThatTestListenerErrorLogged(logRecordListener, ThrowingEngineExecutionListener.class, - "executionFinished"); + assertThatTestListenerErrorLogged(logRecordListener, "executionFinished"); } @Test @@ -73,8 +72,7 @@ LogRecordListener logRecordListener) { compositeEngineExecutionListener().reportingEntryPublished(anyTestDescriptor(), ReportEntry.from("one", "two")); - assertThatTestListenerErrorLogged(logRecordListener, ThrowingEngineExecutionListener.class, - "reportingEntryPublished"); + assertThatTestListenerErrorLogged(logRecordListener, "reportingEntryPublished"); } @Test @@ -133,16 +131,15 @@ return mock(); } - private void assertThatTestListenerErrorLogged(LogRecordListener logRecordListener, Class listenerClass, - String methodName) { - assertThat(firstWarnLogRecord(logRecordListener).getMessage()).startsWith( - "EngineExecutionListener [" + listenerClass.getName() + "] threw exception for method: " + methodName); + private void assertThatTestListenerErrorLogged(LogRecordListener logRecordListener, String methodName) { + assertThat(firstWarnLogRecord(logRecordListener).getMessage()).startsWith("EngineExecutionListener [" + + ThrowingEngineExecutionListener.class.getName() + "] threw exception for method: " + methodName); } private static TestDescriptor anyTestDescriptor() { var testClass = CompositeEngineExecutionListenerTests.class; var method = ReflectionUtils.findMethod(testClass, "anyTestDescriptor", new Class[0]).orElseThrow(); - return new DemoMethodTestDescriptor(UniqueId.root("method", "unique_id"), testClass, method); + return new DemoMethodTestDescriptor(UniqueId.root("method", "unique_id"), method); } private static class ThrowingEngineExecutionListener implements EngineExecutionListener { @@ -171,6 +168,11 @@ public void reportingEntryPublished(TestDescriptor testDescriptor, ReportEntry entry) { throw new RuntimeException("failed to invoke listener"); } + + @Override + public void fileEntryPublished(TestDescriptor testDescriptor, FileEntry file) { + throw new RuntimeException("failed to invoke listener"); + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; @@ -206,13 +207,13 @@ } private static TestPlan anyTestPlan() { - return TestPlan.from(Set.of(anyTestDescriptor()), mock()); + return TestPlan.from(true, Set.of(anyTestDescriptor()), mock(), dummyOutputDirectoryCreator()); } private static DemoMethodTestDescriptor anyTestDescriptor() { var testClass = CompositeTestExecutionListenerTests.class; var method = ReflectionUtils.findMethod(testClass, "anyTestDescriptor", new Class[0]).orElseThrow(); - return new DemoMethodTestDescriptor(UniqueId.root("method", "unique_id"), testClass, method); + return new DemoMethodTestDescriptor(UniqueId.root("method", "unique_id"), method); } private static class ThrowingEagerTestExecutionListener extends ThrowingTestExecutionListener diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -167,6 +167,26 @@ assertThat(log.stream(WARNING)).isEmpty(); } + @Test + void launcherThrowsExceptionWhenNoEngineMatchesIdInIncludeEngineFilter(@TrackLogRecords LogRecordListener log) { + var engine = new DemoHierarchicalTestEngine("first"); + TestDescriptor test1 = engine.addTest("test1", noOp); + LauncherDiscoveryRequest request = request() // + .selectors(selectUniqueId(test1.getUniqueId())) // + .filters(includeEngines("first", "second")) // + .build(); + + var launcher = createLauncher(engine); + var exception = assertThrows(JUnitException.class, () -> launcher.discover(request)); + + assertThat(exception.getMessage()) // + .startsWith("No TestEngine ID matched the following include EngineFilters: [second].") // + .contains("Please fix/remove the filter or add the engine.") // + .contains("Registered TestEngines:\n- first (") // + .endsWith("Registered EngineFilters:\n- EngineFilter that includes engines with IDs [first, second]"); + assertThat(log.stream(WARNING)).isEmpty(); + } + @Test void launcherWillLogWarningWhenAllEnginesWereExcluded(@TrackLogRecords LogRecordListener log) { var engine = new DemoHierarchicalTestEngine("first"); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,14 +10,22 @@ package org.junit.platform.launcher.core; +import static java.util.Objects.requireNonNull; +import static java.util.function.UnaryOperator.identity; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.engine.SelectorResolutionResult.unresolved; import static org.junit.platform.engine.TestExecutionResult.successful; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; +import static org.junit.platform.fakes.FaultyTestEngines.createEngineThatCannotResolveAnything; +import static org.junit.platform.fakes.FaultyTestEngines.createEngineThatFailsToResolveAnything; +import static org.junit.platform.launcher.LauncherConstants.DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME; import static org.junit.platform.launcher.LauncherConstants.DRY_RUN_PROPERTY_NAME; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; @@ -25,12 +33,17 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.time.Instant; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -42,12 +55,17 @@ import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.commons.util.ExceptionUtils; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.ExecutionRequest; import org.junit.platform.engine.FilterResult; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.engine.TestExecutionResult.Status; +import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.support.descriptor.EngineDescriptor; import org.junit.platform.engine.support.hierarchical.DemoHierarchicalTestDescriptor; @@ -56,6 +74,7 @@ import org.junit.platform.fakes.TestEngineSpy; import org.junit.platform.fakes.TestEngineStub; import org.junit.platform.launcher.EngineDiscoveryResult; +import org.junit.platform.launcher.LauncherConstants; import org.junit.platform.launcher.LauncherDiscoveryListener; import org.junit.platform.launcher.PostDiscoveryFilter; import org.junit.platform.launcher.PostDiscoveryFilterStub; @@ -64,6 +83,7 @@ import org.junit.platform.launcher.TestPlan; import org.junit.platform.launcher.listeners.SummaryGeneratingListener; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; /** * @since 1.0 @@ -121,7 +141,7 @@ .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging") // .build()); assertThat(testPlan.getRoots()).hasSize(1); - assertDiscoveryFailed(engine, discoveryListener); + assertDiscoveryFailed(engine, inOrder(discoveryListener), discoveryListener); } @ParameterizedTest @@ -152,9 +172,11 @@ assertThat(testPlan.getRoots()).hasSize(1); var engineIdentifier = getOnlyElement(testPlan.getRoots()); assertThat(getOnlyElement(testPlan.getRoots()).getDisplayName()).isEqualTo("my-engine-id"); - verify(discoveryListener).launcherDiscoveryStarted(request); - verify(discoveryListener).launcherDiscoveryFinished(request); - assertDiscoveryFailed(engine, discoveryListener); + + InOrder inOrder = inOrder(discoveryListener); + inOrder.verify(discoveryListener).launcherDiscoveryStarted(request); + assertDiscoveryFailed(engine, inOrder, discoveryListener); + inOrder.verify(discoveryListener).launcherDiscoveryFinished(request); var listener = mock(TestExecutionListener.class); launcher.execute(testPlan, listener); @@ -167,10 +189,13 @@ .hasMessage("TestEngine with ID 'my-engine-id' failed to discover tests"); } - private void assertDiscoveryFailed(TestEngine testEngine, LauncherDiscoveryListener discoveryListener) { + private void assertDiscoveryFailed(TestEngine testEngine, InOrder inOrder, + LauncherDiscoveryListener discoveryListener) { var engineId = testEngine.getId(); var failureCaptor = ArgumentCaptor.forClass(EngineDiscoveryResult.class); - verify(discoveryListener).engineDiscoveryFinished(eq(UniqueId.forEngine(engineId)), failureCaptor.capture()); + inOrder.verify(discoveryListener).engineDiscoveryStarted(UniqueId.forEngine(engineId)); + inOrder.verify(discoveryListener).engineDiscoveryFinished(eq(UniqueId.forEngine(engineId)), + failureCaptor.capture()); var result = failureCaptor.getValue(); assertThat(result.getStatus()).isEqualTo(EngineDiscoveryResult.Status.FAILED); assertThat(result.getThrowable()).isPresent(); @@ -197,7 +222,7 @@ assertThat(testExecutionResult.getValue().getThrowable()).isPresent(); assertThat(testExecutionResult.getValue().getThrowable().get()) // .hasMessage("TestEngine with ID 'TestEngineStub' failed to execute tests") // - .hasCauseReference(rootCause); + .cause().isSameAs(rootCause); } @Test @@ -221,7 +246,7 @@ assertThat(testExecutionResult.getValue().getThrowable()).isPresent(); assertThat(testExecutionResult.getValue().getThrowable().get()) // .hasMessage("TestEngine with ID 'TestEngineStub' failed to execute tests") // - .hasCauseReference(rootCause); + .cause().isSameAs(rootCause); } @Test @@ -245,7 +270,7 @@ assertThat(testExecutionResult.getValue().getThrowable()).isPresent(); assertThat(testExecutionResult.getValue().getThrowable().get()) // .hasMessage("TestEngine with ID 'TestEngineStub' failed to execute tests") // - .hasCauseReference(rootCause); + .cause().isSameAs(rootCause); } @Test @@ -256,8 +281,7 @@ public void execute(ExecutionRequest request) { var engineDescriptor = request.getRootTestDescriptor(); request.getEngineExecutionListener().executionStarted(engineDescriptor); - request.getEngineExecutionListener().executionFinished(engineDescriptor, - TestExecutionResult.successful()); + request.getEngineExecutionListener().executionFinished(engineDescriptor, successful()); throw rootCause; } }; @@ -271,7 +295,7 @@ assertThat(testExecutionResult.getValue().getThrowable()).isPresent(); assertThat(testExecutionResult.getValue().getThrowable().get()) // .hasMessage("TestEngine with ID 'TestEngineStub' failed to execute tests") // - .hasCauseReference(rootCause); + .cause().isSameAs(rootCause); } @Test @@ -298,8 +322,8 @@ assertThat(testExecutionResult.getValue().getThrowable()).isPresent(); assertThat(testExecutionResult.getValue().getThrowable().get()) // .hasMessage("TestEngine with ID 'TestEngineStub' failed to execute tests") // - .hasCauseReference(rootCause) // - .hasSuppressedException(originalFailure); + .hasSuppressedException(originalFailure) // + .cause().isSameAs(rootCause); } @Test @@ -328,7 +352,7 @@ var engineDescriptor = request.getRootTestDescriptor(); var listener = request.getEngineExecutionListener(); listener.executionStarted(engineDescriptor); - listener.executionFinished(engineDescriptor, TestExecutionResult.successful()); + listener.executionFinished(engineDescriptor, successful()); } }; @@ -336,7 +360,7 @@ createLauncher(engine).execute(request().build(), listener); verify(listener).executionStarted(any()); - verify(listener).executionFinished(any(), eq(TestExecutionResult.successful())); + verify(listener).executionFinished(any(), eq(successful())); } @Test @@ -574,7 +598,7 @@ verify(engine, times(1)).execute(any()); var e = assertThrows(PreconditionViolationException.class, () -> launcher.execute(testPlan)); - assertEquals(e.getMessage(), "TestPlan must only be executed once"); + assertEquals("TestPlan must only be executed once", e.getMessage()); } @Test @@ -651,4 +675,379 @@ inOrder.verify(listener).testPlanExecutionFinished(any()); inOrder.verifyNoMoreInteractions(); } + + @Test + void notifiesDiscoveryListenersOfProcessedSelectors() { + TestEngine engine = new TestEngineStub("some-engine-id") { + + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + discoveryRequest.getSelectorsByType(DiscoverySelector.class).forEach(selector -> { + discoveryRequest.getDiscoveryListener().selectorProcessed(uniqueId, selector, unresolved()); + }); + return new EngineDescriptor(uniqueId, uniqueId.getLastSegment().getValue()); + } + }; + var engineId = UniqueId.forEngine(engine.getId()); + + var discoveryListenerOnConfig = mock(LauncherDiscoveryListener.class, "discoveryListenerOnConfig"); + var discoveryListenerOnLauncher = mock(LauncherDiscoveryListener.class, "discoveryListenerOnLauncher"); + var discoveryListenerOnRequest = mock(LauncherDiscoveryListener.class, "discoveryListenerOnRequest"); + var selector = mock(DiscoverySelector.class); + + var launcherConfig = LauncherFactoryForTestingPurposesOnly.createLauncherConfigBuilderWithDisabledServiceLoading() // + .addTestEngines(engine) // + .addLauncherDiscoveryListeners(discoveryListenerOnConfig) // + .build(); + + var launcher = LauncherFactory.create(launcherConfig); + launcher.registerLauncherDiscoveryListeners(discoveryListenerOnLauncher); + + launcher.discover(request() // + .selectors(selector) // + .listeners(discoveryListenerOnRequest) // + .build()); + + assertAll( // + () -> verify(discoveryListenerOnConfig).selectorProcessed(engineId, selector, unresolved()), // + () -> verify(discoveryListenerOnLauncher).selectorProcessed(engineId, selector, unresolved()), // + () -> verify(discoveryListenerOnRequest).selectorProcessed(engineId, selector, unresolved()) // + ); + } + + @Test + void reportsEngineExecutionFailureForCriticalDiscoveryIssuesAndLogsRemaining( + @TrackLogRecords LogRecordListener listener) { + + var result = execute(new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.ERROR, "error")); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.WARNING, "warning")); + return new EngineDescriptor(uniqueId, "Engine") { + @Override + public Set getTags() { + return Set.of(TestTag.create("custom-tag")); + } + }; + } + }); + + assertThat(result.testPlan().containsTests()).isTrue(); + + assertThat(result.testIdentifier().getDisplayName()).isEqualTo("Engine"); + assertThat(result.testIdentifier().getTags()).containsExactly(TestTag.create("custom-tag")); + + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.FAILED); + assertThat(result.testExecutionResult().getThrowable().orElseThrow()) // + .isInstanceOf(DiscoveryIssueException.class) // + .hasMessageStartingWith( + "TestEngine with ID 'engine-id' encountered a critical issue during test discovery") // + .hasMessageContaining("(1) [ERROR] error"); + + var logRecord = findFirstDiscoveryIssueLogRecord(listener, Level.WARNING); + assertThat(logRecord.getMessage()) // + .startsWith("TestEngine with ID 'engine-id' encountered a non-critical issue during test discovery") // + .contains("(1) [WARNING] warning"); + assertThat(logRecord.getInstant()) // + .isBetween(result.startTime(), result.finishTime()); + } + + @Test + void logsNonCriticalIssuesForRegularEngineExecution(@TrackLogRecords LogRecordListener listener) { + + var result = execute(new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.INFO, "info")); + return new EngineDescriptor(uniqueId, "Engine"); + } + + @Override + public void execute(ExecutionRequest request) { + var executionListener = request.getEngineExecutionListener(); + var engineDescriptor = request.getRootTestDescriptor(); + executionListener.executionStarted(engineDescriptor); + executionListener.executionFinished(engineDescriptor, successful()); + } + }); + + assertThat(result.testIdentifier().getDisplayName()).isEqualTo("Engine"); + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.SUCCESSFUL); + + var logRecord = findFirstDiscoveryIssueLogRecord(listener, Level.INFO); + assertThat(logRecord.getMessage()) // + .startsWith("TestEngine with ID 'engine-id' encountered a non-critical issue during test discovery") // + .contains("(1) [INFO] info"); + assertThat(logRecord.getInstant()) // + .isBetween(result.startTime(), result.finishTime()); + } + + @Test + void logsAllIssuesForDiscoveryFailure(@TrackLogRecords LogRecordListener listener) { + + var result = execute(new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.ERROR, "error")); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.INFO, "info")); + throw new RuntimeException("boom"); + } + }); + + assertThat(result.testPlan().containsTests()).isTrue(); + + assertThat(result.testIdentifier().getDisplayName()).isEqualTo("engine-id"); + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.FAILED); + assertThat(result.testExecutionResult().getThrowable().orElseThrow()) // + .hasMessage("TestEngine with ID 'engine-id' failed to discover tests") // + .cause().hasMessage("boom"); + + var logRecord = findFirstDiscoveryIssueLogRecord(listener, Level.SEVERE); + assertThat(logRecord.getMessage()) // + .startsWith("TestEngine with ID 'engine-id' encountered a critical issue during test discovery") // + .contains("(1) [ERROR] error"); + assertThat(logRecord.getInstant()) // + .isBetween(result.startTime(), result.finishTime()); + + logRecord = findFirstDiscoveryIssueLogRecord(listener, Level.INFO); + assertThat(logRecord.getMessage()) // + .startsWith("TestEngine with ID 'engine-id' encountered a non-critical issue during test discovery") // + .contains("(1) [INFO] info"); + assertThat(logRecord.getInstant()) // + .isBetween(result.startTime(), result.finishTime()); + } + + @Test + void logsNonCriticalIssuesForExecutionFailure(@TrackLogRecords LogRecordListener listener) { + + var result = execute(new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.INFO, "info")); + return new EngineDescriptor(uniqueId, "Engine"); + } + + @Override + public void execute(ExecutionRequest request) { + throw new RuntimeException("boom"); + } + }); + + assertThat(result.testIdentifier().getDisplayName()).isEqualTo("Engine"); + + assertThat(result.testExecutionResult().getThrowable().orElseThrow()) // + .hasMessage("TestEngine with ID 'engine-id' failed to execute tests") // + .cause().hasMessage("boom"); + + var logRecord = findFirstDiscoveryIssueLogRecord(listener, Level.INFO); + assertThat(logRecord.getMessage()) // + .startsWith("TestEngine with ID 'engine-id' encountered a non-critical issue during test discovery") // + .contains("(1) [INFO] info"); + assertThat(logRecord.getInstant()) // + .isBetween(result.startTime(), result.finishTime()); + } + + @Test + void reportsEngineExecutionFailureOnUnresolvedUniqueIdSelectorWithEnginePrefix() { + var engine = createEngineThatCannotResolveAnything("some-engine"); + var selector = selectUniqueId(UniqueId.forEngine(engine.getId())); + var result = execute(engine, request -> request.selectors(selector)); + + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.FAILED); + assertThat(result.testExecutionResult().getThrowable().orElseThrow()) // + .isInstanceOf(DiscoveryIssueException.class) // + .hasMessageStartingWith( + "TestEngine with ID 'some-engine' encountered a critical issue during test discovery") // + .hasMessageContaining("(1) [ERROR] %s could not be resolved", selector); + } + + @Test + void ignoresUnresolvedUniqueIdSelectorWithoutEnginePrefix() { + var engine = createEngineThatCannotResolveAnything("some-engine"); + var selector = selectUniqueId(UniqueId.forEngine("some-other-engine")); + var result = execute(engine, request -> request.selectors(selector)); + + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.SUCCESSFUL); + } + + @Test + void reportsEngineExecutionFailureForSelectorResolutionFailure() { + var engine = createEngineThatFailsToResolveAnything("some-engine", new RuntimeException("boom")); + var selector = selectClass(Object.class); + var result = execute(engine, request -> request.selectors(selector)); + + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.FAILED); + assertThat(result.testExecutionResult().getThrowable().orElseThrow()) // + .isInstanceOf(DiscoveryIssueException.class) // + .hasMessageStartingWith( + "TestEngine with ID 'some-engine' encountered a critical issue during test discovery") // + .hasMessageContaining("(1) [ERROR] %s resolution failed", selector) // + .hasMessageContaining("Cause: java.lang.RuntimeException: boom"); + } + + @Test + void allowsConfiguringCriticalDiscoveryIssueSeverity() { + + var engine = new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.INFO, "info")); + return new EngineDescriptor(uniqueId, "Engine"); + } + }; + + var result = execute(engine, request -> request // + .configurationParameter(LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, "info")); + + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.FAILED); + assertThat(result.testExecutionResult().getThrowable().orElseThrow()) // + .isInstanceOf(DiscoveryIssueException.class) // + .hasMessageStartingWith( + "TestEngine with ID 'engine-id' encountered a critical issue during test discovery") // + .hasMessageContaining("(1) [INFO] info"); + } + + @Test + void fallsBackToErrorSeverityIfCriticalSeverityIsConfiguredIncorrectly( + @TrackLogRecords LogRecordListener listener) { + + var engine = new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.INFO, "info")); + return new EngineDescriptor(uniqueId, "Engine"); + } + + @Override + public void execute(ExecutionRequest request) { + var executionListener = request.getEngineExecutionListener(); + var engineDescriptor = request.getRootTestDescriptor(); + executionListener.executionStarted(engineDescriptor); + executionListener.executionFinished(engineDescriptor, successful()); + } + }; + + var result = execute(engine, request -> request // + .configurationParameter(LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, "wrong")); + + assertThat(result.testExecutionResult().getStatus()).isEqualTo(Status.SUCCESSFUL); + + var logRecord = listener.stream(DiscoveryIssueCollector.class, Level.WARNING) // + .findFirst() // + .orElseThrow(); + assertThat(logRecord.getMessage()) // + .isEqualTo( + "Invalid DiscoveryIssue.Severity 'wrong' set via the '%s' configuration parameter. " + + "Falling back to the ERROR default value.", + LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME); + } + + @Test + void failsDuringDiscoveryIfConfigurationParameterIsSetAccordingly() { + + var engine = new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.ERROR, "error")); + return new EngineDescriptor(uniqueId, "Engine"); + } + }; + + var exception = assertThrows(DiscoveryIssueException.class, () -> execute(engine, request -> request // + .configurationParameter(LauncherConstants.DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME, "discovery"))); + + assertThat(exception) // + .isInstanceOf(DiscoveryIssueException.class) // + .hasMessageStartingWith( + "TestEngine with ID 'engine-id' encountered a critical issue during test discovery") // + .hasMessageContaining("(1) [ERROR] error"); + } + + @ParameterizedTest + @ValueSource(strings = { "discovery", "execution" }) + void logsNonCriticalIssuesOnlyOnce(String phase, @TrackLogRecords LogRecordListener listener) { + + var engine = new TestEngineStub("engine-id") { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, DiscoveryIssue.create(Severity.WARNING, "warning")); + return new EngineDescriptor(uniqueId, "Engine"); + } + + @Override + public void execute(ExecutionRequest request) { + var executionListener = request.getEngineExecutionListener(); + var engineDescriptor = request.getRootTestDescriptor(); + executionListener.executionStarted(engineDescriptor); + executionListener.executionFinished(engineDescriptor, successful()); + } + }; + + execute(engine, request -> request // + .configurationParameter(LauncherConstants.DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME, phase)); + + assertThat(listener.stream(DiscoveryIssueNotifier.class, Level.WARNING)).hasSize(1); + } + + private static ReportedData execute(TestEngine engine) { + return execute(engine, identity()); + } + + private static ReportedData execute(TestEngine engine, UnaryOperator configurer) { + var executionListener = mock(TestExecutionListener.class); + + AtomicReference startTime = new AtomicReference<>(); + doAnswer(invocation -> { + startTime.set(Instant.now()); + return null; + }).when(executionListener).executionStarted(any()); + + AtomicReference finishTime = new AtomicReference<>(); + doAnswer(invocation -> { + finishTime.set(Instant.now()); + return null; + }).when(executionListener).executionFinished(any(), any()); + + var builder = request() // + .enableImplicitConfigurationParameters(false) // + .configurationParameter(DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME, "execution") // + .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging"); + var request = configurer.apply(builder).build(); + var launcher = createLauncher(engine); + + var testPlan = launcher.discover(request); + launcher.execute(testPlan, executionListener); + + var inOrder = inOrder(executionListener); + var testIdentifier = ArgumentCaptor.forClass(TestIdentifier.class); + var testExecutionResult = ArgumentCaptor.forClass(TestExecutionResult.class); + inOrder.verify(executionListener).testPlanExecutionStarted(any()); + inOrder.verify(executionListener).executionStarted(testIdentifier.capture()); + inOrder.verify(executionListener).executionFinished(any(), testExecutionResult.capture()); + inOrder.verify(executionListener).testPlanExecutionFinished(any()); + inOrder.verifyNoMoreInteractions(); + + return new ReportedData(testPlan, testIdentifier.getValue(), testExecutionResult.getValue(), + requireNonNull(startTime.get()), requireNonNull(finishTime.get())); + } + + private static LogRecord findFirstDiscoveryIssueLogRecord(LogRecordListener listener, Level level) { + return listener.stream(DiscoveryIssueNotifier.class, level) // + .findFirst() // + .orElseThrow(); + } + + private record ReportedData(TestPlan testPlan, TestIdentifier testIdentifier, + TestExecutionResult testExecutionResult, Instant startTime, Instant finishTime) { + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DiscoveryIssueCollectorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DiscoveryIssueCollectorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DiscoveryIssueCollectorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/DiscoveryIssueCollectorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResource; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectDirectory; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectFile; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUri; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.net.URI; +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.RecordArguments; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.SelectorResolutionResult; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.discovery.FilePosition; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.engine.support.descriptor.ClasspathResourceSource; +import org.junit.platform.engine.support.descriptor.DirectorySource; +import org.junit.platform.engine.support.descriptor.FileSource; +import org.junit.platform.engine.support.descriptor.PackageSource; +import org.junit.platform.engine.support.descriptor.UriSource; + +class DiscoveryIssueCollectorTests { + + @ParameterizedTest(name = "{0}") + @MethodSource("pairs") + void reportsFailedResolutionResultAsDiscoveryIssue(DiscoverySelector selector, TestSource source) { + var collector = new DiscoveryIssueCollector(mock()); + var failure = SelectorResolutionResult.failed(new RuntimeException("boom")); + collector.selectorProcessed(UniqueId.forEngine("dummy"), selector, failure); + + var expectedIssue = DiscoveryIssue.builder(Severity.ERROR, selector + " resolution failed") // + .cause(failure.getThrowable()) // + .source(source) // + .build(); + assertThat(collector.toNotifier().getAllIssues()).containsExactly(expectedIssue); + } + + public static Stream pairs() { + return Stream.of( // + new Pair(selectClass("SomeClass"), ClassSource.from("SomeClass")), // + new Pair(selectMethod("SomeClass#someMethod(int,int)"), + org.junit.platform.engine.support.descriptor.MethodSource.from("SomeClass", "someMethod", "int,int")), // + new Pair(selectClasspathResource("someResource"), ClasspathResourceSource.from("someResource")), // + new Pair(selectClasspathResource("someResource", FilePosition.from(42)), + ClasspathResourceSource.from("someResource", + org.junit.platform.engine.support.descriptor.FilePosition.from(42))), // + new Pair(selectClasspathResource("someResource", FilePosition.from(42, 23)), + ClasspathResourceSource.from("someResource", + org.junit.platform.engine.support.descriptor.FilePosition.from(42, 23))), // + new Pair(selectPackage(""), PackageSource.from("")), // + new Pair(selectPackage("some.package"), PackageSource.from("some.package")), // + new Pair(selectFile("someFile"), FileSource.from(new File("someFile"))), // + new Pair(selectFile("someFile", FilePosition.from(42)), + FileSource.from(new File("someFile"), + org.junit.platform.engine.support.descriptor.FilePosition.from(42))), // + new Pair(selectFile("someFile", FilePosition.from(42, 23)), + FileSource.from(new File("someFile"), + org.junit.platform.engine.support.descriptor.FilePosition.from(42, 23))), // + new Pair(selectDirectory("someDir"), DirectorySource.from(new File("someDir"))), // + new Pair(selectUri("some:uri"), UriSource.from(URI.create("some:uri"))) // + ); + } + + record Pair(DiscoverySelector selector, TestSource source) implements RecordArguments { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidatorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/EngineDiscoveryResultValidatorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.platform.launcher.core; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.mock; import java.util.Map; @@ -23,6 +24,7 @@ import org.junit.platform.engine.support.descriptor.DemoMethodTestDescriptor; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.core.LauncherDiscoveryResult.EngineResultInfo; /** * @since 1.0 @@ -34,7 +36,9 @@ void testReportingEntryPublished() { var testDescriptor = getSampleMethodTestDescriptor(); - var discoveryResult = new LauncherDiscoveryResult(Map.of(mock(), testDescriptor), mock()); + var discoveryResult = new LauncherDiscoveryResult( + Map.of(mock(), EngineResultInfo.completed(testDescriptor, DiscoveryIssueNotifier.NO_ISSUES)), mock(), + dummyOutputDirectoryCreator()); var testPlan = InternalTestPlan.from(discoveryResult); var testIdentifier = testPlan.getTestIdentifier(testDescriptor.getUniqueId()); @@ -50,9 +54,9 @@ } private TestDescriptor getSampleMethodTestDescriptor() { - var localMethodNamedNothing = ReflectionUtils.findMethod(this.getClass(), "nothing", new Class[0]).get(); - return new DemoMethodTestDescriptor(UniqueId.root("method", "unique_id"), this.getClass(), - localMethodNamedNothing); + var localMethodNamedNothing = ReflectionUtils.findMethod(this.getClass(), "nothing", + new Class[0]).orElseThrow(); + return new DemoMethodTestDescriptor(UniqueId.root("method", "unique_id"), localMethodNamedNothing); } //for reflection purposes only diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreatorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/HierarchicalOutputDirectoryCreatorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.nio.file.Path; +import java.util.function.Supplier; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoSettings; + +@MockitoSettings +public class HierarchicalOutputDirectoryCreatorTests { + + @TempDir + Path tempDir; + + @Mock + Supplier rootDirSupplier; + + @Mock + TestDescriptor testDescriptor; + + @InjectMocks + HierarchicalOutputDirectoryCreator provider; + + @BeforeEach + void prepareMock() { + when(rootDirSupplier.get()).thenReturn(tempDir); + } + + @Test + void returnsConfiguredRootDir() { + assertThat(provider.getRootDirectory()).isEqualTo(tempDir); + assertThat(provider.getRootDirectory()).isEqualTo(tempDir); + verify(rootDirSupplier, times(1)).get(); + } + + @Test + void createsSubDirectoriesBasedOnUniqueId() throws Exception { + var uniqueId = UniqueId.forEngine("engine") // + .append("irrelevant", "foo") // + .append("irrelevant", "bar"); + when(testDescriptor.getUniqueId()).thenReturn(uniqueId); + + var outputDir = provider.createOutputDirectory(testDescriptor); + + assertThat(outputDir) // + .isEqualTo(tempDir.resolve(Path.of("engine", "foo", "bar"))) // + .exists(); + } + + @Test + void replacesForbiddenCharacters() throws Exception { + var uniqueId = UniqueId.forEngine("Engine<>") // + .append("irrelevant", "*/abc"); + when(testDescriptor.getUniqueId()).thenReturn(uniqueId); + + var outputDir = provider.createOutputDirectory(testDescriptor); + + assertThat(outputDir) // + .isEqualTo(tempDir.resolve(Path.of("Engine__", "__abc"))) // + .exists(); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/InternalTestPlanTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/InternalTestPlanTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/InternalTestPlanTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/InternalTestPlanTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; +import static org.mockito.Mockito.mock; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.TestEngine; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor; +import org.junit.platform.engine.support.descriptor.EngineDescriptor; +import org.junit.platform.launcher.core.LauncherDiscoveryResult.EngineResultInfo; + +public class InternalTestPlanTests { + + private final ConfigurationParameters configParams = mock(); + + private final EngineDescriptor engineDescriptor = new EngineDescriptor(UniqueId.forEngine("foo"), "Foo"); + + @Test + void doesNotContainTestsForEmptyContainers() { + engineDescriptor.addChild( + new AbstractTestDescriptor(engineDescriptor.getUniqueId().append("test", "bar"), "Bar") { + @Override + public Type getType() { + return Type.CONTAINER; + } + }); + + var testPlan = InternalTestPlan.from(createLauncherDiscoveryResult( + EngineResultInfo.completed(engineDescriptor, DiscoveryIssueNotifier.NO_ISSUES))); + + assertThat(testPlan.containsTests()).as("contains tests").isFalse(); + } + + @Test + void containsTestsForTests() { + engineDescriptor.addChild( + new AbstractTestDescriptor(engineDescriptor.getUniqueId().append("test", "bar"), "Bar") { + @Override + public Type getType() { + return Type.TEST; + } + }); + + var testPlan = InternalTestPlan.from(createLauncherDiscoveryResult( + EngineResultInfo.completed(engineDescriptor, DiscoveryIssueNotifier.NO_ISSUES))); + + assertThat(testPlan.containsTests()).as("contains tests").isTrue(); + } + + @Test + void containsTestsForContainersThatMayRegisterTests() { + engineDescriptor.addChild( + new AbstractTestDescriptor(engineDescriptor.getUniqueId().append("test", "bar"), "Bar") { + @Override + public Type getType() { + return Type.CONTAINER; + } + + @Override + public boolean mayRegisterTests() { + return true; + } + }); + + var testPlan = InternalTestPlan.from(createLauncherDiscoveryResult( + EngineResultInfo.completed(engineDescriptor, DiscoveryIssueNotifier.NO_ISSUES))); + + assertThat(testPlan.containsTests()).as("contains tests").isTrue(); + } + + @Test + void containsTestsForEnginesWithDiscoveryError() { + var testPlan = InternalTestPlan.from(createLauncherDiscoveryResult( + EngineResultInfo.errored(engineDescriptor, DiscoveryIssueNotifier.NO_ISSUES, new RuntimeException()))); + + assertThat(testPlan.containsTests()).as("contains tests").isTrue(); + } + + @Test + void containsTestsForEnginesWithCriticalDiscoveryIssues() { + var testPlan = InternalTestPlan.from(createLauncherDiscoveryResult(EngineResultInfo.completed(engineDescriptor, + DiscoveryIssueNotifier.from(Severity.ERROR, List.of(DiscoveryIssue.create(Severity.ERROR, "error")))))); + + assertThat(testPlan.containsTests()).as("contains tests").isTrue(); + } + + @Test + void doesNotContainTestsForEnginesWithNonCriticalDiscoveryIssues() { + var testPlan = InternalTestPlan.from(createLauncherDiscoveryResult(EngineResultInfo.completed(engineDescriptor, + DiscoveryIssueNotifier.from(Severity.ERROR, List.of(DiscoveryIssue.create(Severity.WARNING, "warning")))))); + + assertThat(testPlan.containsTests()).as("contains tests").isFalse(); + } + + private LauncherDiscoveryResult createLauncherDiscoveryResult(EngineResultInfo result) { + var testEngineResults = Map.of(mock(TestEngine.class), result); + return new LauncherDiscoveryResult(testEngineResults, configParams, dummyOutputDirectoryCreator()); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigurationParametersTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigurationParametersTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigurationParametersTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigurationParametersTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -266,6 +266,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") @ExtendWith(Mutator.class) static class Something { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.platform.launcher.core; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -64,7 +63,7 @@ // @formatter:on var packageSelectors = discoveryRequest.getSelectorsByType(ModuleSelector.class).stream().map( - ModuleSelector::getModuleName).collect(toList()); + ModuleSelector::getModuleName).toList(); assertThat(packageSelectors).contains("java.base"); } @@ -78,7 +77,7 @@ // @formatter:on var packageSelectors = discoveryRequest.getSelectorsByType(PackageSelector.class).stream().map( - PackageSelector::getPackageName).collect(toList()); + PackageSelector::getPackageName).toList(); assertThat(packageSelectors).contains("org.junit.platform.engine"); } @@ -93,8 +92,9 @@ .build(); // @formatter:on - List> classes = discoveryRequest.getSelectorsByType(ClassSelector.class).stream().map( - ClassSelector::getJavaClass).collect(toList()); + @SuppressWarnings("rawtypes") + List classes = discoveryRequest.getSelectorsByType(ClassSelector.class).stream()// + .map(ClassSelector::getJavaClass).map(Class.class::cast).toList(); assertThat(classes).contains(SampleTestClass.class, LauncherDiscoveryRequestBuilderTests.class); } @@ -109,7 +109,7 @@ var methodSelectors = discoveryRequest.getSelectorsByType(MethodSelector.class); assertThat(methodSelectors).hasSize(1); - var methodSelector = methodSelectors.get(0); + var methodSelector = methodSelectors.getFirst(); assertThat(methodSelector.getJavaClass()).isEqualTo(LauncherDiscoveryRequestBuilderTests.class); assertThat(methodSelector.getJavaMethod()).isEqualTo(fullyQualifiedMethod()); } @@ -128,7 +128,7 @@ var methodSelectors = discoveryRequest.getSelectorsByType(MethodSelector.class); assertThat(methodSelectors).hasSize(1); - var methodSelector = methodSelectors.get(0); + var methodSelector = methodSelectors.getFirst(); assertThat(methodSelector.getJavaClass()).isEqualTo(testClass); assertThat(methodSelector.getJavaMethod()).isEqualTo(testMethod); } @@ -148,7 +148,7 @@ var methodSelectors = discoveryRequest.getSelectorsByType(MethodSelector.class); assertThat(methodSelectors).hasSize(1); - var methodSelector = methodSelectors.get(0); + var methodSelector = methodSelectors.getFirst(); assertThat(methodSelector.getJavaClass()).isEqualTo(testClass); assertThat(methodSelector.getJavaMethod()).isEqualTo(testMethod); } @@ -167,7 +167,7 @@ // @formatter:on var uniqueIds = discoveryRequest.getSelectorsByType(UniqueIdSelector.class).stream().map( - UniqueIdSelector::getUniqueId).map(Object::toString).collect(toList()); + UniqueIdSelector::getUniqueId).map(Object::toString).toList(); assertThat(uniqueIds).contains(id1.toString(), id2.toString()); } @@ -190,7 +190,7 @@ var filters = discoveryRequest.getEngineFilters(); assertThat(filters).hasSize(1); - var engineFilter = filters.get(0); + var engineFilter = filters.getFirst(); assertTrue(engineFilter.apply(engine1).included()); assertTrue(engineFilter.apply(engine2).included()); assertTrue(engineFilter.apply(engine3).excluded()); @@ -398,6 +398,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") private static class SampleTestClass { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryResultTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryResultTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryResultTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryResultTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.EngineDiscoveryRequest; +import org.junit.platform.engine.ExecutionRequest; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestEngine; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.launcher.core.LauncherDiscoveryResult.EngineResultInfo; + +/** + * Unit tests for {@link LauncherDiscoveryResult}. + */ +class LauncherDiscoveryResultTests { + + /** + * @see GitHub issue #4862 + */ + @Test + void withRetainedEnginesRetainsLinkedHashMapSemantics() { + TestEngine engine1 = new DummyEngine1(); + TestEngine engine2 = new DummyEngine2(); + TestEngine engine3 = new DummyEngine3(); + TestEngine engine4 = new DummyEngine4(); + + TestDescriptor rootDescriptor1 = mock(); + TestDescriptor rootDescriptor2 = mock(); + TestDescriptor rootDescriptor3 = mock(); + TestDescriptor rootDescriptor4 = mock(); + when(rootDescriptor1.isTest()).thenReturn(true); + when(rootDescriptor2.isTest()).thenReturn(false); + when(rootDescriptor3.isTest()).thenReturn(false); + when(rootDescriptor4.isTest()).thenReturn(true); + + EngineResultInfo engineResultInfo1 = mock(); + EngineResultInfo engineResultInfo2 = mock(); + EngineResultInfo engineResultInfo3 = mock(); + EngineResultInfo engineResultInfo4 = mock(); + when(engineResultInfo1.getRootDescriptor()).thenReturn(rootDescriptor1); + when(engineResultInfo2.getRootDescriptor()).thenReturn(rootDescriptor2); + when(engineResultInfo3.getRootDescriptor()).thenReturn(rootDescriptor3); + when(engineResultInfo4.getRootDescriptor()).thenReturn(rootDescriptor4); + + @SuppressWarnings("serial") + Map engineResults = new LinkedHashMap<>() { + { + put(engine1, engineResultInfo1); + put(engine2, engineResultInfo2); + put(engine3, engineResultInfo3); + put(engine4, engineResultInfo4); + } + }; + + assertThat(engineResults.keySet()).containsExactly(engine1, engine2, engine3, engine4); + + LauncherDiscoveryResult discoveryResult = new LauncherDiscoveryResult(engineResults, mock(), mock()); + assertThat(discoveryResult.getTestEngines()).containsExactly(engine1, engine2, engine3, engine4); + + LauncherDiscoveryResult withRetainedEngines = discoveryResult.withRetainedEngines(TestDescriptor::isTest); + + assertThat(withRetainedEngines.getTestEngines()).containsExactly(engine1, engine4); + } + + private static abstract class AbstractDummyEngine implements TestEngine { + + @Override + public String getId() { + return getClass().getSimpleName(); + } + + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + throw new UnsupportedOperationException("discover"); + } + + @Override + public void execute(ExecutionRequest request) { + throw new UnsupportedOperationException("execute"); + } + } + + private static class DummyEngine1 extends AbstractDummyEngine { + } + + private static class DummyEngine2 extends AbstractDummyEngine { + } + + private static class DummyEngine3 extends AbstractDummyEngine { + } + + private static class DummyEngine4 extends AbstractDummyEngine { + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherFactoryTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherFactoryTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherFactoryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherFactoryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,36 +10,41 @@ package org.junit.platform.launcher.core; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.TemporaryClasspathExecutor.withAdditionalClasspathRoot; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.launcher.LauncherConstants.DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME; import static org.junit.platform.launcher.LauncherConstants.ENABLE_LAUNCHER_INTERCEPTORS; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.net.URL; -import java.net.URLClassLoader; import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.LogRecord; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.StoreScope; +import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.engine.JupiterTestEngine; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.engine.EngineDiscoveryRequest; import org.junit.platform.engine.ExecutionRequest; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.store.Namespace; import org.junit.platform.fakes.TestEngineSpy; import org.junit.platform.launcher.InterceptedTestEngine; import org.junit.platform.launcher.InterceptorInjectedLauncherSessionListener; import org.junit.platform.launcher.LauncherConstants; import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.LauncherSession; import org.junit.platform.launcher.LauncherSessionListener; import org.junit.platform.launcher.TagFilter; import org.junit.platform.launcher.TestExecutionListener; @@ -80,7 +85,8 @@ } @Test - void testExecutionListenersExcludedViaConfigParametersIsNotLoadedViaServiceApi() { + void testExecutionListenersExcludedViaConfigParametersIsNotLoadedViaServiceApi( + @TrackLogRecords LogRecordListener listener) { withTestServices(() -> { var value = "org.junit.*.launcher.listeners.Unused*,org.junit.*.launcher.listeners.AnotherUnused*"; withSystemProperty(DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME, value, () -> { @@ -95,6 +101,16 @@ launcher.execute(request().build()); + var logMessage = listener.stream(ServiceLoaderRegistry.class) // + .map(LogRecord::getMessage) // + .filter(it -> it.startsWith("Loaded TestExecutionListener instances")) // + .findAny(); + assertThat(logMessage).isPresent(); + assertThat(logMessage.get()) // + .contains("NoopTestExecutionListener@") // + .endsWith(" (excluded classes: [" + UnusedTestExecutionListener.class.getName() + ", " + + AnotherUnusedTestExecutionListener.class.getName() + "])"); + assertFalse(UnusedTestExecutionListener.called); assertFalse(AnotherUnusedTestExecutionListener.called); }); @@ -112,7 +128,7 @@ // @formatter:off var ids = roots.stream() .map(TestIdentifier::getUniqueId) - .collect(toList()); + .toList(); // @formatter:on assertThat(ids).containsOnly("[engine:junit-vintage]", "[engine:junit-jupiter]", @@ -135,7 +151,7 @@ // @formatter:off var ids = roots.stream() .map(TestIdentifier::getUniqueId) - .collect(toList()); + .toList(); // @formatter:on assertThat(ids).containsOnly("[engine:junit-jupiter]"); @@ -320,6 +336,83 @@ })); } + @Test + void extensionCanReadValueFromSessionStoreAndReadByLauncherSessionListenerOnOpened() { + var config = LauncherConfig.builder() // + .addLauncherSessionListeners(new LauncherSessionListenerOpenedExample()) // + .build(); + + try (LauncherSession session = LauncherFactory.openSession(config)) { + var launcher = session.getLauncher(); + var request = request().selectors(selectClass(SessionTrackingTestCase.class)).build(); + + AtomicReference errorRef = new AtomicReference<>(); + launcher.execute(request, new TestExecutionListener() { + @Override + public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { + testExecutionResult.getThrowable().ifPresent(errorRef::set); + } + }); + + assertThat(errorRef.get()).isNull(); + } + } + + @Test + void extensionCanReadValueFromSessionStoreAndReadByLauncherSessionListenerOnClose() { + var config = LauncherConfig.builder() // + .addLauncherSessionListeners(new LauncherSessionListenerClosedExample()) // + .build(); + + try (LauncherSession session = LauncherFactory.openSession(config)) { + var launcher = session.getLauncher(); + var request = request().selectors(selectClass(SessionStoringTestCase.class)).build(); + + AtomicReference errorRef = new AtomicReference<>(); + launcher.execute(request, new TestExecutionListener() { + @Override + public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { + testExecutionResult.getThrowable().ifPresent(errorRef::set); + } + }); + + assertThat(errorRef.get()).isNull(); + } + } + + @Test + void sessionResourceClosedOnSessionClose() { + CloseTrackingResource.closed = false; + var config = LauncherConfig.builder() // + .addLauncherSessionListeners(new AutoCloseCheckListener()) // + .build(); + + try (LauncherSession session = LauncherFactory.openSession(config)) { + var launcher = session.getLauncher(); + var request = request().selectors(selectClass(SessionResourceAutoCloseTestCase.class)).build(); + + launcher.execute(request); + assertThat(CloseTrackingResource.closed).isFalse(); + } + + assertThat(CloseTrackingResource.closed).isTrue(); + } + + @Test + void requestResourceClosedOnExecutionClose() { + CloseTrackingResource.closed = false; + var config = LauncherConfig.builder().build(); + + try (LauncherSession session = LauncherFactory.openSession(config)) { + var launcher = session.getLauncher(); + var request = request().selectors(selectClass(RequestResourceAutoCloseTestCase.class)).build(); + + launcher.execute(request); + + assertThat(CloseTrackingResource.closed).isTrue(); + } + } + @SuppressWarnings("SameParameterValue") private static void withSystemProperty(String key, String value, Runnable runnable) { var oldValue = System.getProperty(key); @@ -338,18 +431,7 @@ } private static void withTestServices(Runnable runnable) { - var current = Thread.currentThread().getContextClassLoader(); - var url = LauncherFactoryTests.class.getClassLoader().getResource("testservices/"); - try (var classLoader = new URLClassLoader(new URL[] { url }, current)) { - Thread.currentThread().setContextClassLoader(classLoader); - runnable.run(); - } - catch (IOException e) { - throw new UncheckedIOException(e); - } - finally { - Thread.currentThread().setContextClassLoader(current); - } + withAdditionalClasspathRoot("testservices/", runnable); } private LauncherDiscoveryRequest createLauncherDiscoveryRequestForBothStandardEngineExampleClasses() { @@ -361,7 +443,7 @@ // @formatter:on } - @SuppressWarnings("NewClassNamingConvention") + @SuppressWarnings({ "NewClassNamingConvention", "JUnitMalformedDeclaration" }) public static class JUnit4Example { @org.junit.Test @@ -370,13 +452,132 @@ } - @SuppressWarnings("NewClassNamingConvention") + @SuppressWarnings({ "NewClassNamingConvention", "JUnitMalformedDeclaration" }) static class JUnit5Example { @Tag("test-post-discovery") @Test void testJ5() { } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(SessionTrackingExtension.class) + static class SessionTrackingTestCase { + @Test + void dummyTest() { + // Just a placeholder to trigger the extension + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(SessionStoringExtension.class) + static class SessionStoringTestCase { + + @Test + void dummyTest() { + // Just a placeholder to trigger the extension + } + } + + static class LauncherSessionListenerOpenedExample implements LauncherSessionListener { + @Override + public void launcherSessionOpened(LauncherSession session) { + session.getStore().put(Namespace.GLOBAL, "testKey", "testValue"); + } + } + + static class LauncherSessionListenerClosedExample implements LauncherSessionListener { + @Override + public void launcherSessionClosed(LauncherSession session) { + Object storedValue = session.getStore().get(Namespace.GLOBAL, "testKey"); + assertThat(storedValue).isEqualTo("testValue"); + } + } + + static class SessionTrackingExtension implements BeforeAllCallback { + @Override + public void beforeAll(ExtensionContext context) { + var value = context.getStore(ExtensionContext.Namespace.GLOBAL).get("testKey"); + if (!"testValue".equals(value)) { + throw new IllegalStateException("Expected 'testValue' but got: " + value); + } + + value = context.getStore(StoreScope.LAUNCHER_SESSION, ExtensionContext.Namespace.GLOBAL).get("testKey"); + if (!"testValue".equals(value)) { + throw new IllegalStateException("Expected 'testValue' but got: " + value); + } + } + } + + static class SessionStoringExtension implements BeforeAllCallback { + @Override + public void beforeAll(ExtensionContext context) { + context.getStore(StoreScope.LAUNCHER_SESSION, ExtensionContext.Namespace.GLOBAL).put("testKey", + "testValue"); + } + } + + private static class CloseTrackingResource implements AutoCloseable { + private static boolean closed = false; + + @Override + public void close() { + closed = true; + } + + public boolean isClosed() { + return closed; + } + } + + private static class SessionResourceStoreUsingExtension implements BeforeAllCallback { + @Override + public void beforeAll(ExtensionContext context) { + CloseTrackingResource sessionResource = new CloseTrackingResource(); + context.getStore(StoreScope.LAUNCHER_SESSION, ExtensionContext.Namespace.GLOBAL).put("sessionResource", + sessionResource); + } + } + + private static class RequestResourceStoreUsingExtension implements BeforeAllCallback { + @Override + public void beforeAll(ExtensionContext context) { + CloseTrackingResource requestResource = new CloseTrackingResource(); + context.getStore(StoreScope.EXECUTION_REQUEST, ExtensionContext.Namespace.GLOBAL).put("requestResource", + requestResource); + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(SessionResourceStoreUsingExtension.class) + static class SessionResourceAutoCloseTestCase { + + @Test + void dummyTest() { + // Just a placeholder to trigger the extension + } + } + + @SuppressWarnings("JUnitMalformedDeclaration") + @ExtendWith(RequestResourceStoreUsingExtension.class) + static class RequestResourceAutoCloseTestCase { + + @Test + void dummyTest() { + // Just a placeholder to trigger the extension + } + } + + private static class AutoCloseCheckListener implements LauncherSessionListener { + @Override + public void launcherSessionClosed(LauncherSession session) { + CloseTrackingResource sessionResource = session // + .getStore() // + .get(Namespace.GLOBAL, "sessionResource", CloseTrackingResource.class); + + assertThat(sessionResource.isClosed()).isFalse(); + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherSessionTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherSessionTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherSessionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherSessionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ListenerRegistryTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ListenerRegistryTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ListenerRegistryTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/ListenerRegistryTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,7 +20,7 @@ @Test void registerWithNullArray() { - var registry = ListenerRegistry.create(l -> l.get(0)); + var registry = ListenerRegistry.create(l -> l.getFirst()); var exception = assertThrows(PreconditionViolationException.class, () -> registry.addAll((Object[]) null)); @@ -29,7 +29,7 @@ @Test void registerWithEmptyArray() { - var registry = ListenerRegistry.create(l -> l.get(0)); + var registry = ListenerRegistry.create(l -> l.getFirst()); var exception = assertThrows(PreconditionViolationException.class, registry::addAll); @@ -38,7 +38,7 @@ @Test void registerWithArrayContainingNullElements() { - var registry = ListenerRegistry.create(l -> l.get(0)); + var registry = ListenerRegistry.create(l -> l.getFirst()); var exception = assertThrows(PreconditionViolationException.class, () -> registry.addAll(new Object[] { null })); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StoreSharingTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StoreSharingTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StoreSharingTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StoreSharingTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.launcher.core; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.ExecutionRequest; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.fakes.TestEngineSpy; +import org.junit.platform.fakes.TestEngineStub; +import org.junit.platform.launcher.Launcher; +import org.junit.platform.launcher.LauncherDiscoveryRequest; + +/** + * @since 5.13 + */ +class StoreSharingTests { + + @Test + void twoDummyEnginesUseRequestLevelStore() { + TestEngineSpy engineWriter = new TestEngineSpy("Writer") { + @Override + public void execute(ExecutionRequest request) { + request.getStore().put(Namespace.GLOBAL, "sharedKey", "Hello from Writer"); + super.execute(request); + } + }; + + TestEngineStub engineReader = new TestEngineStub("Reader") { + @Override + public void execute(ExecutionRequest request) { + Object value = request.getStore().get(Namespace.GLOBAL, "sharedKey"); + assertEquals("Hello from Writer", value); + super.execute(request); + } + }; + + ExecutionRequest request = mock(ExecutionRequest.class); + when(request.getStore()).thenReturn(NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStore()); + + Launcher launcher = LauncherFactory.create( // + LauncherConfig.builder() // + .addTestEngines(engineWriter, engineReader) // + .build()); + + LauncherDiscoveryRequest discoveryRequest = LauncherDiscoveryRequestBuilder // + .request() // + .build(); + + launcher.execute(discoveryRequest); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,6 +20,7 @@ import java.io.PrintStream; import java.util.stream.IntStream; +import org.junit.jupiter.api.AutoClose; import org.junit.jupiter.api.Test; /** @@ -27,17 +28,19 @@ */ class StreamInterceptorTests { - private ByteArrayOutputStream originalOut = new ByteArrayOutputStream(); - private PrintStream targetStream = new PrintStream(originalOut); + final ByteArrayOutputStream originalOut = new ByteArrayOutputStream(); + PrintStream targetStream = new PrintStream(originalOut); + + @AutoClose + StreamInterceptor streamInterceptor; @Test void interceptsWriteOperationsToStreamPerThread() { - var streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, + streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, 3).orElseThrow(RuntimeException::new); // @formatter:off IntStream.range(0, 1000) .parallel() - .peek(i -> targetStream.println(i)) .mapToObj(String::valueOf) .peek(i -> streamInterceptor.capture()) .peek(i -> targetStream.println(i)) @@ -49,7 +52,7 @@ void unregisterRestoresOriginalStream() { var originalStream = targetStream; - var streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, + streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, 3).orElseThrow(RuntimeException::new); assertSame(streamInterceptor, targetStream); @@ -61,8 +64,8 @@ void writeForwardsOperationsToOriginalStream() throws IOException { var originalStream = targetStream; - StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, 2).orElseThrow( - RuntimeException::new); + streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, + 2).orElseThrow(RuntimeException::new); assertNotSame(originalStream, targetStream); targetStream.write('a'); @@ -73,7 +76,7 @@ @Test void handlesNestedCaptures() { - var streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, + streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, 100).orElseThrow(RuntimeException::new); String outermost, inner, innermost; @@ -100,4 +103,19 @@ () -> assertEquals("innermost", innermost) // ); } + + @Test + void capturesOutputFromNonTestThreads() throws Exception { + streamInterceptor = StreamInterceptor.register(targetStream, newStream -> this.targetStream = newStream, + 100).orElseThrow(RuntimeException::new); + + streamInterceptor.capture(); + var thread = new Thread(() -> { + targetStream.println("from non-test thread"); + }); + thread.start(); + thread.join(); + + assertEquals("from non-test thread", streamInterceptor.consume().trim()); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/AnotherUnusedTestExecutionListener.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/AnotherUnusedTestExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/AnotherUnusedTestExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/AnotherUnusedTestExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/LoggingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/LoggingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/LoggingListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/LoggingListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/NoopTestExecutionListener.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/NoopTestExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/NoopTestExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/NoopTestExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/OutputDirTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/OutputDirTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/OutputDirTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/OutputDirTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,77 +10,92 @@ package org.junit.platform.launcher.listeners; +import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.InstanceOfAssertFactories.STRING; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Optional; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.launcher.LauncherConstants; class OutputDirTests { + @TempDir + Path cwd; + @Test void getOutputDirUsesCustomOutputDir() throws Exception { - String customDir = "build/UniqueIdTrackingListenerIntegrationTests"; - Path outputDir = OutputDir.create(Optional.of(customDir)).toPath(); - assertThat(Files.isSameFile(Paths.get(customDir), outputDir)).isTrue(); + var customDir = cwd.resolve("custom-dir"); + var outputDir = OutputDir.create(Optional.of(customDir.toAbsolutePath().toString())).toPath(); + assertThat(Files.isSameFile(customDir, outputDir)).isTrue(); assertThat(outputDir).exists(); } @Test + void getOutputDirUsesCustomOutputDirWithPlaceholder() { + var customDir = cwd.resolve("build").resolve("junit-" + LauncherConstants.OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER); + var outputDir = OutputDir.create(Optional.of(customDir.toAbsolutePath().toString())).toPath(); + assertThat(outputDir).exists() // + .hasParent(cwd.resolve("build")) // + .extracting(it -> it.getFileName().toString(), as(STRING)) // + .matches("junit-\\d+"); + } + + @Test void getOutputDirFallsBackToCurrentWorkingDir() throws Exception { - String cwd = "src/test/resources/listeners/uidtracking"; - String expected = cwd; + var expected = cwd; - assertOutputDirIsDetected(cwd, expected); + assertOutputDirIsDetected(expected); } @Test void getOutputDirDetectsMavenPom() throws Exception { - String cwd = "src/test/resources/listeners/uidtracking/maven"; - String expected = cwd + "/target"; + Files.createFile(cwd.resolve("pom.xml")); + var expected = cwd.resolve("target"); - assertOutputDirIsDetected(cwd, expected); + assertOutputDirIsDetected(expected); } @Test void getOutputDirDetectsGradleGroovyDefaultBuildScript() throws Exception { - String cwd = "src/test/resources/listeners/uidtracking/gradle/groovy"; - String expected = cwd + "/build"; + Files.createFile(cwd.resolve("build.gradle")); + var expected = cwd.resolve("build"); - assertOutputDirIsDetected(cwd, expected); + assertOutputDirIsDetected(expected); } @Test void getOutputDirDetectsGradleGroovyCustomBuildScript() throws Exception { - String cwd = "src/test/resources/listeners/uidtracking/gradle/groovy/sub-project"; - String expected = cwd + "/build"; + Files.createFile(cwd.resolve("sub-project.gradle")); + var expected = cwd.resolve("build"); - assertOutputDirIsDetected(cwd, expected); + assertOutputDirIsDetected(expected); } @Test void getOutputDirDetectsGradleKotlinDefaultBuildScript() throws Exception { - String cwd = "src/test/resources/listeners/uidtracking/gradle/kotlin"; - String expected = cwd + "/build"; + Files.createFile(cwd.resolve("build.gradle.kts")); + var expected = cwd.resolve("build"); - assertOutputDirIsDetected(cwd, expected); + assertOutputDirIsDetected(expected); } @Test void getOutputDirDetectsGradleKotlinCustomBuildScript() throws Exception { - String cwd = "src/test/resources/listeners/uidtracking/gradle/kotlin/sub-project"; - String expected = cwd + "/build"; + Files.createFile(cwd.resolve("sub-project.gradle.kts")); + var expected = cwd.resolve("build"); - assertOutputDirIsDetected(cwd, expected); + assertOutputDirIsDetected(expected); } - private void assertOutputDirIsDetected(String cwd, String expected) throws IOException { - Path outputDir = OutputDir.createSafely(Optional.empty(), () -> Paths.get(cwd)).toPath(); - assertThat(Files.isSameFile(Paths.get(expected), outputDir)).isTrue(); + private void assertOutputDirIsDetected(Path expected) throws IOException { + var outputDir = OutputDir.createSafely(Optional.empty(), () -> cwd).toPath(); + assertThat(Files.isSameFile(expected, outputDir)).isTrue(); assertThat(outputDir).exists(); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -16,6 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.platform.commons.test.ConcurrencyTestingUtils.executeConcurrently; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.mock; import java.io.PrintWriter; @@ -39,7 +40,7 @@ class SummaryGenerationTests { private final SummaryGeneratingListener listener = new SummaryGeneratingListener(); - private final TestPlan testPlan = TestPlan.from(List.of(), mock()); + private final TestPlan testPlan = TestPlan.from(true, List.of(), mock(), dummyOutputDirectoryCreator()); @Test void emptyReport() { @@ -148,8 +149,8 @@ listener.testPlanExecutionFinished(testPlan); final var failures = listener.getSummary().getFailures(); assertThat(failures).hasSize(1); - assertThat(failures.get(0).getException()).isEqualTo(failedException); - assertThat(failures.get(0).getTestIdentifier()).isEqualTo(failingTest); + assertThat(failures.getFirst().getException()).isEqualTo(failedException); + assertThat(failures.getFirst().getTestIdentifier()).isEqualTo(failingTest); } @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListenerIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListenerIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListenerIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UniqueIdTrackingListenerIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -23,6 +23,7 @@ import static org.junit.platform.launcher.listeners.UniqueIdTrackingListener.LISTENER_ENABLED_PROPERTY_NAME; import static org.junit.platform.launcher.listeners.UniqueIdTrackingListener.OUTPUT_DIR_PROPERTY_NAME; import static org.junit.platform.launcher.listeners.UniqueIdTrackingListener.OUTPUT_FILE_PREFIX_PROPERTY_NAME; +import static org.junit.platform.launcher.listeners.UniqueIdTrackingListener.WORKING_DIR_PROPERTY_NAME; import static org.junit.platform.testkit.engine.Event.byTestDescriptor; import static org.junit.platform.testkit.engine.EventConditions.abortedWithReason; import static org.junit.platform.testkit.engine.EventConditions.event; @@ -35,7 +36,6 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -44,15 +44,16 @@ import java.util.stream.Stream; import org.assertj.core.api.Condition; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.io.TempDir; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.discovery.ClassSelector; -import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestPlan; @@ -88,6 +89,15 @@ private static final String[] expectedConcurrentUniqueIds = { testA, testB, testC, testD, testE, testF }; + @TempDir + Path workingDir; + + @BeforeEach + void createFakeGradleFiles() throws Exception { + Files.createFile(workingDir.resolve("build.gradle")); + Files.createDirectory(workingDir.resolve("build")); + } + @Test void confirmExpectedUniqueIdsViaEngineTestKit() { // @formatter:off @@ -116,28 +126,18 @@ @Test void listenerIsRegisteredButDisabledByDefault() throws Exception { - long numListenersRegistered = ServiceLoader.load(TestExecutionListener.class).stream()// + var numListenersRegistered = ServiceLoader.load(TestExecutionListener.class).stream()// .filter(provider -> UniqueIdTrackingListener.class.equals(provider.type()))// .count(); assertThat(numListenersRegistered).isEqualTo(1); - String outputDir = "build"; - String prefix = DEFAULT_OUTPUT_FILE_PREFIX; + var actualUniqueIds = executeTests(Map.of()); - deleteFiles(outputDir, prefix); + // Sanity check using the results of our local TestExecutionListener + assertThat(actualUniqueIds).containsExactlyInAnyOrder(expectedUniqueIds); - try { - List actualUniqueIds = executeTests(Map.of()); - - // Sanity check using the results of our local TestExecutionListener - assertThat(actualUniqueIds).containsExactlyInAnyOrder(expectedUniqueIds); - - // Check that files were not generated by the UniqueIdTrackingListener - assertThat(findFiles(outputDir, prefix)).isEmpty(); - } - finally { - deleteFiles(outputDir, prefix); - } + // Check that files were not generated by the UniqueIdTrackingListener + assertThat(findFiles(workingDir, DEFAULT_OUTPUT_FILE_PREFIX)).isEmpty(); } @Test @@ -147,20 +147,20 @@ @Test void verifyUniqueIdsAreTrackedWithCustomOutputFile() throws Exception { - String customPrefix = "test_ids"; + var customPrefix = "test_ids"; verifyUniqueIdsAreTracked("build", customPrefix, Map.of(OUTPUT_FILE_PREFIX_PROPERTY_NAME, customPrefix)); } @Test void verifyUniqueIdsAreTrackedWithCustomOutputDir() throws Exception { - String customDir = "build/UniqueIdTrackingListenerIntegrationTests"; + var customDir = "build/UniqueIdTrackingListenerIntegrationTests"; verifyUniqueIdsAreTracked(customDir, DEFAULT_OUTPUT_FILE_PREFIX, Map.of(OUTPUT_DIR_PROPERTY_NAME, customDir)); } @Test void verifyUniqueIdsAreTrackedWithCustomOutputFileAndCustomOutputDir() throws Exception { - String customPrefix = "test_ids"; - String customDir = "build/UniqueIdTrackingListenerIntegrationTests"; + var customPrefix = "test_ids"; + var customDir = "build/UniqueIdTrackingListenerIntegrationTests"; verifyUniqueIdsAreTracked(customDir, customPrefix, Map.of(OUTPUT_DIR_PROPERTY_NAME, customDir, OUTPUT_FILE_PREFIX_PROPERTY_NAME, customPrefix)); @@ -172,59 +172,45 @@ configurationParameters = new HashMap<>(configurationParameters); configurationParameters.put(LISTENER_ENABLED_PROPERTY_NAME, "true"); - deleteFiles(outputDir, prefix); - - try { - List actualUniqueIds = executeTests(configurationParameters); + var actualUniqueIds = executeTests(configurationParameters); - // Sanity check using the results of our local TestExecutionListener - assertThat(actualUniqueIds).containsExactlyInAnyOrder(expectedUniqueIds); + // Sanity check using the results of our local TestExecutionListener + assertThat(actualUniqueIds).containsExactlyInAnyOrder(expectedUniqueIds); - // Check contents of the file (or files) generated by the UniqueIdTrackingListener - assertThat(readAllFiles(outputDir, prefix)).containsExactlyInAnyOrder(expectedUniqueIds); - } - finally { - deleteFiles(outputDir, prefix); - } + // Check contents of the file (or files) generated by the UniqueIdTrackingListener + assertThat(readAllFiles(workingDir.resolve(outputDir), prefix)).containsExactlyInAnyOrder(expectedUniqueIds); } @Test void verifyUniqueIdsAreTrackedWithConcurrentlyExecutingTestPlans() throws Exception { - String customDir = "build/UniqueIdTrackingListenerIntegrationTests"; - String prefix = DEFAULT_OUTPUT_FILE_PREFIX; + var customDir = workingDir.resolve("build/UniqueIdTrackingListenerIntegrationTests"); + var prefix = DEFAULT_OUTPUT_FILE_PREFIX; Map configurationParameters = new HashMap<>(); configurationParameters.put(LISTENER_ENABLED_PROPERTY_NAME, "true"); - configurationParameters.put(OUTPUT_DIR_PROPERTY_NAME, customDir); - - deleteFiles(customDir, prefix); + configurationParameters.put(OUTPUT_DIR_PROPERTY_NAME, customDir.toAbsolutePath().toString()); - try { - Stream.of(TestCase2.class, TestCase3.class, TestCase4.class).parallel()// - .forEach(clazz -> executeTests(configurationParameters, selectClass(clazz))); + Stream.of(TestCase2.class, TestCase3.class, TestCase4.class).parallel()// + .forEach(clazz -> executeTests(configurationParameters, selectClass(clazz))); - // 3 output files should have been generated. - assertThat(findFiles(customDir, prefix)).hasSize(3); + // 3 output files should have been generated. + assertThat(findFiles(customDir, prefix)).hasSize(3); - // Check contents of the file (or files) generated by the UniqueIdTrackingListener - assertThat(readAllFiles(customDir, prefix)).containsExactlyInAnyOrder(expectedConcurrentUniqueIds); - } - finally { - deleteFiles(customDir, prefix); - } + // Check contents of the file (or files) generated by the UniqueIdTrackingListener + assertThat(readAllFiles(customDir, prefix)).containsExactlyInAnyOrder(expectedConcurrentUniqueIds); } - private static List executeTests(Map configurationParameters) { + private List executeTests(Map configurationParameters) { return executeTests(configurationParameters, selectClasses()); } - private static List executeTests(Map configurationParameters, - ClassSelector... classSelectors) { + private List executeTests(Map configurationParameters, ClassSelector... classSelectors) { List uniqueIds = new ArrayList<>(); - LauncherDiscoveryRequest request = request()// + var request = request()// .selectors(classSelectors)// .filters(includeEngines("junit-jupiter"))// .configurationParameters(configurationParameters)// + .configurationParameter(WORKING_DIR_PROPERTY_NAME, workingDir.toAbsolutePath().toString())// .build(); LauncherFactory.create().execute(request, new TestExecutionListener() { @@ -260,8 +246,7 @@ selectClass(DisabledTestCase.class) }; } - private static Stream findFiles(String dir, String prefix) throws IOException { - Path outputDir = Paths.get(dir); + private static Stream findFiles(Path outputDir, String prefix) throws IOException { if (!Files.exists(outputDir)) { return Stream.empty(); } @@ -270,18 +255,7 @@ && path.getFileName().toString().startsWith(prefix))); } - private void deleteFiles(String outputDir, String prefix) throws IOException { - findFiles(outputDir, prefix).forEach(file -> { - try { - Files.deleteIfExists(file); - } - catch (IOException ex) { - throw new UncheckedIOException(ex); - } - }); - } - - private Stream readAllFiles(String outputDir, String prefix) throws IOException { + private Stream readAllFiles(Path outputDir, String prefix) throws IOException { return findFiles(outputDir, prefix).map(outputFile -> { try { return Files.readAllLines(outputFile); @@ -294,6 +268,7 @@ // ------------------------------------------------------------------------- + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase1 { @Test @@ -305,6 +280,7 @@ void skippedTest() { } + @SuppressWarnings("DataFlowIssue") @Test void abortedTest() { assumeTrue(false); @@ -321,6 +297,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase2 { @Test @@ -332,6 +309,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase3 { @Test @@ -343,6 +321,7 @@ } } + @SuppressWarnings("JUnitMalformedDeclaration") static class TestCase4 { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UnusedTestExecutionListener.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UnusedTestExecutionListener.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UnusedTestExecutionListener.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/UnusedTestExecutionListener.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbortOnFailureLauncherDiscoveryListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,9 +11,7 @@ package org.junit.platform.launcher.listeners.discovery; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly.createLauncher; @@ -26,51 +24,7 @@ import org.junit.platform.engine.UniqueId; import org.junit.platform.fakes.TestEngineStub; -class AbortOnFailureLauncherDiscoveryListenerTests extends AbstractLauncherDiscoveryListenerTests { - - @Test - void abortsDiscoveryOnUnresolvedUniqueIdSelectorWithEnginePrefix() { - var engine = createEngineThatCannotResolveAnything("some-engine"); - var request = request() // - .listeners(abortOnFailure()) // - .selectors(selectUniqueId(UniqueId.forEngine(engine.getId()))) // - .build(); - var launcher = createLauncher(engine); - - var exception = assertThrows(JUnitException.class, () -> launcher.discover(request)); - assertThat(exception).hasMessage("TestEngine with ID 'some-engine' failed to discover tests"); - assertThat(exception.getCause()).hasMessage( - "UniqueIdSelector [uniqueId = [engine:some-engine]] could not be resolved"); - } - - @Test - void doesNotAbortDiscoveryOnUnresolvedUniqueIdSelectorWithoutEnginePrefix() { - var engine = createEngineThatCannotResolveAnything("some-engine"); - var request = request() // - .listeners(abortOnFailure()) // - .selectors(selectUniqueId(UniqueId.forEngine("some-other-engine"))) // - .build(); - var launcher = createLauncher(engine); - - assertDoesNotThrow(() -> launcher.discover(request)); - } - - @Test - void abortsDiscoveryOnSelectorResolutionFailure() { - var rootCause = new RuntimeException(); - var engine = createEngineThatFailsToResolveAnything("some-engine", rootCause); - var request = request() // - .listeners(abortOnFailure()) // - .selectors(selectClass(Object.class)) // - .build(); - var launcher = createLauncher(engine); - - var exception = assertThrows(JUnitException.class, () -> launcher.discover(request)); - assertThat(exception).hasMessage("TestEngine with ID 'some-engine' failed to discover tests"); - assertThat(exception.getCause()) // - .hasMessageEndingWith("resolution failed") // - .hasCauseReference(rootCause); - } +class AbortOnFailureLauncherDiscoveryListenerTests { @Test void abortsDiscoveryOnEngineDiscoveryFailure() { @@ -90,7 +44,7 @@ var exception = assertThrows(JUnitException.class, () -> launcher.discover(request)); assertThat(exception) // .hasMessage("TestEngine with ID 'some-engine' failed to discover tests") // - .hasCauseReference(rootCause); + .cause().isSameAs(rootCause); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbstractLauncherDiscoveryListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbstractLauncherDiscoveryListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbstractLauncherDiscoveryListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/AbstractLauncherDiscoveryListenerTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.launcher.listeners.discovery; - -import org.junit.platform.engine.DiscoverySelector; -import org.junit.platform.engine.EngineDiscoveryRequest; -import org.junit.platform.engine.SelectorResolutionResult; -import org.junit.platform.engine.TestDescriptor; -import org.junit.platform.engine.UniqueId; -import org.junit.platform.engine.support.descriptor.EngineDescriptor; -import org.junit.platform.fakes.TestEngineStub; - -abstract class AbstractLauncherDiscoveryListenerTests { - - protected TestEngineStub createEngineThatCannotResolveAnything(String engineId) { - return new TestEngineStub(engineId) { - @Override - public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { - discoveryRequest.getSelectorsByType(DiscoverySelector.class) // - .forEach(selector -> discoveryRequest.getDiscoveryListener().selectorProcessed(uniqueId, - selector, SelectorResolutionResult.unresolved())); - return new EngineDescriptor(uniqueId, "Some Engine"); - } - }; - } - - protected TestEngineStub createEngineThatFailsToResolveAnything(String engineId, RuntimeException rootCause) { - return new TestEngineStub(engineId) { - @Override - public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { - discoveryRequest.getSelectorsByType(DiscoverySelector.class) // - .forEach(selector -> discoveryRequest.getDiscoveryListener().selectorProcessed(uniqueId, - selector, SelectorResolutionResult.failed(rootCause))); - return new EngineDescriptor(uniqueId, "Some Engine"); - } - }; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/CompositeLauncherDiscoveryListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,6 +17,8 @@ import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.SelectorResolutionResult; import org.junit.platform.engine.UniqueId; import org.junit.platform.launcher.EngineDiscoveryResult; @@ -36,20 +38,28 @@ var engineDiscoveryResult = EngineDiscoveryResult.successful(); var selector = selectUniqueId(engineId); var selectorResolutionResult = SelectorResolutionResult.resolved(); + var discoveryIssue = DiscoveryIssue.create(Severity.WARNING, "message"); var composite = new CompositeLauncherDiscoveryListener(List.of(firstListener, secondListener)); composite.launcherDiscoveryStarted(launcherDiscoveryRequest); composite.engineDiscoveryStarted(engineId); composite.selectorProcessed(engineId, selector, selectorResolutionResult); + composite.issueEncountered(engineId, discoveryIssue); composite.engineDiscoveryFinished(engineId, engineDiscoveryResult); composite.launcherDiscoveryFinished(launcherDiscoveryRequest); InOrder inOrder = inOrder(firstListener, secondListener); + inOrder.verify(firstListener).launcherDiscoveryStarted(launcherDiscoveryRequest); inOrder.verify(secondListener).launcherDiscoveryStarted(launcherDiscoveryRequest); inOrder.verify(firstListener).engineDiscoveryStarted(engineId); inOrder.verify(secondListener).engineDiscoveryStarted(engineId); + + inOrder.verify(firstListener).selectorProcessed(engineId, selector, selectorResolutionResult); inOrder.verify(secondListener).selectorProcessed(engineId, selector, selectorResolutionResult); + inOrder.verify(firstListener).issueEncountered(engineId, discoveryIssue); + inOrder.verify(secondListener).issueEncountered(engineId, discoveryIssue); + inOrder.verify(secondListener).engineDiscoveryFinished(engineId, engineDiscoveryResult); inOrder.verify(firstListener).engineDiscoveryFinished(engineId, engineDiscoveryResult); inOrder.verify(secondListener).launcherDiscoveryFinished(launcherDiscoveryRequest); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/discovery/LoggingLauncherDiscoveryListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; +import static org.junit.platform.fakes.FaultyTestEngines.createEngineThatCannotResolveAnything; +import static org.junit.platform.fakes.FaultyTestEngines.createEngineThatFailsToResolveAnything; +import static org.junit.platform.launcher.LauncherConstants.DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly.createLauncher; @@ -29,14 +32,16 @@ import org.junit.platform.fakes.TestEngineStub; @TrackLogRecords -public class LoggingLauncherDiscoveryListenerTests extends AbstractLauncherDiscoveryListenerTests { +public class LoggingLauncherDiscoveryListenerTests { @Test void logsWarningOnUnresolvedUniqueIdSelectorWithEnginePrefix(LogRecordListener log) { var engine = createEngineThatCannotResolveAnything("some-engine"); var request = request() // + .configurationParameter(DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME, "execution") // .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging") // .selectors(selectUniqueId(UniqueId.forEngine(engine.getId()))) // + .enableImplicitConfigurationParameters(false) // .build(); var launcher = createLauncher(engine); @@ -54,6 +59,7 @@ var request = request() // .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging") // .selectors(selectUniqueId(UniqueId.forEngine("some-other-engine"))) // + .enableImplicitConfigurationParameters(false) // .build(); var launcher = createLauncher(engine); @@ -70,8 +76,10 @@ var rootCause = new RuntimeException(); var engine = createEngineThatFailsToResolveAnything("some-engine", rootCause); var request = request() // + .configurationParameter(DISCOVERY_ISSUE_FAILURE_PHASE_PROPERTY_NAME, "execution") // .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging") // .selectors(selectClass(Object.class)) // + .enableImplicitConfigurationParameters(false) // .build(); var launcher = createLauncher(engine); @@ -95,6 +103,7 @@ var request = request() // .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging") // .selectors(selectUniqueId(UniqueId.forEngine(engine.getId()))) // + .enableImplicitConfigurationParameters(false) // .build(); var launcher = createLauncher(engine); @@ -111,6 +120,7 @@ var request = request() // .configurationParameter(DEFAULT_DISCOVERY_LISTENER_CONFIGURATION_PROPERTY_NAME, "logging") // .selectors(selectUniqueId(UniqueId.forEngine(engine.getId()))) // + .enableImplicitConfigurationParameters(false) // .build(); var launcher = createLauncher(engine); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/listeners/session/CompositeLauncherSessionListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserErrorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserErrorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserErrorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserErrorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/ParserTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TagExpressionsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TagExpressionsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TagExpressionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TagExpressionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenizerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenizerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenizerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/launcher/tagexpression/TokenizerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,6 @@ package org.junit.platform.launcher.tagexpression; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import java.util.List; @@ -87,7 +86,7 @@ } private List tokenStringsExtractedFrom(String expression) { - return tokensExtractedFrom(expression).map(Token::string).collect(toList()); + return tokensExtractedFrom(expression).map(Token::string).toList(); } private Stream tokensExtractedFrom(String expression) { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,6 +11,7 @@ package org.junit.platform.reporting.legacy; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.mock; import java.util.Set; @@ -71,13 +72,13 @@ } private String getClassName(UniqueId uniqueId) { - var testPlan = TestPlan.from(Set.of(engineDescriptor), mock()); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), mock(), dummyOutputDirectoryCreator()); return LegacyReportingUtils.getClassName(testPlan, testPlan.getTestIdentifier(uniqueId)); } @SuppressWarnings("deprecation") private String getClassNameFromOldLocation(UniqueId uniqueId) { - var testPlan = TestPlan.from(Set.of(engineDescriptor), mock()); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), mock(), dummyOutputDirectoryCreator()); return org.junit.platform.launcher.listeners.LegacyReportingUtils.getClassName(testPlan, testPlan.getTestIdentifier(uniqueId)); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/IncrementingClock.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/IncrementingClock.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/IncrementingClock.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/IncrementingClock.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,6 +19,7 @@ import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly.createLauncher; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.junit.platform.reporting.legacy.xml.XmlReportAssertions.assertValidAccordingToJenkinsSchema; import static org.mockito.Mockito.mock; @@ -370,7 +371,7 @@ var out = new StringWriter(); var listener = new LegacyXmlReportGeneratingListener(reportsDir, new PrintWriter(out)); - listener.testPlanExecutionStarted(TestPlan.from(Set.of(), mock())); + listener.testPlanExecutionStarted(TestPlan.from(true, Set.of(), mock(), dummyOutputDirectoryCreator())); assertThat(out.toString()).containsSubsequence("Could not create reports directory", "FileAlreadyExistsException", "at "); @@ -386,7 +387,8 @@ var out = new StringWriter(); var listener = new LegacyXmlReportGeneratingListener(tempDirectory, new PrintWriter(out)); - listener.testPlanExecutionStarted(TestPlan.from(Set.of(engineDescriptor), mock())); + listener.testPlanExecutionStarted( + TestPlan.from(true, Set.of(engineDescriptor), mock(), dummyOutputDirectoryCreator())); listener.executionFinished(TestIdentifier.from(engineDescriptor), successful()); assertThat(out.toString()).containsSubsequence("Could not write XML report", "Exception", "at "); @@ -397,7 +399,7 @@ var engineDescriptor = new EngineDescriptor(UniqueId.forEngine("engine"), "Engine"); var childUniqueId = UniqueId.root("child", "test"); engineDescriptor.addChild(new TestDescriptorStub(childUniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), mock()); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), mock(), dummyOutputDirectoryCreator()); var out = new StringWriter(); var listener = new LegacyXmlReportGeneratingListener(tempDirectory, new PrintWriter(out)); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportAssertions.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportAssertions.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportAssertions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportAssertions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.platform.engine.TestExecutionResult.failed; import static org.junit.platform.engine.TestExecutionResult.successful; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.mockito.Mockito.mock; import java.time.Clock; @@ -37,7 +38,7 @@ var engineDescriptor = new EngineDescriptor(UniqueId.forEngine("engine"), "Engine"); var childUniqueId = UniqueId.root("child", "test"); engineDescriptor.addChild(new TestDescriptorStub(childUniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); var results = reportData.getResults(testPlan.getTestIdentifier(childUniqueId)); @@ -50,7 +51,7 @@ var engineDescriptor = new EngineDescriptor(UniqueId.forEngine("engine"), "Engine"); var childUniqueId = UniqueId.root("child", "test"); engineDescriptor.addChild(new TestDescriptorStub(childUniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); var failureOfAncestor = failed(new RuntimeException("failed!")); @@ -66,7 +67,7 @@ var engineDescriptor = new EngineDescriptor(UniqueId.forEngine("engine"), "Engine"); var childUniqueId = UniqueId.root("child", "test"); engineDescriptor.addChild(new TestDescriptorStub(childUniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); reportData.markFinished(testPlan.getTestIdentifier(engineDescriptor.getUniqueId()), successful()); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -20,6 +20,7 @@ import static org.junit.platform.engine.TestExecutionResult.successful; import static org.junit.platform.launcher.LauncherConstants.STDERR_REPORT_ENTRY_KEY; import static org.junit.platform.launcher.LauncherConstants.STDOUT_REPORT_ENTRY_KEY; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.junit.platform.reporting.legacy.xml.XmlReportAssertions.assertValidAccordingToJenkinsSchema; import static org.junit.platform.reporting.legacy.xml.XmlReportWriter.ILLEGAL_CHARACTER_REPLACEMENT; import static org.mockito.Mockito.mock; @@ -57,7 +58,7 @@ @Test void writesTestsuiteElementsWithoutTestcaseElementsWithoutAnyTests() throws Exception { - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); @@ -75,7 +76,7 @@ var uniqueId = engineDescriptor.getUniqueId().append("test", "test"); var testDescriptor = new TestDescriptorStub(uniqueId, "successfulTest"); engineDescriptor.addChild(testDescriptor); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); reportData.addReportEntry(TestIdentifier.from(testDescriptor), ReportEntry.from("myKey", "myValue")); @@ -93,7 +94,7 @@ var uniqueId = engineDescriptor.getUniqueId().append("test", "test"); var testDescriptor = new TestDescriptorStub(uniqueId, "successfulTest"); engineDescriptor.addChild(testDescriptor); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); var reportEntry = ReportEntry.from(Map.of( // @@ -122,7 +123,7 @@ void writesEmptySkippedElementForSkippedTestWithoutReason() throws Exception { var uniqueId = engineDescriptor.getUniqueId().append("test", "test"); engineDescriptor.addChild(new TestDescriptorStub(uniqueId, "skippedTest")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); reportData.markSkipped(testPlan.getTestIdentifier(uniqueId), null); @@ -152,7 +153,7 @@ return "failedTest"; } }); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); reportData.markFinished(testPlan.getTestIdentifier(uniqueId), failed(null)); @@ -172,7 +173,7 @@ void omitsMessageAttributeForFailedTestWithThrowableWithoutMessage() throws Exception { var uniqueId = engineDescriptor.getUniqueId().append("test", "test"); engineDescriptor.addChild(new TestDescriptorStub(uniqueId, "failedTest")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); reportData.markFinished(testPlan.getTestIdentifier(uniqueId), failed(new NullPointerException())); @@ -189,7 +190,7 @@ void writesValidXmlEvenIfExceptionMessageContainsCData() throws Exception { var uniqueId = engineDescriptor.getUniqueId().append("test", "test"); engineDescriptor.addChild(new TestDescriptorStub(uniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); var assertionError = new AssertionError(""); @@ -205,7 +206,7 @@ void escapesInvalidCharactersInSystemPropertiesAndExceptionMessages() throws Exception { var uniqueId = engineDescriptor.getUniqueId().append("test", "test"); engineDescriptor.addChild(new TestDescriptorStub(uniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var reportData = new XmlReportData(testPlan, Clock.systemDefaultZone()); var assertionError = new AssertionError("expected: but was: "); @@ -240,7 +241,7 @@ void writesValidXmlForExceptionMessagesContainingLineBreaks() throws Exception { var uniqueId = engineDescriptor.getUniqueId().append("test", "test"); engineDescriptor.addChild(new TestDescriptorStub(uniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), configParams); + var testPlan = TestPlan.from(true, Set.of(engineDescriptor), configParams, dummyOutputDirectoryCreator()); var allWhitespaceCharacters = IntStream.range(0, 0x10000) // .filter(Character::isWhitespace) // diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/JUnitContributorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/JUnitContributorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/JUnitContributorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/JUnitContributorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.reporting.open.xml; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.opentest4j.reporting.tooling.core.htmlreport.DefaultHtmlReportWriter; + +public class JUnitContributorTests { + + @Test + void contributesJUnitSpecificMetadata(@TempDir Path tempDir) throws Exception { + var xmlFile = Files.writeString(tempDir.resolve("report.xml"), + """ + + + + [engine:dummy] + dummy + CONTAINER + + + + + [engine:dummy]/[test:method] + method() + TEST + + + + + + + + + + """); + var htmlReport = tempDir.resolve("report.html"); + + new DefaultHtmlReportWriter().writeHtmlReport(List.of(xmlFile), htmlReport); + + assertThat(htmlReport).content() // + .contains("JUnit metadata") // + .contains("Type").contains("CONTAINER") // + .contains("Unique ID").contains("[engine:dummy]") // + .contains("Legacy reporting name").contains("dummy") // + .contains("Type").contains("TEST") // + .contains("Unique ID").contains("[engine:dummy]/[test:method]") // + .contains("Legacy reporting name").contains("method()"); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,29 +12,44 @@ import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.condition.JRE.JAVA_22; -import static org.junit.jupiter.api.io.CleanupMode.ON_SUCCESS; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; +import static org.junit.platform.launcher.LauncherConstants.CAPTURE_STDERR_PROPERTY_NAME; +import static org.junit.platform.launcher.LauncherConstants.CAPTURE_STDOUT_PROPERTY_NAME; +import static org.junit.platform.launcher.LauncherConstants.OUTPUT_DIR_PROPERTY_NAME; +import static org.junit.platform.launcher.LauncherConstants.OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import static org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly.createLauncher; import static org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener.ENABLED_PROPERTY_NAME; -import static org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener.OUTPUT_DIR_PROPERTY_NAME; +import static org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener.GIT_ENABLED_PROPERTY_NAME; +import static org.junit.platform.reporting.testutil.FileUtils.findPath; -import java.io.IOException; +import java.io.PrintStream; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledForJreRange; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.reporting.FileEntry; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.hierarchical.DemoHierarchicalTestEngine; -import org.opentest4j.reporting.tooling.validator.DefaultValidator; -import org.opentest4j.reporting.tooling.validator.ValidationResult; +import org.junit.platform.tests.process.ProcessResult; +import org.junit.platform.tests.process.ProcessStarter; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.tooling.core.validator.DefaultValidator; +import org.opentest4j.reporting.tooling.core.validator.ValidationResult; import org.xmlunit.assertj3.XmlAssert; import org.xmlunit.placeholder.PlaceholderDifferenceEvaluator; @@ -43,30 +58,65 @@ * * @since 1.9 */ -@DisabledForJreRange(min = JAVA_22, disabledReason = "https://github.com/junit-team/junit5/issues/3594") public class OpenTestReportGeneratingListenerTests { - @TempDir(cleanup = ON_SUCCESS) - Path tempDirectory; + private static final Map NAMESPACE_CONTEXT = Map.of( // + "core", Namespace.REPORTING_CORE.getUri(), // + "e", Namespace.REPORTING_EVENTS.getUri(), // + "git", Namespace.REPORTING_GIT.getUri() // + ); + + private PrintStream originalOut; + private PrintStream originalErr; + + @BeforeEach + void wrapSystemPrintStreams() { + // Work around nesting check in org.junit.platform.launcher.core.StreamInterceptor + originalOut = System.out; + System.setOut(new PrintStream(System.out)); + originalErr = System.err; + System.setErr(new PrintStream(System.err)); + } + + @AfterEach + void restoreSystemPrintStreams() { + System.setOut(originalOut); + System.setErr(originalErr); + } @Test - void writesValidXmlReport() throws Exception { + void writesValidXmlReport(@TempDir Path tempDirectory) throws Exception { var engine = new DemoHierarchicalTestEngine("dummy"); engine.addTest("failingTest", "display<-->Name 😎", (context, descriptor) -> { - var listener = context.request.getEngineExecutionListener(); - listener.reportingEntryPublished(descriptor, ReportEntry.from("key", "value")); + try { + var listener = context.request.getEngineExecutionListener(); + listener.reportingEntryPublished(descriptor, ReportEntry.from("key", "value")); + listener.fileEntryPublished(descriptor, FileEntry.from( + Files.writeString(tempDirectory.resolve("test.txt"), "Hello, world!"), "text/plain")); + System.out.println("Hello, stdout!"); + System.err.println("Hello, stderr!"); + } + catch (Throwable t) { + throw ExceptionUtils.throwAsUncheckedException(t); + } fail("failure message"); }); - executeTests(engine); + executeTests(tempDirectory, engine, tempDirectory.resolve("junit-" + OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER)); - var xmlFile = findXmlReport(); + var xmlFile = findPath(tempDirectory, "glob:**/open-test-report.xml"); + assertThat(tempDirectory.relativize(xmlFile).toString()) // + .matches("junit-\\d+[/\\\\]open-test-report.xml"); assertThat(validate(xmlFile)).isEmpty(); var expected = """ - + ${xmlunit.ignore} ${xmlunit.ignore} @@ -97,6 +147,17 @@ + + + + + + + + + + + @@ -116,24 +177,135 @@ .areIdentical(); } + @ParameterizedTest + @ValueSource(strings = { "https://github.com/junit-team/junit-framework.git", + "git@github.com:junit-team/junit-framework.git" }) + void includesGitInfoWhenEnabled(String originUrl, @TempDir Path tempDirectory) throws Exception { + + assumeTrue(tryExecGit(tempDirectory, "--version").exitCode() == 0, "git not installed"); + execGit(tempDirectory, "init", "--initial-branch=my_branch"); + execGit(tempDirectory, "remote", "add", "origin", originUrl); + + Files.writeString(tempDirectory.resolve("README.md"), "Hello, world!"); + execGit(tempDirectory, "add", "."); + + execGit(tempDirectory, "config", "user.name", "Alice"); + execGit(tempDirectory, "config", "user.email", "alice@example.org"); + execGit(tempDirectory, "commit", "-m", "Initial commit"); + + var engine = new DemoHierarchicalTestEngine("dummy"); + + executeTests(tempDirectory, engine, tempDirectory.resolve("junit-reports")); + + var xmlFile = findPath(tempDirectory, "glob:**/open-test-report.xml"); + assertThat(validate(xmlFile)).isEmpty(); + + assertThatXml(xmlFile) // + .doesNotHaveXPath("/e:events/core:infrastructure/git:repository"); + assertThatXml(xmlFile) // + .doesNotHaveXPath("/e:events/core:infrastructure/git:branch"); + assertThatXml(xmlFile) // + .doesNotHaveXPath("/e:events/core:infrastructure/git:commit"); + assertThatXml(xmlFile) // + .doesNotHaveXPath("/e:events/core:infrastructure/git:status"); + + executeTests(tempDirectory, engine, tempDirectory.resolve("junit-reports"), + Map.of(GIT_ENABLED_PROPERTY_NAME, "true")); + + assertThat(validate(xmlFile)).isEmpty(); + + assertThatXml(xmlFile) // + .valueByXPath("/e:events/core:infrastructure/git:repository/@originUrl") // + .isEqualTo(originUrl); + + assertThatXml(xmlFile) // + .valueByXPath("/e:events/core:infrastructure/git:branch") // + .isEqualTo("my_branch"); + + var commitHash = execGit(tempDirectory, "rev-parse", "--verify", "HEAD").stdOut().trim(); + assertThatXml(xmlFile) // + .valueByXPath("/e:events/core:infrastructure/git:commit") // + .isEqualTo(commitHash); + + assertThatXml(xmlFile) // + .valueByXPath("/e:events/core:infrastructure/git:status/@clean") // + .isEqualTo(false); + + assertThatXml(xmlFile) // + .valueByXPath("/e:events/core:infrastructure/git:status") // + .startsWith("?? junit-reports"); + } + + @ParameterizedTest + @CsvSource(textBlock = """ + https://foo:bar@github.com/junit-team/junit5.git, https://***@github.com/junit-team/junit5.git + https://token@github.com/junit-team/junit5.git, https://***@github.com/junit-team/junit5.git + foo@github.com:junit-team/junit5.git, ***@github.com:junit-team/junit5.git + ssh://foo@github.com:junit-team/junit5.git, ssh://***@github.com:junit-team/junit5.git + git@github.com:junit-team/junit5.git, git@github.com:junit-team/junit5.git + ssh://git@github.com:junit-team/junit5.git, ssh://git@github.com:junit-team/junit5.git + """) + void stripsCredentialsFromOriginUrl(String configuredUrl, String reportedUrl, @TempDir Path tempDirectory) + throws Exception { + + assumeTrue(tryExecGit(tempDirectory, "--version").exitCode() == 0, "git not installed"); + execGit(tempDirectory, "init", "--initial-branch=my_branch"); + execGit(tempDirectory, "remote", "add", "origin", configuredUrl); + + var engine = new DemoHierarchicalTestEngine("dummy"); + + executeTests(tempDirectory, engine, tempDirectory.resolve("junit-reports"), + Map.of(GIT_ENABLED_PROPERTY_NAME, "true")); + + var xmlFile = findPath(tempDirectory, "glob:**/open-test-report.xml"); + assertThat(validate(xmlFile)).isEmpty(); + + assertThatXml(xmlFile) // + .valueByXPath("/e:events/core:infrastructure/git:repository/@originUrl") // + .isEqualTo(reportedUrl); + } + + private static XmlAssert assertThatXml(Path xmlFile) { + return XmlAssert.assertThat(xmlFile) // + .withNamespaceContext(NAMESPACE_CONTEXT); + } + + private static ProcessResult execGit(Path workingDir, String... arguments) throws InterruptedException { + var result = tryExecGit(workingDir, arguments); + assertEquals(0, result.exitCode(), "git " + String.join(" ", arguments) + " failed"); + return result; + } + + private static ProcessResult tryExecGit(Path workingDir, String... arguments) throws InterruptedException { + System.out.println("$ git " + String.join(" ", arguments)); + return new ProcessStarter() // + .executable(Path.of("git")) // + .workingDir(workingDir) // + .addArguments(arguments) // + .startAndWait(); + } + private ValidationResult validate(Path xmlFile) throws URISyntaxException { var catalogUri = requireNonNull(getClass().getResource("catalog.xml")).toURI(); return new DefaultValidator(catalogUri).validate(xmlFile); } - private void executeTests(TestEngine engine) { - var build = request() // + private static void executeTests(Path tempDirectory, TestEngine engine, Path outputDir) { + executeTests(tempDirectory, engine, outputDir, Map.of()); + } + + private static void executeTests(Path tempDirectory, TestEngine engine, Path outputDir, + Map extraConfigurationParameters) { + var request = request() // .selectors(selectUniqueId(UniqueId.forEngine(engine.getId()))) // + .enableImplicitConfigurationParameters(false) // .configurationParameter(ENABLED_PROPERTY_NAME, String.valueOf(true)) // - .configurationParameter(OUTPUT_DIR_PROPERTY_NAME, tempDirectory.toString()) // + .configurationParameter(CAPTURE_STDOUT_PROPERTY_NAME, String.valueOf(true)) // + .configurationParameter(CAPTURE_STDERR_PROPERTY_NAME, String.valueOf(true)) // + .configurationParameter(OUTPUT_DIR_PROPERTY_NAME, outputDir.toString()) // + .configurationParameters(extraConfigurationParameters) // .build(); - createLauncher(engine).execute(build, new OpenTestReportGeneratingListener()); - } - - private Path findXmlReport() throws IOException { - try (var stream = Files.list(tempDirectory)) { - return stream.findAny().orElseThrow(AssertionError::new); - } + createLauncher(engine).execute(request, new OpenTestReportGeneratingListener(tempDirectory)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -22,6 +22,7 @@ import static org.junit.platform.engine.TestExecutionResult.successful; import static org.junit.platform.engine.discovery.ClassNameFilter.STANDARD_INCLUDE_PATTERN; import static org.junit.platform.launcher.core.LauncherFactoryForTestingPurposesOnly.createLauncher; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.dummyOutputDirectoryCreator; import static org.junit.runner.Description.createSuiteDescription; import static org.junit.runner.Description.createTestDescription; import static org.junit.runner.manipulation.Filter.matchMethodDescription; @@ -138,7 +139,7 @@ var filters = request.getFiltersByType(ClassNameFilter.class); assertThat(filters).hasSize(1); - var filter = filters.get(0); + var filter = filters.getFirst(); // Excluded by default assertExcludes(filter, "example.MyClass"); @@ -184,7 +185,7 @@ var filters = request.getFiltersByType(PackageNameFilter.class); assertThat(filters).hasSize(1); - var filter = filters.get(0); + var filter = filters.getFirst(); assertIncludes(filter, "includedpackage1.TestClass"); assertIncludes(filter, "includedpackage2.TestClass"); assertExcludes(filter, "excludedpackage1.TestClass"); @@ -202,7 +203,7 @@ var filters = request.getFiltersByType(PackageNameFilter.class); assertThat(filters).hasSize(1); - var filter = filters.get(0); + var filter = filters.getFirst(); assertIncludes(filter, "includedpackage1.TestClass"); assertExcludes(filter, "excludedpackage1.TestClass"); assertExcludes(filter, "excludedpackage2.TestClass"); @@ -220,7 +221,7 @@ var filters = request.getPostDiscoveryFilters(); assertThat(filters).hasSize(1); - var filter = filters.get(0); + var filter = filters.getFirst(); assertIncludes(filter, testDescriptorWithTags("foo")); assertIncludes(filter, testDescriptorWithTags("bar")); assertExcludes(filter, testDescriptorWithTags("baz")); @@ -238,7 +239,7 @@ var filters = request.getPostDiscoveryFilters(); assertThat(filters).hasSize(1); - var filter = filters.get(0); + var filter = filters.getFirst(); assertExcludes(filter, testDescriptorWithTags("foo")); assertExcludes(filter, testDescriptorWithTags("bar")); assertIncludes(filter, testDescriptorWithTags("baz")); @@ -256,7 +257,7 @@ var filters = request.getPostDiscoveryFilters(); assertThat(filters).hasSize(1); - var filter = filters.get(0); + var filter = filters.getFirst(); assertIncludes(filter, testDescriptorWithTags("foo")); assertIncludes(filter, testDescriptorWithTags("foo", "any_other_tag")); assertExcludes(filter, testDescriptorWithTags("foo", "bar")); @@ -276,7 +277,7 @@ var filters = request.getPostDiscoveryFilters(); assertThat(filters).hasSize(1); - var filter = filters.get(0); + var filter = filters.getFirst(); assertExcludes(filter, testDescriptorWithTags("foo")); assertExcludes(filter, testDescriptorWithTags("foo", "any_other_tag")); assertIncludes(filter, testDescriptorWithTags("foo", "bar")); @@ -308,7 +309,7 @@ assertIncludes(includeFilter, bazEngine); assertExcludes(includeFilter, quuxEngine); - var excludeFilter = filters.get(0); + var excludeFilter = filters.getFirst(); assertIncludes(excludeFilter, fooEngine); assertExcludes(excludeFilter, barEngine); assertIncludes(excludeFilter, bazEngine); @@ -465,7 +466,7 @@ TestDescriptor container2 = new TestDescriptorStub(UniqueId.root("root", "container2"), "container2"); container2.addChild(new TestDescriptorStub(UniqueId.root("root", "test2a"), "test2a")); container2.addChild(new TestDescriptorStub(UniqueId.root("root", "test2b"), "test2b")); - var testPlan = TestPlan.from(List.of(container1, container2), mock()); + var testPlan = TestPlan.from(true, List.of(container1, container2), mock(), dummyOutputDirectoryCreator()); var launcher = mock(Launcher.class); when(launcher.discover(any())).thenReturn(testPlan); @@ -512,11 +513,13 @@ TestDescriptor originalParent2 = new TestDescriptorStub(UniqueId.root("root", "parent2"), "parent2"); originalParent2.addChild(new TestDescriptorStub(UniqueId.root("root", "leaf2a"), "leaf2a")); originalParent2.addChild(new TestDescriptorStub(UniqueId.root("root", "leaf2b"), "leaf2b")); - var fullTestPlan = TestPlan.from(List.of(originalParent1, originalParent2), configParams); + var fullTestPlan = TestPlan.from(true, List.of(originalParent1, originalParent2), configParams, + dummyOutputDirectoryCreator()); TestDescriptor filteredParent = new TestDescriptorStub(UniqueId.root("root", "parent2"), "parent2"); filteredParent.addChild(new TestDescriptorStub(UniqueId.root("root", "leaf2b"), "leaf2b")); - var filteredTestPlan = TestPlan.from(Set.of(filteredParent), configParams); + var filteredTestPlan = TestPlan.from(true, Set.of(filteredParent), configParams, + dummyOutputDirectoryCreator()); var launcher = mock(Launcher.class); var captor = ArgumentCaptor.forClass(LauncherDiscoveryRequest.class); @@ -538,8 +541,8 @@ @Test void throwsNoTestsRemainExceptionWhenNoTestIdentifierMatchesFilter() { - var testPlan = TestPlan.from(Set.of(new TestDescriptorStub(UniqueId.root("root", "test"), "test")), - configParams); + var testPlan = TestPlan.from(true, Set.of(new TestDescriptorStub(UniqueId.root("root", "test"), "test")), + configParams, dummyOutputDirectoryCreator()); var launcher = mock(Launcher.class); when(launcher.discover(any())).thenReturn(testPlan); @@ -694,7 +697,7 @@ List children = platformRunner.getDescription().getChildren(); assertEquals(1, children.size()); - var engineDescription = children.get(0); + var engineDescription = children.getFirst(); assertEquals("dummy", engineDescription.getDisplayName()); var containerDescription = getOnlyElement(engineDescription.getChildren()); @@ -730,7 +733,7 @@ List children = platformRunner.getDescription().getChildren(); assertEquals(1, children.size()); - var engineDescription = children.get(0); + var engineDescription = children.getFirst(); assertEquals("dummy", engineDescription.getDisplayName()); var containerDescription = getOnlyElement(engineDescription.getChildren()); @@ -777,7 +780,8 @@ private LauncherDiscoveryRequest instantiateRunnerAndCaptureGeneratedRequest(Class testClass) { var launcher = mock(Launcher.class); var captor = ArgumentCaptor.forClass(LauncherDiscoveryRequest.class); - when(launcher.discover(captor.capture())).thenReturn(TestPlan.from(Set.of(), mock())); + when(launcher.discover(captor.capture())).thenReturn( + TestPlan.from(true, Set.of(), mock(), dummyOutputDirectoryCreator())); new JUnitPlatform(testClass, launcher); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/BeforeAndAfterSuiteTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/BeforeAndAfterSuiteTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/BeforeAndAfterSuiteTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/BeforeAndAfterSuiteTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Named.named; import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.suite.engine.SuiteEngineDescriptor.ENGINE_ID; import static org.junit.platform.suite.engine.testsuites.LifecycleMethodsSuites.FailingAfterSuite; @@ -47,7 +48,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.junit.platform.commons.JUnitException; +import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.suite.api.AfterSuite; import org.junit.platform.suite.api.BeforeSuite; import org.junit.platform.suite.engine.testcases.StatefulTestCase; @@ -192,14 +193,12 @@ @ParameterizedTest(name = "{0}") @MethodSource void invalidBeforeOrAfterSuiteMethod(Class testSuiteClass, Predicate failureMessagePredicate) { - // @formatter:off - executeSuite(testSuiteClass) - .allEvents() - .assertThatEvents() - .haveExactly(1, event( - container(testSuiteClass), - finishedWithFailure(instanceOf(JUnitException.class), message(failureMessagePredicate)))); - // @formatter:on + var results = engineWithSelectedSuite(testSuiteClass).discover(); + + var issue = getOnlyElement(results.getDiscoveryIssues()); + assertThat(issue.severity()).isEqualTo(Severity.ERROR); + assertThat(issue.message()).matches(failureMessagePredicate); + assertThat(issue.source()).containsInstanceOf(org.junit.platform.engine.support.descriptor.MethodSource.class); } private static Stream invalidBeforeOrAfterSuiteMethod() { @@ -219,11 +218,19 @@ private static Arguments invalidBeforeOrAfterSuiteCase(Class suiteClass, String failureMessageStart, String failureMessageEnd) { return arguments(named(suiteClass.getSimpleName(), suiteClass), - (Predicate) s -> s.startsWith(failureMessageStart) && s.endsWith(failureMessageEnd)); + expectedMessage(failureMessageStart, failureMessageEnd)); + } + + private static Predicate expectedMessage(String failureMessageStart, String failureMessageEnd) { + return message -> message.startsWith(failureMessageStart) && message.endsWith(failureMessageEnd); } private static EngineExecutionResults executeSuite(Class suiteClass) { - return EngineTestKit.engine(ENGINE_ID).selectors(selectClass(suiteClass)).execute(); + return engineWithSelectedSuite(suiteClass).execute(); + } + + private static EngineTestKit.Builder engineWithSelectedSuite(Class suiteClass) { + return EngineTestKit.engine(ENGINE_ID).selectors(selectClass(suiteClass)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,9 +10,11 @@ package org.junit.platform.suite.engine; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; import static org.junit.platform.launcher.TagFilter.excludeTags; +import static org.junit.platform.launcher.core.OutputDirectoryCreators.hierarchicalOutputDirectoryCreator; import static org.junit.platform.suite.engine.SuiteEngineDescriptor.ENGINE_ID; import static org.junit.platform.testkit.engine.EventConditions.container; import static org.junit.platform.testkit.engine.EventConditions.displayName; @@ -23,24 +25,44 @@ import static org.junit.platform.testkit.engine.EventConditions.test; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.nio.file.Path; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.EngineExecutionListener; +import org.junit.platform.engine.ExecutionRequest; import org.junit.platform.engine.FilterResult; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.ClassSource; import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; import org.junit.platform.launcher.PostDiscoveryFilter; +import org.junit.platform.launcher.core.NamespacedHierarchicalStoreProviders; import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite; import org.junit.platform.suite.engine.testcases.ConfigurationSensitiveTestCase; import org.junit.platform.suite.engine.testcases.DynamicTestsTestCase; +import org.junit.platform.suite.engine.testcases.ErroneousTestCase; import org.junit.platform.suite.engine.testcases.JUnit4TestsTestCase; import org.junit.platform.suite.engine.testcases.MultipleTestsTestCase; import org.junit.platform.suite.engine.testcases.SingleTestTestCase; import org.junit.platform.suite.engine.testcases.TaggedTestTestCase; import org.junit.platform.suite.engine.testsuites.AbstractSuite; +import org.junit.platform.suite.engine.testsuites.BlankSuiteDisplayNameSuite; import org.junit.platform.suite.engine.testsuites.ConfigurationSuite; import org.junit.platform.suite.engine.testsuites.CyclicSuite; import org.junit.platform.suite.engine.testsuites.DynamicSuite; @@ -49,6 +71,8 @@ import org.junit.platform.suite.engine.testsuites.EmptyDynamicTestWithFailIfNoTestFalseSuite; import org.junit.platform.suite.engine.testsuites.EmptyTestCaseSuite; import org.junit.platform.suite.engine.testsuites.EmptyTestCaseWithFailIfNoTestFalseSuite; +import org.junit.platform.suite.engine.testsuites.ErroneousTestSuite; +import org.junit.platform.suite.engine.testsuites.InheritedSuite; import org.junit.platform.suite.engine.testsuites.MultiEngineSuite; import org.junit.platform.suite.engine.testsuites.MultipleSuite; import org.junit.platform.suite.engine.testsuites.NestedSuite; @@ -57,7 +81,9 @@ import org.junit.platform.suite.engine.testsuites.SelectMethodsSuite; import org.junit.platform.suite.engine.testsuites.SuiteDisplayNameSuite; import org.junit.platform.suite.engine.testsuites.SuiteSuite; +import org.junit.platform.suite.engine.testsuites.SuiteWithErroneousTestSuite; import org.junit.platform.suite.engine.testsuites.ThreePartCyclicSuite; +import org.junit.platform.suite.engine.testsuites.WhitespaceSuiteDisplayNameSuite; import org.junit.platform.testkit.engine.EngineTestKit; /** @@ -65,15 +91,25 @@ */ class SuiteEngineTests { - @Test - void selectClasses() { - // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(SelectClassesSuite.class)) + @TempDir + private Path outputDir; + + @ParameterizedTest + @ValueSource(classes = { SelectClassesSuite.class, InheritedSuite.class }) + void selectClasses(Class suiteClass) { + // @formatter:off + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(suiteClass)); + var testKit = builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .isEmpty(); + + testKit .execute() .testEvents() .assertThatEvents() - .haveExactly(1, event(test(SelectClassesSuite.class.getName()), finishedSuccessfully())) + .haveExactly(1, event(test(suiteClass.getName()), finishedSuccessfully())) .haveExactly(1, event(test(SingleTestTestCase.class.getName()), finishedSuccessfully())); // @formatter:on } @@ -81,8 +117,13 @@ @Test void selectMethods() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(SelectMethodsSuite.class)) + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(SelectMethodsSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .isEmpty(); + + testKit .execute() .testEvents() .assertThatEvents() @@ -106,8 +147,13 @@ @Test void abstractSuiteIsNotExecuted() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(AbstractSuite.class)) + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(AbstractSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .isEmpty(); + + testKit .execute() .testEvents() .assertThatEvents() @@ -118,8 +164,18 @@ @Test void privateSuiteIsNotExecuted() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(PrivateSuite.class)) + var message = "@Suite class '%s' must not be private. It will not be executed." + .formatted(PrivateSuite.class.getName()); + var issue = DiscoveryIssue.builder(Severity.WARNING, message) + .source(ClassSource.from(PrivateSuite.class)) + .build(); + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(PrivateSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .containsExactly(issue); + + testKit .execute() .testEvents() .assertThatEvents() @@ -128,10 +184,86 @@ } @Test - void innerSuiteIsNotExecuted() { + void abstractPrivateSuiteIsNotExecuted() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(InnerSuite.class)) + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(AbstractPrivateSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .isEmpty(); + + testKit + .execute() + .testEvents() + .assertThatEvents() + .isEmpty(); + // @formatter:on + } + + @ParameterizedTest + @ValueSource(classes = { InnerSuite.class, AbstractInnerSuite.class }) + void innerSuiteIsNotExecuted(Class suiteClass) { + // @formatter:off + var message = "@Suite class '%s' must not be an inner class. Did you forget to declare it static? It will not be executed." + .formatted(suiteClass.getName()); + var issue = DiscoveryIssue.builder(Severity.WARNING, message) + .source(ClassSource.from(suiteClass)) + .build(); + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(suiteClass)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .containsExactly(issue); + + testKit + .execute() + .testEvents() + .assertThatEvents() + .isEmpty(); + // @formatter:on + } + + @Test + void localSuiteIsNotExecuted() { + + @Suite + @SelectClasses(names = "org.junit.platform.suite.engine.testcases.SingleTestTestCase") + class LocalSuite { + } + + // @formatter:off + var message = "@Suite class '%s' must not be a local class. It will not be executed." + .formatted(LocalSuite.class.getName()); + var issue = DiscoveryIssue.builder(Severity.WARNING, message) + .source(ClassSource.from(LocalSuite.class)) + .build(); + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(LocalSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .containsExactly(issue); + + testKit + .execute() + .testEvents() + .assertThatEvents() + .isEmpty(); + // @formatter:on + } + + @Test + void anonymousSuiteIsNotExecuted() { + var object = new Object() { + }; + + // @formatter:off + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(object.getClass())); + + assertThat(testKit.discover().getDiscoveryIssues()) + .isEmpty(); + + testKit .execute() .testEvents() .assertThatEvents() @@ -166,8 +298,9 @@ @Test void suiteSuite() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(SuiteSuite.class)) + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(SuiteSuite.class)); + builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)) .execute() .testEvents() .assertThatEvents() @@ -182,8 +315,9 @@ // @formatter:off UniqueId uniqId = UniqueId.forEngine(ENGINE_ID) .append(SuiteTestDescriptor.SEGMENT_TYPE, SelectClassesSuite.class.getName()); - EngineTestKit.engine(ENGINE_ID) - .selectors(selectUniqueId(uniqId)) + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) + .selectors(selectUniqueId(uniqId)); + builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)) .execute() .testEvents() .assertThatEvents() @@ -236,9 +370,10 @@ .append(ClassTestDescriptor.SEGMENT_TYPE, MultipleTestsTestCase.class.getName()) .append(TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); - EngineTestKit.engine(ENGINE_ID) + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) .selectors(selectUniqueId(uniqueId)) - .selectors(selectClass(SelectClassesSuite.class)) + .selectors(selectClass(SelectClassesSuite.class)); + builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)) .execute() .testEvents() .assertThatEvents() @@ -389,8 +524,24 @@ @Test void cyclicSuite() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(CyclicSuite.class)) + var expectedUniqueId = UniqueId.forEngine(ENGINE_ID) + .append(SuiteTestDescriptor.SEGMENT_TYPE, CyclicSuite.class.getName()) + .appendEngine(ENGINE_ID) + .append(SuiteTestDescriptor.SEGMENT_TYPE, CyclicSuite.class.getName()); + var message = "The suite configuration of [%s] resulted in a cycle [%s] and will not be discovered a second time." + .formatted(CyclicSuite.class.getName(), expectedUniqueId); + var issue = DiscoveryIssue.builder(Severity.INFO, message) + .source(ClassSource.from(CyclicSuite.class)) + .build(); + + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(CyclicSuite.class)); + var testKit = builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)); + + assertThat(testKit.discover().getDiscoveryIssues()) + .containsExactly(issue); + + testKit .execute() .allEvents() .assertThatEvents() @@ -415,8 +566,9 @@ @Test void threePartCyclicSuite() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(ThreePartCyclicSuite.PartA.class)) + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(ThreePartCyclicSuite.PartA.class)); + builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)) .execute() .allEvents() .assertThatEvents() @@ -427,8 +579,9 @@ @Test void selectByIdentifier() { // @formatter:off - EngineTestKit.engine(ENGINE_ID) - .selectors(selectClass(SelectByIdentifierSuite.class)) + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(SelectByIdentifierSuite.class)); + builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)) .execute() .testEvents() .assertThatEvents() @@ -437,6 +590,103 @@ // @formatter:on } + @Test + void passesOutputDirectoryCreatorToEnginesInSuite() { + // @formatter:off + EngineTestKit.Builder builder = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(SelectClassesSuite.class)); + builder.outputDirectoryCreator(hierarchicalOutputDirectoryCreator(outputDir)) + .execute() + .testEvents() + .assertThatEvents() + .haveExactly(1, event(test(SingleTestTestCase.class.getName()), finishedSuccessfully())); + // @formatter:on + + assertThat(outputDir).isDirectoryRecursivelyContaining("glob:**/test.txt"); + } + + @Test + void discoveryIssueOfNestedTestEnginesAreReported() throws Exception { + // @formatter:off + var testKit = EngineTestKit.engine(ENGINE_ID) + .selectors(selectClass(SuiteWithErroneousTestSuite.class)); + + var discoveryIssues = testKit.discover().getDiscoveryIssues(); + assertThat(discoveryIssues).hasSize(1); + + var issue = discoveryIssues.getFirst(); + assertThat(issue.message()) // + .startsWith("[junit-jupiter] @BeforeAll method") // + .endsWith(" (via @Suite %s > %s).".formatted(SuiteWithErroneousTestSuite.class.getName(), + ErroneousTestSuite.class.getName())); + + var method = ErroneousTestCase.class.getDeclaredMethod("nonStaticLifecycleMethod"); + assertThat(issue.source()).contains(MethodSource.from(method)); + + testKit + .execute() + .testEvents() + .assertThatEvents() + .isEmpty(); + // @formatter:on + } + + @Suite + @SelectClasses(SingleTestTestCase.class) + abstract private static class AbstractPrivateSuite { + } + + @Test + void suiteEnginePassesRequestLevelStoreToSuiteTestDescriptors() { + UniqueId engineId = UniqueId.forEngine(SuiteEngineDescriptor.ENGINE_ID); + SuiteEngineDescriptor engineDescriptor = new SuiteEngineDescriptor(engineId); + + SuiteTestDescriptor mockDescriptor = mock(SuiteTestDescriptor.class); + engineDescriptor.addChild(mockDescriptor); + + EngineExecutionListener listener = mock(EngineExecutionListener.class); + NamespacedHierarchicalStore requestLevelStore = NamespacedHierarchicalStoreProviders.dummyNamespacedHierarchicalStore(); + + ExecutionRequest request = ExecutionRequest.create(engineDescriptor, listener, + mock(ConfigurationParameters.class), mock(OutputDirectoryCreator.class), requestLevelStore); + + new SuiteTestEngine().execute(request); + + verify(mockDescriptor).execute(same(listener), same(requestLevelStore)); + } + + @Test + void blankSuiteDisplayNameGeneratesWarning() { + var expectedMessage = "@SuiteDisplayName on %s must be declared with a non-blank value.".formatted( + BlankSuiteDisplayNameSuite.class.getName()); + var expectedIssue = DiscoveryIssue.builder(Severity.WARNING, expectedMessage).source( + ClassSource.from(BlankSuiteDisplayNameSuite.class)).build(); + + var testKit = EngineTestKit.engine(ENGINE_ID).selectors(selectClass(BlankSuiteDisplayNameSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()).contains(expectedIssue); + } + + @Test + void whitespaceSuiteDisplayNameGeneratesWarning() { + var expectedMessage = "@SuiteDisplayName on %s must be declared with a non-blank value.".formatted( + WhitespaceSuiteDisplayNameSuite.class.getName()); + var expectedIssue = DiscoveryIssue.builder(Severity.WARNING, expectedMessage).source( + ClassSource.from(WhitespaceSuiteDisplayNameSuite.class)).build(); + + var testKit = EngineTestKit.engine(ENGINE_ID).selectors(selectClass(WhitespaceSuiteDisplayNameSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()).contains(expectedIssue); + } + + @Test + void validSuiteDisplayNameGeneratesNoWarning() { + var testKit = EngineTestKit.engine(ENGINE_ID).selectors(selectClass(SuiteDisplayNameSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()) // + .noneMatch(issue -> issue.message().contains("@SuiteDisplayName")); + } + @Suite @SelectClasses(SingleTestTestCase.class) private static class PrivateSuite { @@ -444,7 +694,12 @@ @Suite @SelectClasses(names = "org.junit.platform.suite.engine.testcases.SingleTestTestCase") - private class InnerSuite { + abstract class AbstractInnerSuite { + } + + @Suite + @SelectClasses(names = "org.junit.platform.suite.engine.testcases.SingleTestTestCase") + class InnerSuite { } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteTestDescriptorTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteTestDescriptorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteTestDescriptorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteTestDescriptorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,21 +11,25 @@ package org.junit.platform.suite.engine; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; +import static org.mockito.Mockito.mock; import java.util.Collections; import java.util.Optional; import java.util.Set; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestReporter; import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor; import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor; -import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.engine.ConfigurationParameters; +import org.junit.platform.engine.OutputDirectoryCreator; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; +import org.junit.platform.launcher.core.OutputDirectoryCreators; import org.junit.platform.suite.api.Suite; import org.junit.platform.suite.engine.testcases.SingleTestTestCase; import org.junit.platform.suite.engine.testsuites.SelectClassesSuite; @@ -40,10 +44,14 @@ final UniqueId jupiterEngineId = suiteId.append("engine", JupiterEngineDescriptor.ENGINE_ID); final UniqueId testClassId = jupiterEngineId.append(ClassTestDescriptor.SEGMENT_TYPE, SingleTestTestCase.class.getName()); - final UniqueId methodId = testClassId.append(TestMethodTestDescriptor.SEGMENT_TYPE, "test()"); + final UniqueId methodId = testClassId.append(TestMethodTestDescriptor.SEGMENT_TYPE, + "test(%s)".formatted(TestReporter.class.getName())); final ConfigurationParameters configurationParameters = new EmptyConfigurationParameters(); - final SuiteTestDescriptor suite = new SuiteTestDescriptor(suiteId, TestSuite.class, configurationParameters); + final OutputDirectoryCreator outputDirectoryCreator = OutputDirectoryCreators.dummyOutputDirectoryCreator(); + final DiscoveryIssueReporter discoveryIssueReporter = DiscoveryIssueReporter.forwarding(mock(), engineId); + final SuiteTestDescriptor suite = new SuiteTestDescriptor(suiteId, TestSuite.class, configurationParameters, + outputDirectoryCreator, mock(), discoveryIssueReporter); @Test void suiteIsEmptyBeforeDiscovery() { @@ -62,7 +70,7 @@ } @Test - void suitDiscoversTestsFromUniqueId() { + void suiteDiscoversTestsFromUniqueId() { suite.addDiscoveryRequestFrom(methodId); suite.discover(); @@ -76,11 +84,9 @@ suite.discover(); assertAll(// - () -> assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> suite.addDiscoveryRequestFrom(SelectClassesSuite.class))// + () -> assertPreconditionViolationFor(() -> suite.addDiscoveryRequestFrom(SelectClassesSuite.class))// .withMessage("discovery request cannot be modified after discovery"), - () -> assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> suite.addDiscoveryRequestFrom(methodId))// + () -> assertPreconditionViolationFor(() -> suite.addDiscoveryRequestFrom(methodId))// .withMessage("discovery request cannot be modified after discovery")); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ConfigurationSensitiveTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ConfigurationSensitiveTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ConfigurationSensitiveTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ConfigurationSensitiveTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/DynamicTestsTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/DynamicTestsTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/DynamicTestsTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/DynamicTestsTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyDynamicTestsTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyDynamicTestsTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyDynamicTestsTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyDynamicTestsTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyTestTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyTestTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyTestTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/EmptyTestTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ErroneousTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ErroneousTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ErroneousTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/ErroneousTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.engine.testcases; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ErroneousTestCase { + + @SuppressWarnings({ "JUnitMalformedDeclaration", "unused" }) + @BeforeAll + void nonStaticLifecycleMethod() { + fail("should not be called"); + } + + @Test + void name() { + fail("should not be called"); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/JUnit4TestsTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/JUnit4TestsTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/JUnit4TestsTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/JUnit4TestsTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/MultipleTestsTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/MultipleTestsTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/MultipleTestsTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/MultipleTestsTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/SingleTestTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/SingleTestTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/SingleTestTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/SingleTestTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,7 +10,11 @@ package org.junit.platform.suite.engine.testcases; +import java.nio.file.Files; + +import org.junit.jupiter.api.MediaType; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestReporter; /** * @since 1.8 @@ -18,6 +22,7 @@ public class SingleTestTestCase { @Test - void test() { + void test(TestReporter testReporter) { + testReporter.publishFile("test.txt", MediaType.TEXT_PLAIN_UTF_8, file -> Files.writeString(file, "test")); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/StatefulTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/StatefulTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/StatefulTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/StatefulTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -24,6 +24,7 @@ public static List callSequence = new ArrayList<>(); + @SuppressWarnings("JUnitMalformedDeclaration") public static class Test1 { @Test @@ -33,6 +34,7 @@ } + @SuppressWarnings("JUnitMalformedDeclaration") public static class Test2 { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/TaggedTestTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/TaggedTestTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/TaggedTestTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testcases/TaggedTestTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/AbstractSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/AbstractSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/AbstractSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/AbstractSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.engine.testsuites; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; +import org.junit.platform.suite.api.SuiteDisplayName; +import org.junit.platform.suite.engine.testcases.SingleTestTestCase; + +/** + * Test suite with blank @SuiteDisplayName to verify validation. + * + * @since 5.14 + */ +@Suite +@SelectClasses(SingleTestTestCase.class) +@SuiteDisplayName("") +public class BlankSuiteDisplayNameSuite { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ConfigurationSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ConfigurationSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ConfigurationSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ConfigurationSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/CyclicSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/CyclicSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/CyclicSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/CyclicSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/DynamicSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/DynamicSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/DynamicSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/DynamicSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyCyclicSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyCyclicSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyCyclicSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyCyclicSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestWithFailIfNoTestFalseSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestWithFailIfNoTestFalseSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestWithFailIfNoTestFalseSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyDynamicTestWithFailIfNoTestFalseSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseWithFailIfNoTestFalseSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseWithFailIfNoTestFalseSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseWithFailIfNoTestFalseSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/EmptyTestCaseWithFailIfNoTestFalseSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ErroneousTestSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ErroneousTestSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ErroneousTestSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ErroneousTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.engine.testsuites; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; +import org.junit.platform.suite.engine.testcases.ErroneousTestCase; + +@Suite +@SelectClasses(ErroneousTestCase.class) +public class ErroneousTestSuite { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/InheritedSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/InheritedSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/InheritedSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/InheritedSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.engine.testsuites; + +public class InheritedSuite extends AbstractSuite { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/LifecycleMethodsSuites.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/LifecycleMethodsSuites.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/LifecycleMethodsSuites.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/LifecycleMethodsSuites.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -29,6 +29,7 @@ * * @since 1.11 */ +@SuppressWarnings("NewClassNamingConvention") public class LifecycleMethodsSuites { @Retention(RetentionPolicy.RUNTIME) diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultiEngineSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultiEngineSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultiEngineSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultiEngineSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultipleSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultipleSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultipleSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/MultipleSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/NestedSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/NestedSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/NestedSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/NestedSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectByIdentifierSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectByIdentifierSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectByIdentifierSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectByIdentifierSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectClassesSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectClassesSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectClassesSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectClassesSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectMethodsSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectMethodsSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectMethodsSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SelectMethodsSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteDisplayNameSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteDisplayNameSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteDisplayNameSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteDisplayNameSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteWithErroneousTestSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteWithErroneousTestSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteWithErroneousTestSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/SuiteWithErroneousTestSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.engine.testsuites; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses(ErroneousTestSuite.class) +public class SuiteWithErroneousTestSuite { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ThreePartCyclicSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ThreePartCyclicSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ThreePartCyclicSuite.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/ThreePartCyclicSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.engine.testsuites; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; +import org.junit.platform.suite.api.SuiteDisplayName; +import org.junit.platform.suite.engine.testcases.SingleTestTestCase; + +/** + * Test suite with whitespace-only @SuiteDisplayName to verify validation. + * + * @since 5.14 + */ +@Suite +@SelectClasses(SingleTestTestCase.class) +@SuiteDisplayName(" ") +public class WhitespaceSuiteDisplayNameSuite { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineDiscoveryResultsIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineDiscoveryResultsIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineDiscoveryResultsIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineDiscoveryResultsIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.testkit.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.platform.engine.DiscoveryIssue; +import org.junit.platform.engine.DiscoveryIssue.Severity; +import org.junit.platform.engine.DiscoverySelector; +import org.junit.platform.engine.EngineDiscoveryRequest; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestEngine; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.fakes.TestEngineStub; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; + +@ParameterizedClass +@EnumSource +record EngineDiscoveryResultsIntegrationTests(TestKitApi testKit) { + + @Test + void returnsEngineDescriptor() { + var results = testKit.discover("junit-jupiter", selectClass(TestCase.class)); + + assertThat(results.getEngineDescriptor().getDisplayName()).isEqualTo("JUnit Jupiter"); + assertThat(getOnlyElement(results.getEngineDescriptor().getChildren()).getSource()) // + .contains(ClassSource.from(TestCase.class)); + } + + @Test + void collectsDiscoveryIssues() { + var issue = DiscoveryIssue.create(Severity.WARNING, "warning"); + var testEngine = new TestEngineStub() { + @Override + public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) { + var listener = discoveryRequest.getDiscoveryListener(); + listener.issueEncountered(uniqueId, issue); + return super.discover(discoveryRequest, uniqueId); + } + }; + + var results = testKit.discover(testEngine); + + assertThat(results.getDiscoveryIssues()).containsExactly(issue); + } + + @SuppressWarnings("JUnitMalformedDeclaration") + static class TestCase { + @Test + void test() { + } + } + + enum TestKitApi { + + STATIC_METHOD { + @Override + EngineDiscoveryResults discover(String engineId, DiscoverySelector selector) { + return EngineTestKit.discover(engineId, newRequest().selectors(selector).build()); + } + + @Override + EngineDiscoveryResults discover(TestEngine testEngine) { + return EngineTestKit.discover(testEngine, newRequest().build()); + } + + private static LauncherDiscoveryRequestBuilder newRequest() { + return request().enableImplicitConfigurationParameters(false); + } + }, + + FLUENT_API { + @Override + EngineDiscoveryResults discover(String engineId, DiscoverySelector selector) { + return EngineTestKit.engine(engineId).selectors(selector).discover(); + } + + @Override + EngineDiscoveryResults discover(TestEngine testEngine) { + return EngineTestKit.engine(testEngine).discover(); + } + }; + + @SuppressWarnings("SameParameterValue") + abstract EngineDiscoveryResults discover(String engineId, DiscoverySelector selector); + + abstract EngineDiscoveryResults discover(TestEngine testEngine); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineTestKitTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineTestKitTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineTestKitTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EngineTestKitTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,7 +11,14 @@ package org.junit.platform.testkit.engine; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.mockito.ArgumentCaptor.forClass; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.util.Optional; import java.util.function.UnaryOperator; @@ -23,7 +30,15 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.reporting.ReportEntry; +import org.junit.platform.engine.support.store.Namespace; +import org.junit.platform.engine.support.store.NamespacedHierarchicalStore; +import org.junit.platform.launcher.LauncherDiscoveryListener; +import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.core.EngineExecutionOrchestrator; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedConstruction; class EngineTestKitTests { @@ -46,6 +61,30 @@ assertThat(value).isEmpty(); } + @Test + @SuppressWarnings("unchecked") + void verifyRequestLevelStoreIsUsedInExecution() { + TestEngine testEngine = mock(TestEngine.class); + when(testEngine.getId()).thenReturn("test-engine"); + + LauncherDiscoveryRequest request = mock(LauncherDiscoveryRequest.class); + when(request.getConfigurationParameters()).thenReturn(mock()); + when(request.getDiscoveryListener()).thenReturn(LauncherDiscoveryListener.NOOP); + + try (MockedConstruction mockedConstruction = mockConstruction( + EngineExecutionOrchestrator.class)) { + EngineTestKit.execute(testEngine, request); + assertThat(mockedConstruction.constructed()).isNotEmpty(); + + EngineExecutionOrchestrator mockOrchestrator = mockedConstruction.constructed().getFirst(); + ArgumentCaptor> storeCaptor = forClass( + NamespacedHierarchicalStore.class); + + verify(mockOrchestrator).execute(any(), any(), storeCaptor.capture()); + assertNotNull(storeCaptor.getValue(), "Request level store should be passed to execute"); + } + } + @ParameterizedTest @CsvSource({ "true, from system property", "false," }) void usesImplicitConfigurationParametersWhenEnabled(boolean enabled, String expectedValue) { @@ -67,6 +106,7 @@ .findFirst(); } + @SuppressWarnings("JUnitMalformedDeclaration") static class ExampleTestCase { @RegisterExtension diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EventsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EventsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EventsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/EventsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -146,7 +146,7 @@ var failures = error.getFailures(); assertEquals(1, failures.size()); - assertEquals(AssertionError.class, failures.get(0).getClass()); + assertEquals(AssertionError.class, failures.getFirst().getClass()); } @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/ExecutionsIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/ExecutionsIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/ExecutionsIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/ExecutionsIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -94,6 +94,7 @@ .assertStatistics(stats -> stats.skipped(1).started(3).succeeded(1).aborted(1).failed(1)); } + @SuppressWarnings("JUnitMalformedDeclaration") static class ExampleTestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/NestedContainerEventConditionTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/NestedContainerEventConditionTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/NestedContainerEventConditionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/NestedContainerEventConditionTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,8 +11,8 @@ package org.junit.platform.testkit.engine; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.testkit.engine.EventConditions.container; import static org.junit.platform.testkit.engine.EventConditions.displayName; @@ -30,7 +30,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; import org.junit.platform.testkit.engine.NestedContainerEventConditionTests.ATestCase.BTestCase; @@ -43,12 +42,10 @@ @Test void preconditions() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> nestedContainer(null))// + assertPreconditionViolationFor(() -> nestedContainer(null))// .withMessage("Class must not be null"); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> nestedContainer(NestedContainerEventConditionTests.class))// + assertPreconditionViolationFor(() -> nestedContainer(NestedContainerEventConditionTests.class))// .withMessage(NestedContainerEventConditionTests.class.getName() + " must be a nested class"); } @@ -123,6 +120,7 @@ // @formatter:on } + @SuppressWarnings("JUnitMalformedDeclaration") static class ATestCase { @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/TestExecutionResultConditionsTests.java jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/TestExecutionResultConditionsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/TestExecutionResultConditionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/java/org/junit/platform/testkit/engine/TestExecutionResultConditionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,13 +11,12 @@ package org.junit.platform.testkit.engine; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.rootCause; import org.assertj.core.api.Condition; import org.junit.jupiter.api.Test; -import org.junit.platform.commons.PreconditionViolationException; /** * Tests for {@link TestExecutionResultConditions}. @@ -34,8 +33,7 @@ @Test void rootCauseFailsForNullThrowable() { - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> rootCauseCondition.matches(null))// + assertPreconditionViolationFor(() -> rootCauseCondition.matches(null))// .withMessage("Throwable must not be null"); } @@ -43,8 +41,7 @@ void rootCauseFailsForThrowableWithoutCause() { Throwable throwable = new Throwable(); - assertThatExceptionOfType(PreconditionViolationException.class)// - .isThrownBy(() -> rootCauseCondition.matches(throwable))// + assertPreconditionViolationFor(() -> rootCauseCondition.matches(throwable))// .withMessage("Throwable does not have a cause"); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/junit-platform.properties jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/junit-platform.properties --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/junit-platform.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/junit-platform.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +junit.jupiter.extensions.autodetection.enabled=true diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/build.gradle jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/build.gradle --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/build.gradle 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/build.gradle 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -// This file is used in tests for the UniqueIdTrackingListener diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/sub-project/sub-project.gradle jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/sub-project/sub-project.gradle --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/sub-project/sub-project.gradle 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/groovy/sub-project/sub-project.gradle 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -// This file is used in tests for the UniqueIdTrackingListener diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -// This file is used in tests for the UniqueIdTrackingListener diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/sub-project/sub-project.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/sub-project/sub-project.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/sub-project/sub-project.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/gradle/kotlin/sub-project/sub-project.gradle.kts 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -// This file is used in tests for the UniqueIdTrackingListener diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/maven/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/maven/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/maven/pom.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/listeners/uidtracking/maven/pom.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/log4j2-test.xml jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/log4j2-test.xml --- jtreg8-8.1+1+ds1/junit5/platform-tests/src/test/resources/log4j2-test.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tests/src/test/resources/log4j2-test.xml 2026-06-21 20:26:05.000000000 +0000 @@ -7,13 +7,17 @@ - + + + + + + - + - diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/platform-tooling-support-tests.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/platform-tooling-support-tests.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/platform-tooling-support-tests.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/platform-tooling-support-tests.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,7 +1,7 @@ import com.gradle.develocity.agent.gradle.internal.test.TestDistributionConfigurationInternal import junitbuild.extensions.capitalized +import junitbuild.extensions.dependencyProject import org.gradle.api.tasks.PathSensitivity.RELATIVE -import org.gradle.jvm.toolchain.internal.NoToolchainAvailableException import org.gradle.kotlin.dsl.support.listFilesOrdered import java.time.Duration @@ -12,13 +12,16 @@ } javaLibrary { - mainJavaVersion = JavaVersion.VERSION_11 + mainJavaVersion = JavaVersion.VERSION_21 } spotless { java { target(files(project.java.sourceSets.map { it.allJava }), "projects/**/*.java") } + format("moduleAndPackageInfo") { + target("projects/**/module-info.java", "projects/**/package-info.java") + } kotlin { target("projects/**/*.kt") } @@ -43,39 +46,24 @@ } dependencies { - implementation(libs.bartholdy) { - because("manage external tool installations") - } implementation(libs.commons.io) { because("moving/deleting directory trees") } - - testImplementation(libs.archunit) { - because("checking the architecture of JUnit 5") - } - testImplementation(libs.apiguardian) { - because("we validate that public classes are annotated") - } - testImplementation(libs.groovy4) { - because("it provides convenience methods to handle process output") - } - testImplementation(libs.bndlib) { - because("parsing OSGi metadata") - } - testRuntimeOnly(libs.slf4j.julBinding) { - because("provide appropriate SLF4J binding") + implementation(projects.platformTests) { + capabilities { + requireFeature("process-starter") + } } - testImplementation(libs.ant) { - because("we reference Ant's main class") + implementation(projects.junitJupiterApi) { + because("it uses the OS enum to support Windows") } - testImplementation(libs.bundles.xmlunit) - testImplementation(testFixtures(projects.junitJupiterApi)) thirdPartyJars(libs.junit4) thirdPartyJars(libs.assertj) thirdPartyJars(libs.apiguardian) thirdPartyJars(libs.hamcrest) thirdPartyJars(libs.opentest4j) + thirdPartyJars(libs.openTestReporting.tooling.spi) thirdPartyJars(libs.jimfs) antJars(platform(projects.junitBom)) @@ -107,7 +95,7 @@ val tempRepoName: String by rootProject // All maven-aware projects must be published to the local temp repository - (mavenizedProjects + projects.junitBom.dependencyProject) + (mavenizedProjects + dependencyProject(projects.junitBom)) .map { project -> project.tasks.named("publishAllPublicationsTo${tempRepoName.capitalized()}Repository") } .forEach { dependsOn(it) } @@ -126,45 +114,120 @@ into(layout.buildDirectory.dir("normalized-repo")) } -tasks.test { - // Opt-out via system property: '-Dplatform.tooling.support.tests.enabled=false' - enabled = System.getProperty("platform.tooling.support.tests.enabled")?.toBoolean() ?: true +val archUnit by testing.suites.registering(JvmTestSuite::class) { + dependencies { + implementation(libs.archunit) { + because("checking the architecture of JUnit 5") + } + implementation(libs.apiguardian) { + because("we validate that public classes are annotated") + } + runtimeOnly.bundle(libs.bundles.log4j) + val modularProjects: List by rootProject + modularProjects.forEach { + implementation(project(it.path)) + } + } - // The following if-block is necessary since Gradle will otherwise - // always publish all mavenizedProjects even if this "test" task - // is not executed. - if (enabled) { - dependsOn(normalizeMavenRepo) - jvmArgumentProviders += MavenRepo(project, normalizeMavenRepo.map { it.destinationDir }) + targets { + all { + testTask.configure { + useJUnitPlatform() + (options as JUnitPlatformOptions).apply { + includeEngines("archunit") + excludeEngines("junit-jupiter") + } + develocity { + testRetry.maxRetries = 0 + testDistribution.enabled = false + predictiveTestSelection.enabled = false + } + } + } } +} - jvmArgumentProviders += JarPath(project, thirdPartyJarsClasspath.get(), "thirdPartyJars") - jvmArgumentProviders += JarPath(project, antJarsClasspath.get(), "antJars") - jvmArgumentProviders += MavenDistribution(project, unzipMavenDistribution, mavenDistributionDir) +tasks.named("checkstyle${archUnit.name.capitalized()}").configure { + config = resources.text.fromFile(checkstyle.configDirectory.file("checkstyleTest.xml")) +} - (options as JUnitPlatformOptions).apply { - includeEngines("archunit") - } +tasks.check { + dependsOn(archUnit) +} + +val test by testing.suites.getting(JvmTestSuite::class) { + dependencies { + implementation(libs.bndlib) { + because("parsing OSGi metadata") + } + runtimeOnly(libs.slf4j.julBinding) { + because("provide appropriate SLF4J binding") + } + implementation(libs.ant) { + because("we reference Ant's main class") + } + implementation.bundle(libs.bundles.xmlunit) + implementation(testFixtures(projects.junitJupiterApi)) + implementation(testFixtures(projects.junitPlatformReporting)) + implementation(libs.snapshotTests.junit5) + implementation(libs.snapshotTests.xml) - inputs.apply { - dir("projects").withPathSensitivity(RELATIVE) - file("${rootDir}/gradle.properties").withPathSensitivity(RELATIVE) - file("${rootDir}/settings.gradle.kts").withPathSensitivity(RELATIVE) - file("${rootDir}/gradlew").withPathSensitivity(RELATIVE) - file("${rootDir}/gradlew.bat").withPathSensitivity(RELATIVE) - dir("${rootDir}/gradle/wrapper").withPathSensitivity(RELATIVE) - dir("${rootDir}/documentation/src/main").withPathSensitivity(RELATIVE) - dir("${rootDir}/documentation/src/test").withPathSensitivity(RELATIVE) } - develocity { - testDistribution { - requirements.add("jdk=8") - this as TestDistributionConfigurationInternal - preferredMaxDuration = Duration.ofMillis(500) + targets { + all { + testTask.configure { + shouldRunAfter(archUnit) + + // Opt-out via system property: '-Dplatform.tooling.support.tests.enabled=false' + enabled = System.getProperty("platform.tooling.support.tests.enabled")?.toBoolean() ?: true + + // The following if-block is necessary since Gradle will otherwise + // always publish all mavenizedProjects even if this "test" task + // is not executed. + if (enabled) { + dependsOn(normalizeMavenRepo) + jvmArgumentProviders += MavenRepo(project, normalizeMavenRepo.map { it.destinationDir }) + } + environment.remove("JAVA_TOOL_OPTIONS") + + jvmArgumentProviders += JarPath(project, thirdPartyJarsClasspath.get(), "thirdPartyJars") + jvmArgumentProviders += JarPath(project, antJarsClasspath.get(), "antJars") + jvmArgumentProviders += MavenDistribution(project, unzipMavenDistribution, mavenDistributionDir) + + inputs.apply { + dir("projects").withPathSensitivity(RELATIVE) + file("${rootDir}/gradle.properties").withPathSensitivity(RELATIVE) + file("${rootDir}/settings.gradle.kts").withPathSensitivity(RELATIVE) + file("${rootDir}/gradlew").withPathSensitivity(RELATIVE) + file("${rootDir}/gradlew.bat").withPathSensitivity(RELATIVE) + dir("${rootDir}/gradle/wrapper").withPathSensitivity(RELATIVE) + dir("${rootDir}/documentation/src/main").withPathSensitivity(RELATIVE) + dir("${rootDir}/documentation/src/test").withPathSensitivity(RELATIVE) + } + + // Disable capturing output since parallel execution is enabled and output of + // external processes happens on non-test threads which can't reliably be + // attributed to the test that started the process. + systemProperty("junit.platform.output.capture.stdout", "false") + systemProperty("junit.platform.output.capture.stderr", "false") + + develocity { + testDistribution { + requirements.add("jdk=8") + this as TestDistributionConfigurationInternal + preferredMaxDuration = Duration.ofMillis(500) + } + } + jvmArgumentProviders += JavaHomeDir(project, 8, develocity.testDistribution.enabled) + jvmArgumentProviders += JavaHomeDir(project, 17, develocity.testDistribution.enabled) + + val gradleJavaVersion = JavaVersion.current().majorVersion.toInt() + jvmArgumentProviders += JavaHomeDir(project, gradleJavaVersion, develocity.testDistribution.enabled) + systemProperty("gradle.java.version", gradleJavaVersion) + } } } - jvmArgumentProviders += JavaHomeDir(project, 8, develocity.testDistribution.enabled) } class MavenRepo(project: Project, @get:Internal val repoDir: Provider) : CommandLineArgumentProvider { @@ -196,7 +259,7 @@ project.javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(version) }.get() - } catch (e: NoToolchainAvailableException) { + } catch (e: Exception) { null } }) diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/build.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/build.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/build.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/build.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/main/java/com/example/project/Calculator.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/main/java/com/example/project/Calculator.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/main/java/com/example/project/Calculator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/main/java/com/example/project/Calculator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package com.example.project; - -public class Calculator { - - public int add(int a, int b) { - return a + b; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/test/java/com/example/project/CalculatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/test/java/com/example/project/CalculatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/test/java/com/example/project/CalculatorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/ant-starter/src/test/java/com/example/project/CalculatorTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package com.example.project; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -class CalculatorTests { - - @Test - @DisplayName("1 + 1 = 2") - void addsTwoNumbers() { - Calculator calculator = new Calculator(); - assertEquals(2, calculator.add(1, 1), "1 + 1 should equal 2"); - } - - @ParameterizedTest(name = "{0} + {1} = {2}") - @CsvSource({ // - "0, 1, 1", // - "1, 2, 3", // - "49, 51, 100", // - "1, 100, 101" // - }) - void add(int first, int second, int expectedResult) { - Calculator calculator = new Calculator(); - assertEquals(expectedResult, calculator.add(first, second), - () -> first + " + " + second + " should equal " + expectedResult); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -3,21 +3,26 @@ id("org.graalvm.buildtools.native") } -val jupiterVersion: String = System.getenv("JUNIT_JUPITER_VERSION") -val platformVersion: String = System.getenv("JUNIT_PLATFORM_VERSION") - -repositories { - maven { url = uri(file(System.getProperty("maven.repo"))) } - mavenCentral() -} +val jupiterVersion: String by project +val platformVersion: String by project +val vintageVersion: String by project dependencies { testImplementation("org.junit.jupiter:junit-jupiter:$jupiterVersion") + testImplementation("junit:junit:4.13.2") + testImplementation("org.junit.platform:junit-platform-suite:$platformVersion") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:$vintageVersion") testRuntimeOnly("org.junit.platform:junit-platform-reporting:$platformVersion") } +tasks.withType().configureEach { + options.release = 21 +} + tasks.test { - useJUnitPlatform() + useJUnitPlatform { + includeEngines("junit-platform-suite") + } val outputDir = reports.junitXml.outputLocation jvmArgumentProviders += CommandLineArgumentProvider { @@ -28,10 +33,16 @@ } } +val initializeAtBuildTime = mapOf>( + // These need to be added to native-build-tools + "6.1" to listOf(), +) + graalvmNative { binaries { named("test") { buildArgs.add("-H:+ReportExceptionStackTraces") + buildArgs.add("--initialize-at-build-time=${initializeAtBuildTime.values.flatten().joinToString(",")}") } } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,11 +1,35 @@ pluginManagement { - plugins { - id("org.graalvm.buildtools.native") version "0.10.1" - } - repositories { - mavenCentral() - gradlePluginPortal() - } + plugins { + // TODO Check if classes can be removed from `initializeAtBuildTime` in build.gradle.kts when upgrading + id("org.graalvm.buildtools.native") version "0.11.1" + } + repositories { + mavenCentral() + gradlePluginPortal() + maven(url = "https://raw.githubusercontent.com/graalvm/native-build-tools/snapshots") { + mavenContent { + snapshotsOnly() + } + } + } +} + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" +} + +dependencyResolutionManagement { + repositories { + repositories { + maven { url = uri(file(System.getProperty("maven.repo"))) } + mavenCentral() + maven(url = "https://raw.githubusercontent.com/graalvm/native-build-tools/snapshots") { + mavenContent { + snapshotsOnly() + } + } + } + } } rootProject.name = "graalvm-starter" diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/main/java/com/example/project/Calculator.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/main/java/com/example/project/Calculator.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/main/java/com/example/project/Calculator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/main/java/com/example/project/Calculator.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.Parameter; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@ParameterizedClass +@ValueSource(ints = { 1, 2 }) +class CalculatorParameterizedClassTests { + + @Parameter + int i; + + @ParameterizedTest + @ValueSource(ints = { 1, 2 }) + void parameterizedTest(int j) { + Calculator calculator = new Calculator(); + assertEquals(i + j, calculator.add(i, j)); + } + + @Nested + @ParameterizedClass + @ValueSource(ints = { 1, 2 }) + @Disabled("https://github.com/junit-team/junit-framework/issues/4440") + class Inner { + + final int j; + + Inner(int j) { + this.j = j; + } + + @Test + void regularTest() { + Calculator calculator = new Calculator(); + assertEquals(i + j, calculator.add(i, j)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/CalculatorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/ClassLevelAnnotationTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/ClassLevelAnnotationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/ClassLevelAnnotationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/ClassLevelAnnotationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,11 +10,14 @@ package com.example.project; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.IndicativeSentencesGeneration; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledInNativeImage; @EnabledInNativeImage +@IndicativeSentencesGeneration(generator = DisplayNameGenerator.ReplaceUnderscores.class) class ClassLevelAnnotationTests { @Nested class Inner { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +import org.junit.platform.suite.api.*; + +@Suite +@SelectPackages("com.example.project") +public class GraalvmSuite { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +import org.junit.Test; + +public class VintageTests { + @Test + public void test() { + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/resources/junit-platform.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/resources/junit-platform.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/resources/junit-platform.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/graalvm-starter/src/test/resources/junit-platform.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +junit.platform.stacktrace.pruning.enabled=false diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.9.0" + kotlin("jvm") version "2.1.21" } repositories { @@ -9,12 +9,19 @@ mavenCentral() } -// grab jupiter version from system environment -val jupiterVersion = System.getenv("JUNIT_JUPITER_VERSION") +val jupiterVersion: String by project +val platformVersion: String by project dependencies { testImplementation(kotlin("stdlib-jdk8")) testImplementation("org.junit.jupiter:junit-jupiter:$jupiterVersion") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:$platformVersion") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } } tasks.withType().configureEach { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/gradle.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/gradle.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/gradle.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/gradle.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +org.gradle.java.installations.fromEnv=JDK8 diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" +} + rootProject.name = "gradle-kotlin-extensions" diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/src/test/kotlin/com/example/project/ExtensionFunctionsTests.kt jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/src/test/kotlin/com/example/project/ExtensionFunctionsTests.kt --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/src/test/kotlin/com/example/project/ExtensionFunctionsTests.kt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-kotlin-extensions/src/test/kotlin/com/example/project/ExtensionFunctionsTests.kt 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -7,6 +7,8 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + + package com.example.project import org.junit.jupiter.api.Assertions.assertEquals diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -2,25 +2,8 @@ java } -// grab jupiter version from system environment -val jupiterVersion: String = System.getenv("JUNIT_JUPITER_VERSION") -val vintageVersion: String = System.getenv("JUNIT_VINTAGE_VERSION") -val platformVersion: String = System.getenv("JUNIT_PLATFORM_VERSION") - -// emit default file encoding to a file -file("file.encoding.txt").writeText(System.getProperty("file.encoding")) - -// emit more Java runtime information -file("java.runtime.txt").writeText(""" -java.version=${System.getProperty("java.version")} -""") - -// emit versions of JUnit groups -file("junit.versions.txt").writeText(""" -jupiterVersion=$jupiterVersion -vintageVersion=$vintageVersion -platformVersion=$platformVersion -""") +val jupiterVersion: String by project +val platformVersion: String by project repositories { maven { url = uri(file(System.getProperty("maven.repo"))) } @@ -31,6 +14,12 @@ testImplementation("org.junit.jupiter:junit-jupiter-api:$jupiterVersion") { exclude(group = "org.junit.jupiter", module = "junit-jupiter-engine") } + testRuntimeOnly("org.junit.platform:junit-platform-launcher:$platformVersion")} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } } tasks.test { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/gradle.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/gradle.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/gradle.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/gradle.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +org.gradle.java.installations.fromEnv=JDK8 diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" +} + rootProject.name = "gradle-missing-engine" diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/src/test/java/FooTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/src/test/java/FooTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/src/test/java/FooTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-missing-engine/src/test/java/FooTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,5 @@ - /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,9 +7,9 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + import static org.junit.jupiter.api.Assertions.fail; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; class FooTests { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -plugins { - java -} - -// grab jupiter version from system environment -val jupiterVersion: String = System.getenv("JUNIT_JUPITER_VERSION") -val vintageVersion: String = System.getenv("JUNIT_VINTAGE_VERSION") -val platformVersion: String = System.getenv("JUNIT_PLATFORM_VERSION") - -repositories { - maven { url = uri(file(System.getProperty("maven.repo"))) } - mavenCentral() -} - -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:$jupiterVersion") - testRuntimeOnly("org.junit.platform:junit-platform-reporting:$platformVersion") -} - -tasks.test { - useJUnitPlatform() - - testLogging { - events("passed", "skipped", "failed") - } - - reports { - html.required = true - } - - val outputDir = reports.junitXml.outputLocation - jvmArgumentProviders += CommandLineArgumentProvider { - listOf( - "-Djunit.platform.reporting.open.xml.enabled=true", - "-Djunit.platform.reporting.output.dir=${outputDir.get().asFile.absolutePath}" - ) - } - - doFirst { - println("Using Java version: ${JavaVersion.current()}") - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/settings.gradle.kts 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -rootProject.name = "gradle-starter" diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/main/java/com/example/project/Calculator.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/main/java/com/example/project/Calculator.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/main/java/com/example/project/Calculator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/main/java/com/example/project/Calculator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package com.example.project; - -public class Calculator { - - public int add(int a, int b) { - return a + b; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/test/java/com/example/project/CalculatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/test/java/com/example/project/CalculatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/test/java/com/example/project/CalculatorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/gradle-starter/src/test/java/com/example/project/CalculatorTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package com.example.project; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -class CalculatorTests { - - @Test - @DisplayName("1 + 1 = 2") - void addsTwoNumbers() { - Calculator calculator = new Calculator(); - assertEquals(2, calculator.add(1, 1), "1 + 1 should equal 2"); - } - - @ParameterizedTest(name = "{0} + {1} = {2}") - @CsvSource({ // - "0, 1, 1", // - "1, 2, 3", // - "49, 51, 100", // - "1, 100, 101" // - }) - void add(int first, int second, int expectedResult) { - Calculator calculator = new Calculator(); - assertEquals(expectedResult, calculator.add(first, second), - () -> first + " + " + second + " should equal " + expectedResult); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt 2026-06-21 20:26:05.000000000 +0000 @@ -2,11 +2,14 @@ exports org.junit.platform.commons exports org.junit.platform.commons.annotation exports org.junit.platform.commons.function +exports org.junit.platform.commons.io exports org.junit.platform.commons.support exports org.junit.platform.commons.support.conversion +exports org.junit.platform.commons.support.scanning requires java.base mandated requires java.logging requires java.management requires org.apiguardian.api static transitive +uses org.junit.platform.commons.support.scanning.ClasspathScanner qualified exports org.junit.platform.commons.logging to org.junit.jupiter.api org.junit.jupiter.engine org.junit.jupiter.migrationsupport org.junit.jupiter.params org.junit.platform.console org.junit.platform.engine org.junit.platform.launcher org.junit.platform.reporting org.junit.platform.runner org.junit.platform.suite.api org.junit.platform.suite.engine org.junit.platform.testkit org.junit.vintage.engine -qualified exports org.junit.platform.commons.util to org.junit.jupiter.api org.junit.jupiter.engine org.junit.jupiter.migrationsupport org.junit.jupiter.params org.junit.platform.console org.junit.platform.engine org.junit.platform.launcher org.junit.platform.reporting org.junit.platform.runner org.junit.platform.suite.api org.junit.platform.suite.commons org.junit.platform.suite.engine org.junit.platform.testkit org.junit.vintage.engine +qualified exports org.junit.platform.commons.util to org.junit.jupiter.api org.junit.jupiter.engine org.junit.jupiter.migrationsupport org.junit.jupiter.params org.junit.platform.console org.junit.platform.engine org.junit.platform.jfr org.junit.platform.launcher org.junit.platform.reporting org.junit.platform.runner org.junit.platform.suite.api org.junit.platform.suite.commons org.junit.platform.suite.engine org.junit.platform.testkit org.junit.vintage.engine diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-console.expected.txt jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-console.expected.txt --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-console.expected.txt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-console.expected.txt 2026-06-21 20:26:05.000000000 +0000 @@ -7,7 +7,8 @@ requires org.junit.platform.reporting provides java.util.spi.ToolProvider with org.junit.platform.console.ConsoleLauncherToolProvider contains org.junit.platform.console +contains org.junit.platform.console.command contains org.junit.platform.console.options +contains org.junit.platform.console.output contains org.junit.platform.console.shadow.picocli -contains org.junit.platform.console.tasks main-class org.junit.platform.console.ConsoleLauncher diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-reporting.expected.txt jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-reporting.expected.txt --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-reporting.expected.txt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-reporting.expected.txt 2026-06-21 20:26:05.000000000 +0000 @@ -8,4 +8,6 @@ requires org.junit.platform.commons requires org.junit.platform.engine transitive requires org.junit.platform.launcher transitive +requires org.opentest4j.reporting.tooling.spi provides org.junit.platform.launcher.TestExecutionListener with org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener +provides org.opentest4j.reporting.tooling.spi.htmlreport.Contributor with org.junit.platform.reporting.open.xml.JUnitContributor diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/pom.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/pom.xml 2026-06-21 20:26:05.000000000 +0000 @@ -9,8 +9,6 @@ UTF-8 - ${env.JUNIT_JUPITER_VERSION} - ${env.JUNIT_PLATFORM_VERSION} @@ -33,7 +31,7 @@ maven-compiler-plugin - 3.8.1 + 3.14.0 1.8 1.8 @@ -41,7 +39,7 @@ maven-surefire-plugin - 2.22.2 + 3.5.3 @@ -53,9 +51,11 @@ file://${maven.repo} true + ignore true + ignore diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/src/test/java/JUnitPlatformCommonsTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/src/test/java/JUnitPlatformCommonsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/src/test/java/JUnitPlatformCommonsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/java-versions/src/test/java/JUnitPlatformCommonsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,5 @@ - /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,6 +7,7 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +plugins { + java +} + +val jupiterVersion: String by project +val platformVersion: String by project + +repositories { + maven { url = uri(file(System.getProperty("maven.repo"))) } + mavenCentral() +} + +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:$jupiterVersion") + testRuntimeOnly("org.junit.platform:junit-platform-reporting:$platformVersion") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(System.getProperty("java.toolchain.version")) + } +} + +tasks.test { + useJUnitPlatform() + + testLogging { + events("passed", "skipped", "failed", "standardOut") + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + } + + reports { + html.required = true + } + + val outputDir = reports.junitXml.outputLocation + jvmArgumentProviders += CommandLineArgumentProvider { + listOf( + "-Djunit.platform.reporting.open.xml.enabled=true", + "-Djunit.platform.reporting.output.dir=${outputDir.get().asFile.absolutePath}" + ) + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.xml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/build.xml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/gradle.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/gradle.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/gradle.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/gradle.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +org.gradle.java.installations.fromEnv=JDK8,JDK17 diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/pom.xml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/pom.xml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,94 @@ + + + 4.0.0 + + com.example + maven-starter + 1.0-SNAPSHOT + + + UTF-8 + 1.8 + ${maven.compiler.source} + ${junit.platform.version} + + + + + org.junit.platform + junit-platform-commons + ${junit.platform.commons.version} + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.platform + junit-platform-reporting + test + + + + + + + org.junit + junit-bom + ${junit.bom.version} + pom + import + + + + + + + + maven-compiler-plugin + 3.14.0 + + + maven-surefire-plugin + 3.5.3 + + + + junit.platform.reporting.open.xml.enabled = true + junit.platform.reporting.output.dir = target/surefire-reports + + + + + + + + + + local-temp + file://${maven.repo} + + true + ignore + + + true + ignore + + + + snapshots-repo + ${snapshot.repo.url} + + true + + + false + + + + + diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/settings.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" +} + +rootProject.name = "gradle-starter" diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/main/java/com/example/project/Calculator.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/main/java/com/example/project/Calculator.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/main/java/com/example/project/Calculator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/main/java/com/example/project/Calculator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +public class Calculator { + + public int add(int a, int b) { + return a + b; + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorParameterizedClassTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.Parameter; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@ParameterizedClass +@ValueSource(ints = { 1, 2 }) +class CalculatorParameterizedClassTests { + + @Parameter + int i; + + @ParameterizedTest + @ValueSource(ints = { 1, 2 }) + void parameterizedTest(int j) { + Calculator calculator = new Calculator(); + assertEquals(i + j, calculator.add(i, j)); + } + + @Nested + @ParameterizedClass + @ValueSource(ints = { 1, 2 }) + class Inner { + + final int j; + + Inner(int j) { + this.j = j; + } + + @Test + void regularTest() { + Calculator calculator = new Calculator(); + assertEquals(i + j, calculator.add(i, j)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/java/com/example/project/CalculatorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class CalculatorTests { + + @BeforeAll + static void printJavaVersion() { + System.out.println("Using Java version: " + System.getProperty("java.specification.version")); + } + + @Test + @DisplayName("1 + 1 = 2") + void addsTwoNumbers() { + Calculator calculator = new Calculator(); + assertEquals(2, calculator.add(1, 1), "1 + 1 should equal 2"); + } + + @ParameterizedTest(name = "{0} + {1} = {2}") + @CsvSource({ // + "0, 1, 1", // + "1, 2, 3", // + "49, 51, 100", // + "1, 100, 101" // + }) + void add(int first, int second, int expectedResult) { + Calculator calculator = new Calculator(); + assertEquals(expectedResult, calculator.add(first, second), + () -> first + " + " + second + " should equal " + expectedResult); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/resources/junit-platform.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/resources/junit-platform.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/resources/junit-platform.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/jupiter-starter/src/test/resources/junit-platform.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,4 @@ +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$ClassName + +junit.platform.stacktrace.pruning.enabled = false diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/pom.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/pom.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ - - - 4.0.0 - - com.example - maven-starter - 1.0-SNAPSHOT - - - UTF-8 - 1.8 - ${maven.compiler.source} - ${env.JUNIT_JUPITER_VERSION} - - - - - org.junit.jupiter - junit-jupiter - test - - - org.junit.platform - junit-platform-reporting - test - - - - - - - org.junit - junit-bom - ${junit.bom.version} - pom - import - - - - - - - - maven-compiler-plugin - 3.8.1 - - - maven-surefire-plugin - 2.22.2 - - - - junit.platform.reporting.open.xml.enabled = true - junit.platform.reporting.output.dir = target/surefire-reports - - - - - - org.codehaus.gmaven - groovy-maven-plugin - 2.1.1 - - - validate - - execute - - - - println("Using Java version: ${java.version}") - - - - - - - - - - - local-temp - file://${maven.repo} - - true - - - true - - - - - diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/main/java/com/example/project/Calculator.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/main/java/com/example/project/Calculator.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/main/java/com/example/project/Calculator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/main/java/com/example/project/Calculator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package com.example.project; - -public class Calculator { - - public int add(int a, int b) { - return a + b; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/test/java/com/example/project/CalculatorTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/test/java/com/example/project/CalculatorTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/test/java/com/example/project/CalculatorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-starter/src/test/java/com/example/project/CalculatorTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package com.example.project; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -class CalculatorTests { - - @Test - @DisplayName("1 + 1 = 2") - void addsTwoNumbers() { - Calculator calculator = new Calculator(); - assertEquals(2, calculator.add(1, 1), "1 + 1 should equal 2"); - } - - @ParameterizedTest(name = "{0} + {1} = {2}") - @CsvSource({ // - "0, 1, 1", // - "1, 2, 3", // - "49, 51, 100", // - "1, 100, 101" // - }) - void add(int first, int second, int expectedResult) { - Calculator calculator = new Calculator(); - assertEquals(expectedResult, calculator.add(first, second), - () -> first + " + " + second + " should equal " + expectedResult); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/pom.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/pom.xml 2026-06-21 20:26:05.000000000 +0000 @@ -11,7 +11,6 @@ UTF-8 1.8 ${maven.compiler.source} - ${env.JUNIT_JUPITER_VERSION} @@ -38,7 +37,7 @@ maven-compiler-plugin - 3.8.1 + 3.14.0 maven-surefire-plugin @@ -60,9 +59,11 @@ file://${maven.repo} true + ignore true + ignore diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/src/test/java/com/example/project/DummyTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/src/test/java/com/example/project/DummyTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/src/test/java/com/example/project/DummyTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/maven-surefire-compatibility/src/test/java/com/example/project/DummyTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,12 +10,7 @@ package com.example.project; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; class DummyTests { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/pom.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/pom.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ - - - 4.0.0 - - platform.tooling.support.tests - multi-release-jar - 1.0-SNAPSHOT - - - UTF-8 - ${env.JUNIT_JUPITER_VERSION} - ${env.JUNIT_VINTAGE_VERSION} - ${env.JUNIT_PLATFORM_VERSION} - - - - - org.junit.jupiter - junit-jupiter-engine - ${junit.jupiter.version} - test - - - org.junit.platform - junit-platform-reporting - ${junit.platform.version} - test - - - - - - - - maven-compiler-plugin - 3.8.1 - - 11 - - - - - - - de.sormuras.junit - junit-platform-maven-plugin - 1.1.5 - true - - JAVA - - true - - - - - - - - - local-temp - file://${maven.repo} - - true - - - true - - - - - diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/JupiterIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/JupiterIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/JupiterIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/JupiterIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package integration; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assumptions.assumeTrue; -import static org.junit.platform.launcher.EngineFilter.includeEngines; -import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; - -import org.junit.jupiter.api.MethodOrderer.Alphanumeric; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.platform.engine.discovery.DiscoverySelectors; -import org.junit.platform.engine.discovery.ModuleSelector; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.launcher.TestPlan; -import org.junit.platform.launcher.core.LauncherFactory; - -@TestMethodOrder(Alphanumeric.class) -class JupiterIntegrationTests { - - @Test - void packageName() { - assertEquals("integration", getClass().getPackageName()); - } - - @Test - void moduleIsNamed() { - assumeTrue(getClass().getModule().isNamed(), "not running on the module-path"); - assertEquals("integration", getClass().getModule().getName()); - } - - @Test - void resolve() { - var selector = DiscoverySelectors.selectClass(getClass()); - var testPlan = LauncherFactory.create().discover( - request().selectors(selector).filters(includeEngines("junit-jupiter")).build()); - - var engine = testPlan.getRoots().iterator().next(); - - assertEquals(1, testPlan.getChildren(engine).size()); // JupiterIntegrationTests.class - assertEquals(3, testPlan.getChildren(testPlan.getChildren(engine).iterator().next()).size()); // 3 test methods - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/ModuleUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/ModuleUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/ModuleUtilsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/default/src/test/java/integration/integration/ModuleUtilsTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package integration; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.lang.module.ModuleDescriptor; -import java.util.List; -import java.util.Set; - -import org.junit.jupiter.api.Test; -import org.junit.platform.commons.PreconditionViolationException; -import org.junit.platform.commons.util.ClassFilter; -import org.junit.platform.commons.util.ModuleUtils; - -/** - * Unit tests for {@link ModuleUtils}. - * - * @since 1.1 - */ -class ModuleUtilsTests { - - @Test - void javaPlatformModuleSystemIsAvailable() { - assertTrue(ModuleUtils.isJavaPlatformModuleSystemAvailable()); - } - - @Test - void findAllNonSystemBootModuleNames() { - Set moduleNames = ModuleUtils.findAllNonSystemBootModuleNames(); - - assertTrue(moduleNames.isEmpty()); - } - - @Test - void findAllClassesInModule() { - ClassFilter modular = ClassFilter.of(name -> name.contains("Module"), type -> true); - List> classes = ModuleUtils.findAllClassesInModule("java.base", modular); - assertFalse(classes.isEmpty()); - assertTrue(classes.contains(Module.class)); - assertTrue(classes.contains(ModuleDescriptor.class)); - } - - @Test - void preconditions() { - Class expected = PreconditionViolationException.class; - assertThrows(expected, () -> ModuleUtils.getModuleName(null)); - assertThrows(expected, () -> ModuleUtils.getModuleVersion(null)); - assertThrows(expected, () -> ModuleUtils.findAllClassesInModule(null, null)); - assertThrows(expected, () -> ModuleUtils.findAllClassesInModule("", null)); - assertThrows(expected, () -> ModuleUtils.findAllClassesInModule(" ", null)); - assertThrows(expected, () -> ModuleUtils.findAllClassesInModule("java.base", null)); - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/pom.xml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/pom.xml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ + + + 4.0.0 + + platform.tooling.support.tests + multi-release-jar + 1.0-SNAPSHOT + + + UTF-8 + + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.junit.platform + junit-platform-reporting + ${junit.platform.version} + test + + + + + + + + maven-compiler-plugin + 3.14.0 + + 11 + + + + + + + de.sormuras.junit + junit-platform-maven-plugin + 1.1.8 + true + + JAVA + + true + + + + + + + + + local-temp + file://${maven.repo} + + true + ignore + + + true + ignore + + + + snapshots-repo + ${snapshot.repo.url} + + true + + + false + + + + + diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/JupiterIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/JupiterIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/JupiterIntegrationTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/JupiterIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package integration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.junit.platform.launcher.EngineFilter.includeEngines; +import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; + +import org.junit.jupiter.api.MethodOrderer.Alphanumeric; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.launcher.core.LauncherFactory; + +@TestMethodOrder(Alphanumeric.class) +class JupiterIntegrationTests { + + @Test + void packageName() { + assertEquals("integration", getClass().getPackageName()); + } + + @Test + void moduleIsNamed() { + assumeTrue(getClass().getModule().isNamed(), "not running on the module-path"); + assertEquals("integration", getClass().getModule().getName()); + } + + @Test + void resolve() { + var selector = DiscoverySelectors.selectClass(getClass()); + var testPlan = LauncherFactory.create().discover( + request().selectors(selector).filters(includeEngines("junit-jupiter")).build()); + + var engine = testPlan.getRoots().iterator().next(); + + assertEquals(1, testPlan.getChildren(engine).size()); // JupiterIntegrationTests.class + assertEquals(3, testPlan.getChildren(testPlan.getChildren(engine).iterator().next()).size()); // 3 test methods + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/ModuleUtilsTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/ModuleUtilsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/ModuleUtilsTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/multi-release-jar/src/test/java/integration/integration/ModuleUtilsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package integration; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.module.ModuleDescriptor; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.scanning.ClassFilter; +import org.junit.platform.commons.util.ModuleUtils; + +/** + * Unit tests for {@link ModuleUtils}. + * + * @since 1.1 + */ +class ModuleUtilsTests { + + @Test + void javaPlatformModuleSystemIsAvailable() { + assertTrue(ModuleUtils.isJavaPlatformModuleSystemAvailable()); + } + + @Test + void findAllNonSystemBootModuleNames() { + Set moduleNames = ModuleUtils.findAllNonSystemBootModuleNames(); + + assertTrue(moduleNames.isEmpty()); + } + + @Test + void findAllClassesInModule() { + ClassFilter modular = ClassFilter.of(name -> name.contains("Module"), type -> true); + List> classes = ModuleUtils.findAllClassesInModule("java.base", modular); + assertFalse(classes.isEmpty()); + assertTrue(classes.contains(Module.class)); + assertTrue(classes.contains(ModuleDescriptor.class)); + } + + @Test + void preconditions() { + Class expected = PreconditionViolationException.class; + assertThrows(expected, () -> ModuleUtils.getModuleName(null)); + assertThrows(expected, () -> ModuleUtils.getModuleVersion(null)); + assertThrows(expected, () -> ModuleUtils.findAllClassesInModule(null, null)); + assertThrows(expected, () -> ModuleUtils.findAllClassesInModule("", null)); + assertThrows(expected, () -> ModuleUtils.findAllClassesInModule(" ", null)); + assertThrows(expected, () -> ModuleUtils.findAllClassesInModule("java.base", null)); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -2,10 +2,8 @@ java } -// grab jupiter version from system environment -val jupiterVersion: String = System.getenv("JUNIT_JUPITER_VERSION") -val vintageVersion: String = System.getenv("JUNIT_VINTAGE_VERSION") -val platformVersion: String = System.getenv("JUNIT_PLATFORM_VERSION") +val jupiterVersion: String by project +val platformVersion: String by project repositories { maven { url = uri(file(System.getProperty("maven.repo"))) } @@ -15,29 +13,23 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter:$jupiterVersion") testImplementation("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion") - testRuntimeOnly("org.junit.platform:junit-platform-reporting:$platformVersion") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:$platformVersion") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } } tasks.test { useJUnitPlatform() testLogging { - events("failed") + events("failed", "standardOut") } reports { html.required = true } - - val outputDir = reports.junitXml.outputLocation - jvmArgumentProviders += CommandLineArgumentProvider { - listOf( - "-Djunit.platform.reporting.open.xml.enabled=true", - "-Djunit.platform.reporting.output.dir=${outputDir.get().asFile.absolutePath}" - ) - } - - doFirst { - println("Using Java version: ${JavaVersion.current()}") - } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/gradle.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/gradle.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/gradle.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/gradle.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +org.gradle.java.installations.fromEnv=JDK8 diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" +} + rootProject.name = "reflection-tests" diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/src/test/java/ReflectionTestCase.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/src/test/java/ReflectionTestCase.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/src/test/java/ReflectionTestCase.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/reflection-tests/src/test/java/ReflectionTestCase.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -17,6 +17,7 @@ import java.util.Arrays; import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor; @@ -31,6 +32,11 @@ class ReflectionTestCase { + @BeforeAll + static void printJavaVersion() { + System.out.println("Using Java version: " + System.getProperty("java.specification.version")); + } + @TestFactory Stream canReadParameters() { return Stream.of(JupiterTestDescriptor.class, ClassBasedTestDescriptor.class, ClassTestDescriptor.class, diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/expected-err.txt jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/expected-err.txt --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/expected-err.txt 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/expected-err.txt 2026-06-21 20:26:05.000000000 +0000 @@ -12,7 +12,7 @@ .+ org.junit.platform.launcher.core.ServiceLoaderRegistry load .+ Loaded LauncherDiscoveryListener instances: .. .+ org.junit.platform.launcher.core.ServiceLoaderRegistry load -.+ Loaded TestExecutionListener instances: .+ +.+ Loaded TestExecutionListener instances: .+ \Q(excluded classes: [])\E .+ org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines .+ Discovered TestEngines: - junit-platform-suite .+ diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/other/OtherwiseNotReferencedClass.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/other/OtherwiseNotReferencedClass.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/other/OtherwiseNotReferencedClass.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/other/OtherwiseNotReferencedClass.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package other; + +public class OtherwiseNotReferencedClass { +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterIntegration.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterIntegration.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterIntegration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterIntegration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -19,6 +19,9 @@ @Test void successful() { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + new other.OtherwiseNotReferencedClass(); + })); } @Test diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterParamsIntegration.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterParamsIntegration.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterParamsIntegration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/JupiterParamsIntegration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/SuiteIntegration.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/SuiteIntegration.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/SuiteIntegration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/SuiteIntegration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/VintageIntegration.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/VintageIntegration.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/VintageIntegration.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/standalone/src/standalone/VintageIntegration.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/build.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/build.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,4 +1,3 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent plugins { @@ -10,15 +9,25 @@ mavenCentral() } +val platformVersion: String by project +val vintageVersion: String by project + dependencies { val junit4Version = System.getProperty("junit4Version", "4.12") testImplementation("junit:junit:$junit4Version") - val vintageVersion = System.getenv("JUNIT_VINTAGE_VERSION") ?: "5.3.2" testImplementation("org.junit.vintage:junit-vintage-engine:$vintageVersion") { exclude(group = "junit") because("we want to override it to test against different versions") } + + testRuntimeOnly("org.junit.platform:junit-platform-launcher:$platformVersion") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } } tasks.test { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/gradle.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/gradle.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/gradle.properties 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/gradle.properties 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +org.gradle.java.installations.fromEnv=JDK8 diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/pom.xml jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/pom.xml --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/pom.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/pom.xml 2026-06-21 20:26:05.000000000 +0000 @@ -11,14 +11,13 @@ UTF-8 1.8 ${maven.compiler.source} - ${env.JUNIT_VINTAGE_VERSION} org.junit.vintage junit-vintage-engine - ${vintageVersion} + ${junit.vintage.version} test @@ -39,11 +38,11 @@ maven-compiler-plugin - 3.8.1 + 3.14.0 maven-surefire-plugin - 2.22.2 + 3.5.3 @@ -54,9 +53,11 @@ file://${maven.repo} true + ignore true + ignore diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" +} + rootProject.name = "vintage" diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,5 @@ - /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -8,12 +7,13 @@ * * https://www.eclipse.org/legal/epl-v20.html */ + import com.example.vintage.VintageTest; import org.junit.Ignore; /** - * Reproducer for https://github.com/junit-team/junit5/issues/4076 + * Reproducer for https://github.com/junit-team/junit-framework/issues/4076 */ @Ignore public class DefaultPackageTest extends VintageTest { diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/archUnit/java/platform/tooling/support/tests/ArchUnitTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/archUnit/java/platform/tooling/support/tests/ArchUnitTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/archUnit/java/platform/tooling/support/tests/ArchUnitTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/archUnit/java/platform/tooling/support/tests/ArchUnitTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,190 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support.tests; + +import static com.tngtech.archunit.base.DescribedPredicate.describe; +import static com.tngtech.archunit.base.DescribedPredicate.not; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.ANONYMOUS_CLASSES; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.TOP_LEVEL_CLASSES; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAnyPackage; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.simpleName; +import static com.tngtech.archunit.core.domain.JavaModifier.PUBLIC; +import static com.tngtech.archunit.core.domain.properties.HasModifiers.Predicates.modifier; +import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name; +import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameContaining; +import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameStartingWith; +import static com.tngtech.archunit.lang.conditions.ArchPredicates.are; +import static com.tngtech.archunit.lang.conditions.ArchPredicates.have; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.Arrays; +import java.util.function.BiPredicate; + +import com.tngtech.archunit.base.DescribedPredicate; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchCondition; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.library.GeneralCodingRules; + +import org.apiguardian.api.API; +import org.junit.jupiter.api.TestReporter; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.scanning.ClasspathScanner; +import org.junit.platform.engine.OutputDirectoryCreator; +import org.junit.platform.engine.TestDescriptor; + +@AnalyzeClasses(packages = { "org.junit.platform", "org.junit.jupiter", "org.junit.vintage" }) +class ArchUnitTests { + + @SuppressWarnings("unused") + @ArchTest + private final ArchRule allClassesAreInJUnitPackage = classes() // + .should().haveNameMatching("org\\.junit\\..+"); + + @SuppressWarnings("unused") + @ArchTest + private final ArchRule allPublicTopLevelTypesHaveApiAnnotations = classes() // + .that(have(modifier(PUBLIC))) // + .and(TOP_LEVEL_CLASSES) // + .and(not(ANONYMOUS_CLASSES)) // + .and(not(describe("are Kotlin SAM type implementations", simpleName("")))) // + .and(not(describe("are shadowed", resideInAnyPackage("..shadow..")))) // + .should().beAnnotatedWith(API.class); + + @SuppressWarnings("unused") + @ArchTest // Consistency of @Documented and @Inherited is checked by the compiler but not for @Retention and @Target + private final ArchRule repeatableAnnotationsShouldHaveMatchingContainerAnnotations = classes() // + .that(nameStartingWith("org.junit.")) // + .and().areAnnotations() // + .and().areAnnotatedWith(Repeatable.class) // + .should(haveContainerAnnotationWithSameRetentionPolicy()) // + .andShould(haveContainerAnnotationWithSameTargetTypes()); + + @ArchTest + void allAreIn(JavaClasses classes) { + // about 928 classes found in all jars + assertTrue(classes.size() > 800, "expected more than 800 classes, got: " + classes.size()); + } + + @ArchTest + void freeOfGroupCycles(JavaClasses classes) { + slices().matching("org.junit.(*)..").should().beFreeOfCycles().check(classes); + } + + @ArchTest + @SuppressWarnings("deprecation") + void freeOfPackageCycles(JavaClasses classes) throws Exception { + slices().matching("org.junit.(**)").should().beFreeOfCycles() // + + // Ignore shadowed packages + .ignoreDependency(nameContaining(".shadow."), nameContaining(".shadow.")) // + + // https://github.com/junit-team/junit-framework/issues/1863 + .ignoreDependency(PreconditionViolationException.class, + org.junit.platform.commons.util.PreconditionViolationException.class) // + + // https://github.com/junit-team/junit-framework/issues/4886 + .ignoreDependency(TestReporter.class, org.junit.jupiter.api.extension.MediaType.class) // + + // https://github.com/junit-team/junit-framework/issues/4885 + .ignoreDependency(ClasspathScanner.class, org.junit.platform.commons.support.Resource.class) // + + // https://github.com/junit-team/junit-framework/issues/4919 + .ignoreDependency(org.junit.jupiter.params.support.ParameterInfo.class, + org.junit.jupiter.params.ParameterInfo.class) + + // https://github.com/junit-team/junit-framework/issues/4923 + .ignoreDependency(org.junit.platform.engine.reporting.OutputDirectoryProvider.class, + OutputDirectoryCreator.class) // + .ignoreDependency(Class.forName("org.junit.platform.engine.reporting.OutputDirectoryProviderAdapter"), + OutputDirectoryCreator.class) // + .ignoreDependency(Class.forName("org.junit.platform.engine.reporting.OutputDirectoryProviderAdapter"), + TestDescriptor.class) // + + .check(classes); + } + + @ArchTest + void avoidJavaUtilLogging(JavaClasses classes) { + // LoggerFactory.java:80 -> sets field LoggerFactory$DelegatingLogger.julLogger + var subset = classes.that(are(not(name("org.junit.platform.commons.logging.LoggerFactory$DelegatingLogger")))); + GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING.check(subset); + } + + @ArchTest + void avoidThrowingGenericExceptions(JavaClasses classes) { + // LoggerFactory.java:155 -> new Throwable() + var subset = classes.that(are(not( + name("org.junit.platform.commons.logging.LoggerFactory$DelegatingLogger").or(nameContaining(".shadow."))))); + GeneralCodingRules.NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS.check(subset); + } + + @ArchTest + void avoidAccessingStandardStreams(JavaClasses classes) { + // ConsoleLauncher, StreamInterceptor, Picocli et al... + var subset = classes // + .that(are(not(name("org.junit.platform.console.ConsoleLauncher")))) // + .that(are(not(name("org.junit.platform.console.command.ConsoleTestExecutor")))) // + .that(are(not(name("org.junit.platform.launcher.core.StreamInterceptor")))) // + .that(are(not(name("org.junit.platform.runner.JUnitPlatformRunnerListener")))) // + .that(are(not(name("org.junit.platform.testkit.engine.Events")))) // + .that(are(not(name("org.junit.platform.testkit.engine.Executions")))) // + //The PreInterruptThreadDumpPrinter writes to StdOut by contract to dump threads + .that(are(not(name("org.junit.jupiter.engine.extension.PreInterruptThreadDumpPrinter")))) // + .that(are(not(resideInAPackage("org.junit.platform.console.shadow.picocli")))); + GeneralCodingRules.NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS.check(subset); + } + + private static ArchCondition haveContainerAnnotationWithSameRetentionPolicy() { + return ArchCondition.from(new RepeatableAnnotationPredicate<>(Retention.class, + (expectedTarget, actualTarget) -> expectedTarget.value() == actualTarget.value())); + } + + private static ArchCondition haveContainerAnnotationWithSameTargetTypes() { + return ArchCondition.from(new RepeatableAnnotationPredicate<>(Target.class, + (expectedTarget, actualTarget) -> Arrays.equals(expectedTarget.value(), actualTarget.value()))); + } + + private static class RepeatableAnnotationPredicate extends DescribedPredicate { + + private final Class annotationType; + private final BiPredicate predicate; + + public RepeatableAnnotationPredicate(Class annotationType, BiPredicate predicate) { + super("have identical @%s annotation as container annotation", annotationType.getSimpleName()); + this.annotationType = annotationType; + this.predicate = predicate; + } + + @Override + public boolean test(JavaClass annotationClass) { + var containerAnnotationClass = (JavaClass) annotationClass.getAnnotationOfType( + Repeatable.class.getName()).get("value").orElseThrow(); + var expectedAnnotation = annotationClass.tryGetAnnotationOfType(annotationType); + var actualAnnotation = containerAnnotationClass.tryGetAnnotationOfType(annotationType); + return expectedAnnotation.map(expectedTarget -> actualAnnotation // + .map(actualTarget -> predicate.test(expectedTarget, actualTarget)) // + .orElse(false)) // + .orElse(actualAnnotation.isEmpty()); + } + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Helper.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Helper.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Helper.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Helper.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,23 +10,15 @@ package platform.tooling.support; -import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.Duration; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Properties; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -34,8 +26,6 @@ */ public class Helper { - public static final Duration TOOL_TIMEOUT = Duration.ofMinutes(3); - private static final Path ROOT = Paths.get(".."); private static final Path GRADLE_PROPERTIES = ROOT.resolve("gradle.properties"); private static final Path SETTINGS_GRADLE = ROOT.resolve("settings.gradle.kts"); @@ -64,57 +54,22 @@ throw new AssertionError("Unknown module: " + module); } - static String groupId(String artifactId) { - if (artifactId.startsWith("junit-jupiter")) { - return "org.junit.jupiter"; - } - if (artifactId.startsWith("junit-platform")) { - return "org.junit.platform"; - } - if (artifactId.startsWith("junit-vintage")) { - return "org.junit.vintage"; - } - return "org.junit"; - } - - public static String replaceVersionPlaceholders(String line) { - line = line.replace("${jupiterVersion}", version("junit-jupiter")); - line = line.replace("${vintageVersion}", version("junit-vintage")); - line = line.replace("${platformVersion}", version("junit-platform")); - return line; - } - public static List loadModuleDirectoryNames() { var moduleLinePattern = Pattern.compile("include\\(\"(.+)\"\\)"); - try (var stream = Files.lines(SETTINGS_GRADLE) // - .map(moduleLinePattern::matcher) // - .filter(Matcher::matches) // - .map(matcher -> matcher.group(1)) // - .filter(name -> name.startsWith("junit-")) // - .filter(name -> !name.equals("junit-bom")) // - .filter(name -> !name.equals("junit-platform-console-standalone"))) { - return stream.collect(Collectors.toList()); + try (var stream = Files.lines(SETTINGS_GRADLE)) { + return stream.map(moduleLinePattern::matcher) // + .filter(Matcher::matches) // + .map(matcher -> matcher.group(1)) // + .filter(name -> name.startsWith("junit-")) // + .filter(name -> !name.equals("junit-bom")) // + .filter(name -> !name.equals("junit-platform-console-standalone")).toList(); } catch (Exception e) { throw new AssertionError("loading module directory names failed: " + SETTINGS_GRADLE); } } - static JarFile createJarFile(String module) { - var path = MavenRepo.jar(module); - try { - return new JarFile(path.toFile()); - } - catch (IOException e) { - throw new UncheckedIOException("Creating JarFile for '" + path + "' failed.", e); - } - } - - public static List loadJarFiles() { - return loadModuleDirectoryNames().stream().map(Helper::createJarFile).collect(Collectors.toList()); - } - - public static Optional getJavaHome(String version) { + public static Optional getJavaHome(int version) { // First, try various system sources... var sources = Stream.of( // System.getProperty("java.home." + version), // @@ -128,31 +83,6 @@ return sources.filter(Objects::nonNull).findFirst().map(Path::of); } - /** Load, here copy, modular jar files to the given target directory. */ - public static void loadAllJUnitModules(Path target) throws Exception { - for (var module : loadModuleDirectoryNames()) { - var jar = MavenRepo.jar(module); - Files.copy(jar, target.resolve(jar.getFileName())); - } - } - - /** Walk directory tree structure. */ - public static List treeWalk(Path root) { - var lines = new ArrayList(); - treeWalk(root, lines::add); - return lines; - } - - /** Walk directory tree structure. */ - public static void treeWalk(Path root, Consumer out) { - try (var stream = Files.walk(root)) { - stream.map(root::relativize) // - .map(path -> path.toString().replace('\\', '/')) // - .sorted().filter(Predicate.not(String::isEmpty)) // - .forEach(out); - } - catch (Exception e) { - throw new Error("Walking tree failed: " + root, e); - } + private Helper() { } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/MavenRepo.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/MavenRepo.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/MavenRepo.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/MavenRepo.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -45,7 +45,7 @@ private static Path artifact(String artifactId, Predicate fileNamePredicate) { var parentDir = dir() // - .resolve(Helper.groupId(artifactId).replace('.', File.separatorChar)) // + .resolve(groupId(artifactId).replace('.', File.separatorChar)) // .resolve(artifactId) // .resolve(Helper.version(artifactId)); try (var files = Files.list(parentDir)) { @@ -57,4 +57,16 @@ } } + private static String groupId(String artifactId) { + if (artifactId.startsWith("junit-jupiter")) { + return "org.junit.jupiter"; + } + if (artifactId.startsWith("junit-platform")) { + return "org.junit.platform"; + } + if (artifactId.startsWith("junit-vintage")) { + return "org.junit.vintage"; + } + return "org.junit"; + } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ProcessStarters.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ProcessStarters.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ProcessStarters.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ProcessStarters.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support; + +import java.nio.file.Path; +import java.util.Optional; + +import org.junit.jupiter.api.condition.OS; +import org.junit.platform.tests.process.ProcessStarter; +import org.opentest4j.TestAbortedException; + +public class ProcessStarters { + + public static ProcessStarter java() { + return javaCommand(currentJdkHome(), "java"); + } + + public static Path currentJdkHome() { + var executable = ProcessHandle.current().info().command().map(Path::of).orElseThrow(); + // path element count is 3 or higher: "/bin/java[.exe]" + return executable.getParent().getParent().toAbsolutePath(); + } + + public static ProcessStarter java(Path javaHome) { + return javaCommand(javaHome, "java"); + } + + public static ProcessStarter javaCommand(String commandName) { + return javaCommand(currentJdkHome(), commandName); + } + + public static ProcessStarter javaCommand(Path javaHome, String commandName) { + return new ProcessStarter() // + .executable(javaHome.resolve("bin").resolve(commandName)) // + .putEnvironment("JAVA_HOME", javaHome); + } + + public static ProcessStarter gradlew() { + return new ProcessStarter() // + .executable(Path.of("..").resolve(windowsOrOtherExecutable("gradlew.bat", "gradlew")).toAbsolutePath()) // + .putEnvironment("JAVA_HOME", getGradleJavaHome().orElseThrow(TestAbortedException::new)) // + .addArguments("-PjupiterVersion=" + Helper.version("junit-jupiter")) // + .addArguments("-PvintageVersion=" + Helper.version("junit-vintage")) // + .addArguments("-PplatformVersion=" + Helper.version("junit-platform")); + } + + public static ProcessStarter maven() { + return maven(currentJdkHome()); + } + + public static ProcessStarter maven(Path javaHome) { + return new ProcessStarter() // + .executable(Path.of(System.getProperty("mavenDistribution")).resolve("bin").resolve( + windowsOrOtherExecutable("mvn.cmd", "mvn")).toAbsolutePath()) // + .putEnvironment("JAVA_HOME", javaHome) // + .addArguments("-Djunit.jupiter.version=" + Helper.version("junit-jupiter")) // + .addArguments("-Djunit.bom.version=" + Helper.version("junit-jupiter")) // + .addArguments("-Djunit.vintage.version=" + Helper.version("junit-vintage")) // + .addArguments("-Djunit.platform.version=" + Helper.version("junit-platform")); + } + + private static String windowsOrOtherExecutable(String cmdOrExe, String other) { + return OS.current() == OS.WINDOWS ? cmdOrExe : other; + } + + public static Optional getGradleJavaHome() { + return Helper.getJavaHome(getGradleJavaVersion()); + } + + public static int getGradleJavaVersion() { + return Integer.parseInt(System.getProperty("gradle.java.version")); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Request.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Request.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Request.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/Request.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,183 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package platform.tooling.support; - -import java.io.FileFilter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import de.sormuras.bartholdy.Configuration; -import de.sormuras.bartholdy.Result; -import de.sormuras.bartholdy.Tool; -import de.sormuras.bartholdy.tool.Maven; - -import org.apache.commons.io.FileUtils; - -/** - * @since 1.3 - */ -public class Request { - - public static final Path PROJECTS = Paths.get("projects"); - private static final Path TOOLS = Paths.get("build", "test-tools"); - public static final Path WORKSPACE = Paths.get("build", "test-workspace"); - - public static Builder builder() { - return new Builder(); - } - - public static Maven maven() { - return new Maven(Path.of(System.getProperty("mavenDistribution"))); - } - - private Tool tool; - private String project; - private String workspace; - private List arguments = new ArrayList<>(); - private Map environment = new HashMap<>(); - private FileFilter copyProjectToWorkspaceFileFilter; - private Duration timeout = Duration.ofMinutes(1); - - public String getProject() { - return project; - } - - public FileFilter getCopyProjectToWorkspaceFileFilter() { - return copyProjectToWorkspaceFileFilter; - } - - public String getWorkspace() { - return workspace; - } - - public Map getEnvironment() { - return environment; - } - - public List getArguments() { - return arguments; - } - - public Duration getTimeout() { - return timeout; - } - - public Result run() { - return run(true); - } - - public Result run(boolean cleanWorkspace) { - try { - // sanity check - if (!Files.isDirectory(PROJECTS)) { - var cwd = Paths.get(".").normalize().toAbsolutePath(); - throw new IllegalStateException("Directory " + PROJECTS + " not found in: " + cwd); - } - - Files.createDirectories(TOOLS); - Files.createDirectories(WORKSPACE); - - var workspace = WORKSPACE.resolve(getWorkspace()); - if (cleanWorkspace) { - FileUtils.deleteQuietly(workspace.toFile()); - var project = PROJECTS.resolve(getProject()); - if (Files.isDirectory(project)) { - var filter = getCopyProjectToWorkspaceFileFilter(); - FileUtils.copyDirectory(project.toFile(), workspace.toFile(), filter); - } - } - - var configuration = Configuration.builder(); - configuration.setArguments(getArguments()); - configuration.setWorkingDirectory(workspace); - configuration.setTimeout(getTimeout()); - configuration.getEnvironment().putAll(getEnvironment()); - - var result = tool.run(configuration.build()); - System.out.println(result.getOutput("out")); - System.err.println(result.getOutput("err")); - return result; - } - catch (Exception e) { - throw new IllegalStateException("run failed", e); - } - } - - public static class Builder { - - private final Request request = new Request(); - - public Request build() { - if (request.project == null) { - throw new IllegalStateException("project must not be null"); - } - if (request.workspace == null) { - request.workspace = request.project; - } - buildEnvironment(request.environment); - request.arguments = List.copyOf(request.arguments); - request.environment = Map.copyOf(request.environment); - return request; - } - - private void buildEnvironment(Map environment) { - environment.computeIfAbsent("JUNIT_JUPITER_VERSION", key -> Helper.version("junit-jupiter")); - environment.computeIfAbsent("JUNIT_VINTAGE_VERSION", key -> Helper.version("junit-vintage")); - environment.computeIfAbsent("JUNIT_PLATFORM_VERSION", key -> Helper.version("junit-platform")); - } - - public Builder setTool(Tool tool) { - request.tool = tool; - return this; - } - - public Builder setJavaHome(Path javaHome) { - return putEnvironment("JAVA_HOME", javaHome.normalize().toAbsolutePath().toString()); - } - - public Builder setProject(String project) { - request.project = project; - return this; - } - - public Builder setProjectToWorkspaceCopyFileFilter(FileFilter copyProjectToWorkspaceFileFilter) { - request.copyProjectToWorkspaceFileFilter = copyProjectToWorkspaceFileFilter; - return this; - } - - public Builder setWorkspace(String workspace) { - request.workspace = workspace; - return this; - } - - public Builder addArguments(Object... arguments) { - Stream.of(arguments).map(Object::toString).forEach(request.arguments::add); - return this; - } - - public Builder putEnvironment(String key, String value) { - request.environment.put(key, value); - return this; - } - - public Builder setTimeout(Duration timeout) { - request.timeout = timeout; - return this; - } - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ThirdPartyJars.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ThirdPartyJars.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ThirdPartyJars.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/main/java/platform/tooling/support/ThirdPartyJars.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/HelperTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/HelperTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/HelperTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/HelperTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -61,13 +61,13 @@ @Test void nonExistingJdkVersionYieldsAnEmptyOptional() { - assertEquals(Optional.empty(), Helper.getJavaHome("does not exist")); + assertEquals(Optional.empty(), Helper.getJavaHome(-1)); } @ParameterizedTest @ValueSource(ints = 8) void checkJavaHome(int version) { - var home = Helper.getJavaHome(String.valueOf(version)); + var home = Helper.getJavaHome(version); assumeTrue(home.isPresent(), "No 'jdk' element found in Maven toolchain for: " + version); assertTrue(Files.isDirectory(home.get())); } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/AntStarterTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/AntStarterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/AntStarterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/AntStarterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,56 +11,61 @@ package platform.tooling.support.tests; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static platform.tooling.support.tests.Projects.copyToWorkspace; import static platform.tooling.support.tests.XmlAssertions.verifyContainsExpectedStartedOpenTestReport; +import java.nio.file.Path; import java.util.List; -import de.sormuras.bartholdy.tool.Java; +import de.skuzzle.test.snapshots.Snapshot; +import de.skuzzle.test.snapshots.junit5.EnableSnapshotTests; import org.apache.tools.ant.Main; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.tests.process.OutputFiles; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.3 */ +@EnableSnapshotTests +//@SnapshotTestOptions(alwaysPersistActualResult = true) class AntStarterTests { - @ResourceLock(Projects.ANT_STARTER) @Test - void ant_starter() { - var request = Request.builder() // - .setTool(new Java()) // - .setProject(Projects.ANT_STARTER) // - .addArguments("-cp", System.getProperty("antJars"), Main.class.getName()) // - .addArguments("-verbose") // - .build(); - - var result = request.run(); + @Timeout(60) + void ant_starter(@TempDir Path workspace, @FilePrefix("ant") OutputFiles outputFiles, Snapshot snapshot) + throws Exception { - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); + var result = ProcessStarters.java() // + .workingDir(copyToWorkspace(Projects.JUPITER_STARTER, workspace)) // + .addArguments("-cp", System.getProperty("antJars"), Main.class.getName()) // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode()); - assertEquals("", result.getOutput("err"), "error log isn't empty"); + assertEquals(0, result.exitCode()); + assertEquals("", result.stdErr(), "error log isn't empty"); assertLinesMatch(List.of(">> HEAD >>", // "test.junit.launcher:", // ">>>>", // + "\\[junitlauncher\\] Tests run: 8, Failures: 0, Aborted: 0, Skipped: 0, Time elapsed: .+ sec", // + "\\[junitlauncher\\] Running com.example.project.CalculatorTests", // "\\[junitlauncher\\] Tests run: 5, Failures: 0, Aborted: 0, Skipped: 0, Time elapsed: .+ sec", // ">>>>", // "test.console.launcher:", // ">>>>", // " \\[java\\] Test run finished after [\\d]+ ms", // ">>>>", // - " \\[java\\] \\[ 5 tests successful \\]", // + " \\[java\\] \\[ 13 tests successful \\]", // " \\[java\\] \\[ 0 tests failed \\]", // ">> TAIL >>"), // - result.getOutputLines("out")); + result.stdOutLines()); - var testResultsDir = Request.WORKSPACE.resolve(request.getWorkspace()).resolve("build/test-report"); - verifyContainsExpectedStartedOpenTestReport(testResultsDir); + var testResultsDir = workspace.resolve("build/test-report"); + verifyContainsExpectedStartedOpenTestReport(testResultsDir, snapshot); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package platform.tooling.support.tests; - -import static com.tngtech.archunit.base.DescribedPredicate.describe; -import static com.tngtech.archunit.base.DescribedPredicate.not; -import static com.tngtech.archunit.core.domain.JavaClass.Predicates.ANONYMOUS_CLASSES; -import static com.tngtech.archunit.core.domain.JavaClass.Predicates.TOP_LEVEL_CLASSES; -import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage; -import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAnyPackage; -import static com.tngtech.archunit.core.domain.JavaClass.Predicates.simpleName; -import static com.tngtech.archunit.core.domain.JavaModifier.PUBLIC; -import static com.tngtech.archunit.core.domain.properties.HasModifiers.Predicates.modifier; -import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name; -import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameContaining; -import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameStartingWith; -import static com.tngtech.archunit.lang.conditions.ArchPredicates.are; -import static com.tngtech.archunit.lang.conditions.ArchPredicates.have; -import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; -import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static platform.tooling.support.Helper.loadJarFiles; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.util.Arrays; -import java.util.Set; -import java.util.function.BiPredicate; -import java.util.stream.Collectors; - -import com.tngtech.archunit.base.DescribedPredicate; -import com.tngtech.archunit.core.domain.JavaClass; -import com.tngtech.archunit.core.domain.JavaClasses; -import com.tngtech.archunit.core.importer.Location; -import com.tngtech.archunit.junit.AnalyzeClasses; -import com.tngtech.archunit.junit.ArchTest; -import com.tngtech.archunit.junit.LocationProvider; -import com.tngtech.archunit.lang.ArchCondition; -import com.tngtech.archunit.lang.ArchRule; -import com.tngtech.archunit.library.GeneralCodingRules; - -import org.apiguardian.api.API; - -@AnalyzeClasses(locations = ArchUnitTests.AllJars.class) -class ArchUnitTests { - - @SuppressWarnings("unused") - @ArchTest - private final ArchRule allPublicTopLevelTypesHaveApiAnnotations = classes() // - .that(have(modifier(PUBLIC))) // - .and(TOP_LEVEL_CLASSES) // - .and(not(ANONYMOUS_CLASSES)) // - .and(not(describe("are Kotlin SAM type implementations", simpleName("")))) // - .and(not(describe("are shadowed", resideInAnyPackage("..shadow..")))) // - .should().beAnnotatedWith(API.class); - - @SuppressWarnings("unused") - @ArchTest // Consistency of @Documented and @Inherited is checked by the compiler but not for @Retention and @Target - private final ArchRule repeatableAnnotationsShouldHaveMatchingContainerAnnotations = classes() // - .that(nameStartingWith("org.junit.")) // - .and().areAnnotations() // - .and().areAnnotatedWith(Repeatable.class) // - .should(haveContainerAnnotationWithSameRetentionPolicy()) // - .andShould(haveContainerAnnotationWithSameTargetTypes()); - - @ArchTest - void allAreIn(JavaClasses classes) { - // about 928 classes found in all jars - assertTrue(classes.size() > 800, "expected more than 800 classes, got: " + classes.size()); - } - - @ArchTest - void freeOfCycles(JavaClasses classes) { - slices().matching("org.junit.(*)..").should().beFreeOfCycles().check(classes); - } - - @ArchTest - void avoidJavaUtilLogging(JavaClasses classes) { - // LoggerFactory.java:80 -> sets field LoggerFactory$DelegatingLogger.julLogger - var subset = classes.that(are(not(name("org.junit.platform.commons.logging.LoggerFactory$DelegatingLogger")))); - GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING.check(subset); - } - - @ArchTest - void avoidThrowingGenericExceptions(JavaClasses classes) { - // LoggerFactory.java:155 -> new Throwable() - var subset = classes.that(are(not( - name("org.junit.platform.commons.logging.LoggerFactory$DelegatingLogger").or(nameContaining(".shadow."))))); - GeneralCodingRules.NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS.check(subset); - } - - @ArchTest - void avoidAccessingStandardStreams(JavaClasses classes) { - // ConsoleLauncher, StreamInterceptor, Picocli et al... - var subset = classes // - .that(are(not(name("org.junit.platform.console.ConsoleLauncher")))) // - .that(are(not(name("org.junit.platform.launcher.core.StreamInterceptor")))) // - .that(are(not(name("org.junit.platform.runner.JUnitPlatformRunnerListener")))) // - .that(are(not(name("org.junit.platform.testkit.engine.Events")))) // - .that(are(not(name("org.junit.platform.testkit.engine.Executions")))) // - .that(are(not(resideInAPackage("org.junit.platform.console.shadow.picocli")))); - GeneralCodingRules.NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS.check(subset); - } - - private static ArchCondition haveContainerAnnotationWithSameRetentionPolicy() { - return ArchCondition.from(new RepeatableAnnotationPredicate<>(Retention.class, - (expectedTarget, actualTarget) -> expectedTarget.value() == actualTarget.value())); - } - - private static ArchCondition haveContainerAnnotationWithSameTargetTypes() { - return ArchCondition.from(new RepeatableAnnotationPredicate<>(Target.class, - (expectedTarget, actualTarget) -> Arrays.equals(expectedTarget.value(), actualTarget.value()))); - } - - static class AllJars implements LocationProvider { - - @Override - public Set get(Class testClass) { - return loadJarFiles().stream().map(Location::of).collect(Collectors.toSet()); - } - - } - - private static class RepeatableAnnotationPredicate extends DescribedPredicate { - - private final Class annotationType; - private final BiPredicate predicate; - - public RepeatableAnnotationPredicate(Class annotationType, BiPredicate predicate) { - super("have identical @%s annotation as container annotation", annotationType.getSimpleName()); - this.annotationType = annotationType; - this.predicate = predicate; - } - - @Override - public boolean test(JavaClass annotationClass) { - var containerAnnotationClass = (JavaClass) annotationClass.getAnnotationOfType( - Repeatable.class.getName()).get("value").orElseThrow(); - var expectedAnnotation = annotationClass.tryGetAnnotationOfType(annotationType); - var actualAnnotation = containerAnnotationClass.tryGetAnnotationOfType(annotationType); - return expectedAnnotation.map(expectedTarget -> actualAnnotation // - .map(actualTarget -> predicate.test(expectedTarget, actualTarget)) // - .orElse(false)) // - .orElse(actualAnnotation.isEmpty()); - } - } -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/FilePrefix.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/FilePrefix.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/FilePrefix.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/FilePrefix.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support.tests; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(OutputAttachingExtension.class) +@interface FilePrefix { + String value(); +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,23 +10,23 @@ package platform.tooling.support.tests; +import static java.util.concurrent.TimeUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static platform.tooling.support.tests.Projects.copyToWorkspace; -import java.nio.file.Paths; -import java.time.Duration; - -import de.sormuras.bartholdy.tool.GradleWrapper; +import java.nio.file.Path; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.DisabledOnOpenJ9; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.tests.process.OutputFiles; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.9.1 @@ -36,26 +36,29 @@ @EnabledIfEnvironmentVariable(named = "GRAALVM_HOME", matches = ".+") class GraalVmStarterTests { - @ResourceLock(Projects.GRAALVM_STARTER) @Test - void runsTestsInNativeImage() { - var request = Request.builder() // - .setTool(new GradleWrapper(Paths.get(".."))) // - .setProject(Projects.GRAALVM_STARTER) // + @Timeout(value = 10, unit = MINUTES) + void runsTestsInNativeImage(@TempDir Path workspace, @FilePrefix("gradle") OutputFiles outputFiles) + throws Exception { + var result = ProcessStarters.gradlew() // + .workingDir(copyToWorkspace(Projects.GRAALVM_STARTER, workspace)) // .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // - .addArguments("javaToolchains", "nativeTest", "--no-daemon", "--stacktrace", "--no-build-cache") // - .setTimeout(Duration.ofMinutes(10)) // - .build(); - - var result = request.run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); + .addArguments("javaToolchains", "nativeTest", "--no-daemon", "--stacktrace", "--no-build-cache", + "--warning-mode=fail", "--refresh-dependencies") // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode()); - assertThat(result.getOutputLines("out")) // + assertEquals(0, result.exitCode()); + assertThat(result.stdOutLines()) // .anyMatch(line -> line.contains("CalculatorTests > 1 + 1 = 2 SUCCESSFUL")) // .anyMatch(line -> line.contains("CalculatorTests > 1 + 100 = 101 SUCCESSFUL")) // - .anyMatch(line -> line.contains("ClassLevelAnnotationTests$Inner > test() SUCCESSFUL")) // + .anyMatch(line -> line.contains( + "ClassLevelAnnotationTests$Inner > ClassLevelAnnotationTests, Inner, test SUCCESSFUL")) // + .anyMatch( + line -> line.contains("com.example.project.CalculatorParameterizedClassTests > [1] 1 SUCCESSFUL")) // + .anyMatch( + line -> line.contains("com.example.project.CalculatorParameterizedClassTests > [2] 2 SUCCESSFUL")) // + .anyMatch(line -> line.contains("com.example.project.VintageTests > test SUCCESSFUL")) // .anyMatch(line -> line.contains("BUILD SUCCESSFUL")); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleKotlinExtensionsTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleKotlinExtensionsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleKotlinExtensionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleKotlinExtensionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,43 +11,36 @@ package platform.tooling.support.tests; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; -import java.nio.file.Paths; - -import de.sormuras.bartholdy.tool.GradleWrapper; +import java.nio.file.Path; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.tests.process.OutputFiles; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.3 */ class GradleKotlinExtensionsTests { - @ResourceLock(Projects.GRADLE_KOTLIN_EXTENSIONS) @Test - void gradle_wrapper() { - var result = Request.builder() // - .setTool(new GradleWrapper(Paths.get(".."))) // - .setProject(Projects.GRADLE_KOTLIN_EXTENSIONS) // + void gradle_wrapper(@TempDir Path workspace, @FilePrefix("gradle") OutputFiles outputFiles) throws Exception { + var result = ProcessStarters.gradlew() // + .workingDir(copyToWorkspace(Projects.GRADLE_KOTLIN_EXTENSIONS, workspace)) // .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // - .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache") // - .setTimeout(TOOL_TIMEOUT) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .build() // - .run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); + .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache", "--warning-mode=fail") // + .putEnvironment("JDK8", Helper.getJavaHome(8).orElseThrow(TestAbortedException::new).toString()) // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode(), "result=" + result); - assertTrue(result.getOutputLines("out").stream().anyMatch(line -> line.contains("BUILD SUCCESSFUL"))); + assertEquals(0, result.exitCode(), "result=" + result); + assertTrue(result.stdOut().lines().anyMatch(line -> line.contains("BUILD SUCCESSFUL"))); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleMissingEngineTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleMissingEngineTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleMissingEngineTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleMissingEngineTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,58 +10,42 @@ package platform.tooling.support.tests; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertLinesMatch; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; -import java.nio.file.Paths; -import java.util.List; - -import de.sormuras.bartholdy.Tool; -import de.sormuras.bartholdy.tool.GradleWrapper; +import java.nio.file.Path; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.reporting.testutil.FileUtils; +import org.junit.platform.tests.process.OutputFiles; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.3 */ class GradleMissingEngineTests { - @ResourceLock(Projects.GRADLE_MISSING_ENGINE) @Test - void gradle_wrapper() { - test(new GradleWrapper(Paths.get(".."))); - } - - private void test(Tool gradle) { - var result = Request.builder() // - .setProject(Projects.GRADLE_MISSING_ENGINE) // - .setTool(gradle) // + void gradle_wrapper(@TempDir Path workspace, @FilePrefix("gradle") OutputFiles outputFiles) throws Exception { + var result = ProcessStarters.gradlew() // + .workingDir(copyToWorkspace(Projects.GRADLE_MISSING_ENGINE, workspace)) // .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // - .addArguments("build", "--no-daemon", "--debug", "--stacktrace", "--no-build-cache") // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .setTimeout(TOOL_TIMEOUT).build() // - .run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - - assertEquals(1, result.getExitCode()); - assertLinesMatch(List.of( // - ">> HEAD >>", // - ".+DEBUG.+Cannot create Launcher without at least one TestEngine.+", // - ">> TAIL >>"), // - result.getOutputLines("out")); - assertLinesMatch(List.of( // - ">> HEAD >>", // - ".+ERROR.+FAILURE: Build failed with an exception.", // - ">> TAIL >>"), // - result.getOutputLines("err")); + .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache", "--warning-mode=fail") // + .putEnvironment("JDK8", Helper.getJavaHome(8).orElseThrow(TestAbortedException::new).toString()) // + .redirectOutput(outputFiles).startAndWait(); + + assertEquals(1, result.exitCode()); + assertThat(result.stdErrLines()) // + .contains("FAILURE: Build failed with an exception."); + + var htmlFile = FileUtils.findPath(workspace, "glob:**/build/reports/tests/test/classes/*.html"); + assertThat(htmlFile).content() // + .contains("Cannot create Launcher without at least one TestEngine"); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleModuleFileTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleModuleFileTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleModuleFileTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleModuleFileTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleStarterTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleStarterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleStarterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GradleStarterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,49 +12,109 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; import static platform.tooling.support.tests.XmlAssertions.verifyContainsExpectedStartedOpenTestReport; -import java.nio.file.Paths; +import java.nio.file.Path; -import de.sormuras.bartholdy.tool.GradleWrapper; +import de.skuzzle.test.snapshots.Snapshot; +import de.skuzzle.test.snapshots.junit5.EnableSnapshotTests; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.tests.process.OutputFiles; +import org.junit.platform.tests.process.ProcessResult; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.3 */ +@EnableSnapshotTests +//@SnapshotTestOptions(alwaysPersistActualResult = true) class GradleStarterTests { - @ResourceLock(Projects.GRADLE_STARTER) - @Test - void gradle_wrapper() { - var request = Request.builder() // - .setTool(new GradleWrapper(Paths.get(".."))) // - .setProject(Projects.GRADLE_STARTER) // - .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // - .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache") // - .setTimeout(TOOL_TIMEOUT) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .build(); + @TempDir + Path workspace; + + @BeforeEach + void prepareWorkspace() throws Exception { + copyToWorkspace(Projects.JUPITER_STARTER, workspace); + } + + @ParameterizedTest(name = "Java {0}") + @ValueSource(ints = { 8, 17 }) + void buildJupiterStarterProject(int javaVersion, @FilePrefix("gradle") OutputFiles outputFiles, Snapshot snapshot) + throws Exception { + + var result = runGradle(outputFiles, javaVersion, "build"); + + assertThat(result.stdOut()) // + .contains( // + "CalculatorParameterizedClassTests > [1] i=1 > parameterizedTest(int)", // + "CalculatorParameterizedClassTests > [1] i=1 > Inner > [1] 1 > regularTest() PASSED", // + "CalculatorParameterizedClassTests > [1] i=1 > Inner > [2] 2 > regularTest() PASSED", // + "CalculatorParameterizedClassTests > [2] i=2 > parameterizedTest(int)", // + "CalculatorParameterizedClassTests > [2] i=2 > Inner > [1] 1 > regularTest() PASSED", // + "CalculatorParameterizedClassTests > [2] i=2 > Inner > [2] 2 > regularTest() PASSED", // + "Using Java version: " + (javaVersion == 8 ? "1.8" : javaVersion), // + "CalculatorTests > 1 + 1 = 2 PASSED", // + "CalculatorTests > add(int, int, int) > 0 + 1 = 1 PASSED", // + "CalculatorTests > add(int, int, int) > 1 + 2 = 3 PASSED", // + "CalculatorTests > add(int, int, int) > 49 + 51 = 100 PASSED", // + "CalculatorTests > add(int, int, int) > 1 + 100 = 101 PASSED" // + ); - var result = request.run(); + var testResultsDir = workspace.resolve("build/test-results/test"); + verifyContainsExpectedStartedOpenTestReport(testResultsDir, snapshot); + } - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); + @Test + void runOnlyOneMethodInClassTemplate(@FilePrefix("gradle") OutputFiles outputFiles) throws Exception { - assertEquals(0, result.getExitCode()); - assertTrue(result.getOutputLines("out").stream().anyMatch(line -> line.contains("BUILD SUCCESSFUL"))); - assertThat(result.getOutput("out")).contains("Using Java version: 1.8"); + var result = runGradle(outputFiles, 8, "test", "--tests", "CalculatorParameterized*.regular*"); - var testResultsDir = Request.WORKSPACE.resolve(request.getWorkspace()).resolve("build/test-results/test"); - verifyContainsExpectedStartedOpenTestReport(testResultsDir); + assertThat(result.stdOut()) // + .contains( // + "CalculatorParameterizedClassTests > [1] i=1 > Inner > [1] 1 > regularTest() PASSED", // + "CalculatorParameterizedClassTests > [1] i=1 > Inner > [2] 2 > regularTest() PASSED", // + "CalculatorParameterizedClassTests > [2] i=2 > Inner > [1] 1 > regularTest() PASSED", // + "CalculatorParameterizedClassTests > [2] i=2 > Inner > [2] 2 > regularTest() PASSED" // + ) // + .doesNotContain("parameterizedTest(int)", "CalculatorTests"); + + result = runGradle(outputFiles, 8, "test", "--tests", "*ParameterizedClassTests.parameterized*"); + + assertThat(result.stdOut()) // + .contains( // + "CalculatorParameterizedClassTests > [1] i=1 > parameterizedTest(int)", // + "CalculatorParameterizedClassTests > [2] i=2 > parameterizedTest(int)" // + ) // + .doesNotContain("regularTest()", "CalculatorTests"); + } + + private ProcessResult runGradle(OutputFiles outputFiles, int javaVersion, String... extraArgs) + throws InterruptedException { + var result = ProcessStarters.gradlew() // + .workingDir(workspace) // + .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // + .addArguments("-Djava.toolchain.version=" + javaVersion) // + .addArguments("--stacktrace", "--no-build-cache", "--warning-mode=fail") // + .addArguments(extraArgs) // + .putEnvironment("JDK8", Helper.getJavaHome(8).orElseThrow(TestAbortedException::new).toString()) // + .putEnvironment("JDK17", Helper.getJavaHome(17).orElseThrow(TestAbortedException::new).toString()) // + .redirectOutput(outputFiles) // + .startAndWait(); + + assertEquals(0, result.exitCode()); + assertTrue(result.stdOut().lines().anyMatch(line -> line.contains("BUILD SUCCESSFUL"))); + return result; } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarContainsManifestFirstTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarContainsManifestFirstTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarContainsManifestFirstTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarContainsManifestFirstTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarDescribeModuleTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarDescribeModuleTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarDescribeModuleTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JarDescribeModuleTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,27 +11,21 @@ package platform.tooling.support.tests; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static platform.tooling.support.tests.Projects.getSourceDirectory; import java.lang.module.ModuleFinder; import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.stream.Collectors; - -import de.sormuras.bartholdy.jdk.Jar; import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.parallel.ResourceLock; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.platform.tests.process.OutputFiles; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.3 @@ -39,32 +33,24 @@ @Order(Integer.MAX_VALUE) class JarDescribeModuleTests { - @ResourceLock(Projects.JAR_DESCRIBE_MODULE) @ParameterizedTest @MethodSource("platform.tooling.support.Helper#loadModuleDirectoryNames") - void describeModule(String module) throws Exception { + void describeModule(String module, @FilePrefix("jar") OutputFiles outputFiles) throws Exception { + var sourceDirectory = getSourceDirectory(Projects.JAR_DESCRIBE_MODULE); var modulePath = MavenRepo.jar(module); - var result = Request.builder() // - .setTool(new Jar()) // - .setProject(Projects.JAR_DESCRIBE_MODULE) // - .setProjectToWorkspaceCopyFileFilter(file -> file.getName().startsWith(module)) // - .setWorkspace("jar-describe-module/" + module) // - .addArguments("--describe-module", "--file", modulePath) // - .build() // - .run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - - assertEquals(0, result.getExitCode()); - assertEquals("", result.getOutput("err"), "error log isn't empty"); - var expected = Paths.get("build", "test-workspace", "jar-describe-module", module, module + ".expected.txt"); - if (Files.notExists(expected)) { - result.getOutputLines("out").forEach(System.err::println); - fail("No such file: " + expected); - } - var expectedLines = Files.lines(expected).map(Helper::replaceVersionPlaceholders).collect(Collectors.toList()); - var origin = Path.of("projects", "jar-describe-module", module + ".expected.txt").toUri(); - assertLinesMatch(expectedLines, result.getOutputLines("out"), () -> String.format("%s\nError", origin)); + + var result = ProcessStarters.javaCommand("jar") // + .workingDir(sourceDirectory) // + .addArguments("--describe-module", "--file", modulePath.toAbsolutePath().toString()) // + .redirectOutput(outputFiles) // + .startAndWait(); + + assertEquals(0, result.exitCode()); + assertEquals("", result.stdErr(), "error log isn't empty"); + + var expectedLines = replaceVersionPlaceholders( + Files.readString(sourceDirectory.resolve(module + ".expected.txt")).trim()); + assertLinesMatch(expectedLines.lines().toList(), result.stdOut().trim().lines().toList()); } @ParameterizedTest @@ -78,4 +64,11 @@ } } + private static String replaceVersionPlaceholders(String line) { + line = line.replace("${jupiterVersion}", Helper.version("junit-jupiter")); + line = line.replace("${vintageVersion}", Helper.version("junit-vintage")); + line = line.replace("${platformVersion}", Helper.version("junit-platform")); + return line; + } + } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JavaVersionsTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JavaVersionsTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JavaVersionsTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/JavaVersionsTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,61 +11,62 @@ package platform.tooling.support.tests; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.ProcessStarters.currentJdkHome; +import static platform.tooling.support.tests.Projects.copyToWorkspace; import java.nio.file.Path; import java.util.List; import java.util.Map; -import de.sormuras.bartholdy.tool.Java; - import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.tests.process.OutputFiles; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.4 */ class JavaVersionsTests { + @ManagedResource + LocalMavenRepo localMavenRepo; + + @TempDir + Path workspace; + @Test - void java_8() { - var java8Home = Helper.getJavaHome("8"); + void java_8(@FilePrefix("maven") OutputFiles outputFiles) throws Exception { + var java8Home = Helper.getJavaHome(8); assumeTrue(java8Home.isPresent(), "Java 8 installation directory not found!"); - var actualLines = execute("8", java8Home.get(), Map.of()); + var actualLines = execute(java8Home.get(), outputFiles, Map.of()); assertTrue(actualLines.contains("[WARNING] Tests run: 2, Failures: 0, Errors: 0, Skipped: 1")); } @Test - void java_default() { - var actualLines = execute("default", new Java().getHome(), MavenEnvVars.FOR_JDK24_AND_LATER); + void java_default(@FilePrefix("maven") OutputFiles outputFiles) throws Exception { + var actualLines = execute(currentJdkHome(), outputFiles, MavenEnvVars.forJre(JRE.currentJre())); assertTrue(actualLines.contains("[WARNING] Tests run: 2, Failures: 0, Errors: 0, Skipped: 1")); } - List execute(String version, Path javaHome, Map environmentVars) { - var builder = Request.builder() // - .setTool(Request.maven()) // - .setProject(Projects.JAVA_VERSIONS) // - .setWorkspace("java-versions-" + version) // - .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // + List execute(Path javaHome, OutputFiles outputFiles, Map environmentVars) throws Exception { + var result = ProcessStarters.maven(javaHome) // + .workingDir(copyToWorkspace(Projects.JAVA_VERSIONS, workspace)) // + .putEnvironment(environmentVars) // + .addArguments(localMavenRepo.toCliArgument(), "-Dmaven.repo=" + MavenRepo.dir()) // .addArguments("--update-snapshots", "--batch-mode", "verify") // - .setTimeout(TOOL_TIMEOUT) // - .setJavaHome(javaHome); - environmentVars.forEach(builder::putEnvironment); - - var result = builder.build().run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - assertEquals(0, result.getExitCode()); - assertEquals("", result.getOutput("err")); - return result.getOutputLines("out"); + .startAndWait(); + + assertEquals(0, result.exitCode()); + assertEquals("", result.stdErr()); + return result.stdOutLines(); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/LocalMavenRepo.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/LocalMavenRepo.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/LocalMavenRepo.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/LocalMavenRepo.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support.tests; + +import static platform.tooling.support.tests.ManagedResource.Scope.GLOBAL; +import static platform.tooling.support.tests.ManagedResource.Scope.PER_CONTEXT; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; + +@ManagedResource.Scoped(LocalMavenRepo.ScopeProvider.class) +public class LocalMavenRepo implements AutoCloseable { + + public static class ScopeProvider implements ManagedResource.Scoped.Provider { + + private static final Namespace NAMESPACE = Namespace.create(LocalMavenRepo.class); + + @Override + public ManagedResource.Scope determineScope(ExtensionContext extensionContext) { + var store = extensionContext.getRoot().getStore(NAMESPACE); + var fileSystemType = store.getOrComputeIfAbsent("tempFileSystemType", key -> { + var type = getFileSystemType(Path.of(System.getProperty("java.io.tmpdir"))); + extensionContext.getRoot().publishReportEntry("tempFileSystemType", type); + return type; + }, String.class); + // Writing to the same file from multiple Maven processes may fail the build on Windows + return "NTFS".equalsIgnoreCase(fileSystemType) ? PER_CONTEXT : GLOBAL; + } + + private static String getFileSystemType(Path path) { + try { + return Files.getFileStore(path).type(); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + + private final Path tempDir; + + public LocalMavenRepo() { + try { + tempDir = Files.createTempDirectory("local-maven-repo-"); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public String toCliArgument() { + return "-Dmaven.repo.local=" + tempDir; + } + + @Override + public void close() throws IOException { + try (var files = Files.walk(tempDir)) { + files.sorted(Comparator. naturalOrder().reversed()) // + .forEach(path -> { + try { + Files.delete(path); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManagedResource.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManagedResource.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManagedResource.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManagedResource.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,122 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support.tests; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.junit.platform.commons.support.ReflectionSupport.streamFields; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; +import org.junit.platform.commons.support.AnnotationSupport; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.util.Preconditions; + +@Target({ ElementType.PARAMETER, ElementType.FIELD }) +@Retention(RUNTIME) +@ExtendWith(ManagedResource.Extension.class) +public @interface ManagedResource { + + @Target(ElementType.TYPE) + @Retention(RUNTIME) + @interface Scoped { + + Class value(); + + interface Provider { + Scope determineScope(ExtensionContext extensionContext); + } + } + + enum Scope { + GLOBAL, PER_CONTEXT + } + + class Extension implements ParameterResolver, TestInstancePostProcessor { + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return parameterContext.isAnnotated(ManagedResource.class); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + Class type = parameterContext.getParameter().getType(); + return getOrCreateResource(extensionContext, type).get(); + } + + @Override + public ExtensionContextScope getTestInstantiationExtensionContextScope(ExtensionContext rootContext) { + return ExtensionContextScope.TEST_METHOD; + } + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext extensionContext) { + streamFields(testInstance.getClass(), field -> AnnotationSupport.isAnnotated(field, ManagedResource.class), + HierarchyTraversalMode.BOTTOM_UP) // + .forEach(field -> { + try { + field.set(testInstance, getOrCreateResource(extensionContext, field.getType()).get()); + } + catch (IllegalAccessException e) { + throw new RuntimeException("Failed to inject resource into field: " + field, e); + } + }); + } + + @SuppressWarnings("unchecked") + private Resource getOrCreateResource(ExtensionContext extensionContext, Class type) { + var scope = AnnotationSupport.findAnnotation(type, Scoped.class) // + .map(Scoped::value) // + .map(ReflectionSupport::newInstance) // + .map(provider -> provider.determineScope(extensionContext)) // + .orElse(Scope.GLOBAL); + var storingContext = switch (scope) { + case GLOBAL -> extensionContext.getRoot(); + case PER_CONTEXT -> extensionContext; + }; + return storingContext.getStore(Namespace.GLOBAL) // + .getOrComputeIfAbsent(type, Resource::new, Resource.class); + } + } + + @SuppressWarnings("try") + class Resource implements AutoCloseable { + + private final T value; + + private Resource(Class type) { + Preconditions.condition(AutoCloseable.class.isAssignableFrom(type), + () -> "Resource type must implement AutoCloseable: " + type.getName()); + this.value = ReflectionSupport.newInstance(type); + } + + private T get() { + return value; + } + + @Override + public void close() throws Exception { + ((AutoCloseable) value).close(); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManifestTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManifestTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManifestTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ManifestTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenEnvVars.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenEnvVars.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenEnvVars.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenEnvVars.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,20 +10,35 @@ package platform.tooling.support.tests; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.condition.JRE; final class MavenEnvVars { - static final Map FOR_JDK24_AND_LATER = JRE.currentVersion().compareTo(JRE.JAVA_24) >= 0 // - ? Map.of("MAVEN_OPTS", String.join(" ", // - "--enable-native-access=ALL-UNNAMED", // https://issues.apache.org/jira/browse/MNG-8248 - "--sun-misc-unsafe-memory-access=allow" // https://issues.apache.org/jira/browse/MNG-8399 - )) // - : Map.of(); + private static final List FOR_JDK24_AND_LATER = List.of( // + "--enable-native-access=ALL-UNNAMED", // https://issues.apache.org/jira/browse/MNG-8248 + "--sun-misc-unsafe-memory-access=allow" // https://issues.apache.org/jira/browse/MNG-8399 + ); + private static final List FOR_JDK26_AND_LATER = List.of( // + "--enable-final-field-mutation=ALL-UNNAMED" // https://github.com/junit-team/junit-framework/issues/5173 + ); + + static Map forJre(JRE jre) { + var list = new ArrayList(); + if (jre.compareTo(JRE.JAVA_24) >= 0) + list.addAll(FOR_JDK24_AND_LATER); + if (jre.compareTo(JRE.JAVA_26) >= 0) { + // exclude "leyden" and "valhalla" builds + if (Runtime.version().build().orElse(0) >= 25) { + list.addAll(FOR_JDK26_AND_LATER); + } + } + return list.isEmpty() ? Map.of() : Map.of("MAVEN_OPTS", String.join(" ", list)); + } private MavenEnvVars() { } - } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenPomFileTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenPomFileTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenPomFileTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenPomFileTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenRepoProxy.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenRepoProxy.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenRepoProxy.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenRepoProxy.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support.tests; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.List; + +import com.sun.net.httpserver.HttpServer; + +public class MavenRepoProxy implements AutoCloseable { + + // Forbid downloading JUnit artifacts since we want to use the local ones + private static final List FORBIDDEN_PATHS = List.of("/org/junit"); + + private final HttpServer httpServer; + + @SuppressWarnings("unused") + public MavenRepoProxy() throws IOException { + this(0); + } + + @SuppressWarnings("unused") + public MavenRepoProxy(int port) throws IOException { + this("https://central.sonatype.com/repository/maven-snapshots", port); + } + + private MavenRepoProxy(String proxiedUrl, int port) throws IOException { + httpServer = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), port), 0); + httpServer.createContext("/", exchange -> { + try (exchange) { + switch (exchange.getRequestMethod()) { + case "HEAD": + case "GET": + if (FORBIDDEN_PATHS.stream().anyMatch( + it -> exchange.getRequestURI().getPath().startsWith(it))) { + exchange.sendResponseHeaders(404, -1); + break; + } + var redirectUrl = proxiedUrl + exchange.getRequestURI().getPath(); + exchange.getResponseHeaders().add("Location", redirectUrl); + exchange.sendResponseHeaders(302, -1); + break; + default: + exchange.sendResponseHeaders(405, -1); + } + } + catch (Exception e) { + e.printStackTrace(); + } + }); + httpServer.start(); + } + + URI getBaseUri() { + var address = httpServer.getAddress(); + return URI.create("http://" + address.getAddress().getHostName() + ":" + address.getPort()); + } + + @Override + public void close() { + httpServer.stop(0); + } + +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenStarterTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenStarterTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenStarterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenStarterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,47 +12,86 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; import static platform.tooling.support.tests.XmlAssertions.verifyContainsExpectedStartedOpenTestReport; +import java.nio.file.Path; + +import de.skuzzle.test.snapshots.Snapshot; +import de.skuzzle.test.snapshots.junit5.EnableSnapshotTests; + +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.tests.process.OutputFiles; +import org.junit.platform.tests.process.ProcessResult; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.3 */ +@EnableSnapshotTests +//@SnapshotTestOptions(alwaysPersistActualResult = true) class MavenStarterTests { - @ResourceLock(Projects.MAVEN_STARTER) + @ManagedResource + LocalMavenRepo localMavenRepo; + + @ManagedResource + MavenRepoProxy mavenRepoProxy; + + @TempDir + Path workspace; + + @BeforeEach + void prepareWorkspace() throws Exception { + copyToWorkspace(Projects.JUPITER_STARTER, workspace); + } + + @Test + void verifyJupiterStarterProject(@FilePrefix("maven") OutputFiles outputFiles, Snapshot snapshot) throws Exception { + + var result = runMaven(outputFiles, "verify"); + + assertThat(result.stdOutLines()).contains("[INFO] Tests run: 13, Failures: 0, Errors: 0, Skipped: 0"); + assertThat(result.stdOut()).contains("Using Java version: 1.8"); + + var testResultsDir = workspace.resolve("target/surefire-reports"); + verifyContainsExpectedStartedOpenTestReport(testResultsDir, snapshot); + } + @Test - void verifyMavenStarterProject() { - var request = Request.builder() // - .setTool(Request.maven()) // - .setProject(Projects.MAVEN_STARTER) // - .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // - .addArguments("--update-snapshots", "--batch-mode", "verify") // - .setTimeout(TOOL_TIMEOUT) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .build(); - - var result = request.run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - - assertEquals(0, result.getExitCode()); - assertEquals("", result.getOutput("err")); - assertTrue(result.getOutputLines("out").contains("[INFO] BUILD SUCCESS")); - assertTrue(result.getOutputLines("out").contains("[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0")); - assertThat(result.getOutput("out")).contains("Using Java version: 1.8"); + void runOnlyOneMethodInClassTemplate(@FilePrefix("maven") OutputFiles outputFiles) throws Exception { + + var result = runMaven(outputFiles, "test", "-Dtest=CalculatorParameterizedClassTests$Inner#regularTest"); + + assertThat(result.stdOutLines()) // + .doesNotContain("CalculatorTests") // + .contains("[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0"); + + result = runMaven(outputFiles, "test", "-Dtest=CalculatorParameterizedClassTests#parameterizedTest"); + + assertThat(result.stdOutLines()) // + .doesNotContain("CalculatorTests") // + .contains("[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0"); + } - var testResultsDir = Request.WORKSPACE.resolve(request.getWorkspace()).resolve("target/surefire-reports"); - verifyContainsExpectedStartedOpenTestReport(testResultsDir); + private ProcessResult runMaven(OutputFiles outputFiles, String... extraArgs) throws InterruptedException { + var result = ProcessStarters.maven(Helper.getJavaHome(8).orElseThrow(TestAbortedException::new)) // + .workingDir(workspace) // + .addArguments(localMavenRepo.toCliArgument(), "-Dmaven.repo=" + MavenRepo.dir()) // + .addArguments("-Dsnapshot.repo.url=" + mavenRepoProxy.getBaseUri()) // + .addArguments("--update-snapshots", "--batch-mode") // + .addArguments(extraArgs).redirectOutput(outputFiles) // + .startAndWait(); + + assertEquals(0, result.exitCode()); + assertEquals("", result.stdErr()); + assertThat(result.stdOutLines()).contains("[INFO] BUILD SUCCESS"); + return result; } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenSurefireCompatibilityTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenSurefireCompatibilityTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenSurefireCompatibilityTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MavenSurefireCompatibilityTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,58 +12,55 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; -import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.platform.tests.process.OutputFiles; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.9.2 */ class MavenSurefireCompatibilityTests { - @ResourceLock(Projects.MAVEN_SUREFIRE_COMPATIBILITY) + @ManagedResource + LocalMavenRepo localMavenRepo; + @ParameterizedTest @CsvSource(delimiter = '|', nullValues = "", textBlock = """ 2.22.2 | --activate-profiles=manual-platform-dependency 3.0.0-M4 | """) - void testMavenSurefireCompatibilityProject(String surefireVersion, String extraArg) throws IOException { - var extraArgs = extraArg == null ? new Object[0] : new Object[] { extraArg }; - var request = Request.builder() // - .setTool(Request.maven()) // - .setProject(Projects.MAVEN_SUREFIRE_COMPATIBILITY) // - .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // + void testMavenSurefireCompatibilityProject(String surefireVersion, String extraArg, @TempDir Path workspace, + @FilePrefix("maven") OutputFiles outputFiles) throws Exception { + var extraArgs = extraArg == null ? new String[0] : new String[] { extraArg }; + var result = ProcessStarters.maven(Helper.getJavaHome(8).orElseThrow(TestAbortedException::new)) // + .workingDir(copyToWorkspace(Projects.MAVEN_SUREFIRE_COMPATIBILITY, workspace)) // + .addArguments(localMavenRepo.toCliArgument(), "-Dmaven.repo=" + MavenRepo.dir()) // .addArguments("-Dsurefire.version=" + surefireVersion) // .addArguments("--update-snapshots", "--batch-mode", "test") // .addArguments(extraArgs) // - .setTimeout(TOOL_TIMEOUT) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .build(); - - var result = request.run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode()); - assertEquals("", result.getOutput("err")); + assertEquals(0, result.exitCode()); + assertEquals("", result.stdErr()); - var output = result.getOutputLines("out"); + var output = result.stdOutLines(); assertTrue(output.contains("[INFO] BUILD SUCCESS")); assertTrue(output.contains("[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0")); - var targetDir = Request.WORKSPACE.resolve(request.getWorkspace()).resolve("target"); + var targetDir = workspace.resolve("target"); try (var stream = Files.list(targetDir)) { assertThat(stream.filter(file -> file.getFileName().toString().startsWith("junit-platform-unique-ids"))) // .hasSize(1); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ModularUserGuideTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ModularUserGuideTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ModularUserGuideTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ModularUserGuideTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static platform.tooling.support.Helper.loadModuleDirectoryNames; import java.io.File; import java.io.PrintWriter; @@ -23,14 +23,18 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.spi.ToolProvider; -import org.codehaus.groovy.runtime.ProcessGroovyMethods; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.DisabledOnOpenJ9; import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.launcher.LauncherConstants; +import org.junit.platform.tests.process.OutputFiles; -import platform.tooling.support.Helper; +import platform.tooling.support.MavenRepo; +import platform.tooling.support.ProcessStarters; import platform.tooling.support.ThirdPartyJars; /** @@ -86,9 +90,10 @@ ThirdPartyJars.copy(lib, "org.apiguardian", "apiguardian-api"); ThirdPartyJars.copy(lib, "org.hamcrest", "hamcrest"); ThirdPartyJars.copy(lib, "org.opentest4j", "opentest4j"); + ThirdPartyJars.copy(lib, "org.opentest4j.reporting", "open-test-reporting-tooling-spi"); ThirdPartyJars.copy(lib, "com.google.jimfs", "jimfs"); ThirdPartyJars.copy(lib, "com.google.guava", "guava"); - Helper.loadAllJUnitModules(lib); + loadAllJUnitModules(lib); args.add("--module-path"); args.add(lib.toString()); @@ -117,64 +122,38 @@ return args; } - private static void junit(Path temp, Writer out, Writer err) throws Exception { - var command = new ArrayList(); - var projectDir = Path.of("../documentation"); - command.add(Path.of(System.getProperty("java.home"), "bin", "java").toString()); - - command.add("-XX:StartFlightRecording:filename=" + temp.resolve("user-guide.jfr")); - - command.add("--show-version"); - command.add("--show-module-resolution"); - - command.add("--module-path"); - command.add(String.join(File.pathSeparator, // - temp.resolve("destination").toString(), // - temp.resolve("lib").toString() // - )); - - command.add("--add-modules"); - command.add("documentation"); - - // TODO This `patch-module` should work! Why doesn't it? - // command.add("--patch-module"); - // command.add("documentation=../documentation/src/test/resources/"); - Files.copy(projectDir.resolve("src/test/resources/two-column.csv"), - temp.resolve("destination/documentation/two-column.csv")); - - command.add("--module"); - command.add("org.junit.platform.console"); - - command.add("--scan-modules"); - - command.add("--config"); - command.add("enableHttpServer=true"); - - command.add("--fail-if-no-tests"); - command.add("--include-classname"); - command.add(".*Tests"); - command.add("--include-classname"); - command.add(".*Demo"); - command.add("--exclude-tag"); - command.add("exclude"); + private static void junit(Path temp, OutputFiles outputFiles) throws Exception { + var projectDir = Path.of("../documentation").toAbsolutePath(); - // System.out.println("______________"); - // command.forEach(System.out::println); + var result = ProcessStarters.java() // + .workingDir(projectDir) // + .addArguments("-XX:StartFlightRecording:filename=" + temp.resolve("user-guide.jfr")) // + .addArguments("--show-version", "--show-module-resolution") // + .addArguments("--module-path", String.join(File.pathSeparator, // + temp.resolve("destination").toString(), // + temp.resolve("lib").toString() // + )) // + .addArguments("--add-modules", "documentation") // + .addArguments("--patch-module", "documentation=" + projectDir.resolve("src/test/resources")) // + .addArguments("--module", "org.junit.platform.console") // + .addArguments("execute") // + .addArguments("--scan-modules") // + .addArguments("--config", "enableHttpServer=true") // + .addArguments("--config", LauncherConstants.OUTPUT_DIR_PROPERTY_NAME + "=" + temp.resolve("reports")) // + .addArguments("--fail-if-no-tests") // + .addArguments("--include-classname", ".*Tests") // + .addArguments("--include-classname", ".*Demo") // + .addArguments("--exclude-tag", "exclude") // + .addArguments("--exclude-tag", "exclude") // + .redirectOutput(outputFiles) // + .startAndWait(); - var builder = new ProcessBuilder(command).directory(projectDir.toFile()); - var java = builder.start(); - ProcessGroovyMethods.waitForProcessOutput(java, out, err); - var code = java.exitValue(); - - if (code != 0) { - System.out.println(out); - System.err.println(err); - fail("Unexpected exit code: " + code); - } + assertEquals(0, result.exitCode()); } @Test - void runTestsFromUserGuideWithinModularBoundaries(@TempDir Path temp) throws Exception { + void runTestsFromUserGuideWithinModularBoundaries(@TempDir Path temp, + @FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { var out = new StringWriter(); var err = new StringWriter(); @@ -182,7 +161,7 @@ // args.forEach(System.out::println); assertTrue(err.toString().isBlank(), () -> err + "\n\n" + String.join("\n", args)); - var listing = Helper.treeWalk(temp); + var listing = treeWalk(temp); assertLinesMatch(List.of( // "destination", // ">> CLASSES >>", // @@ -203,7 +182,32 @@ // System.out.println("______________"); // listing.forEach(System.out::println); - junit(temp, out, err); + junit(temp, outputFiles); + } + + private static void loadAllJUnitModules(Path target) throws Exception { + for (var module : loadModuleDirectoryNames()) { + var jar = MavenRepo.jar(module); + Files.copy(jar, target.resolve(jar.getFileName())); + } + } + + private static List treeWalk(Path root) { + var lines = new ArrayList(); + treeWalk(root, lines::add); + return lines; + } + + private static void treeWalk(Path root, Consumer out) { + try (var stream = Files.walk(root)) { + stream.map(root::relativize) // + .map(path -> path.toString().replace('\\', '/')) // + .sorted().filter(Predicate.not(String::isEmpty)) // + .forEach(out); + } + catch (Exception e) { + throw new Error("Walking tree failed: " + root, e); + } } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MultiReleaseJarTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MultiReleaseJarTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MultiReleaseJarTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/MultiReleaseJarTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -14,30 +14,33 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertTrue; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import java.util.Map; - -import de.sormuras.bartholdy.Result; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.tests.process.OutputFiles; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.4 */ class MultiReleaseJarTests { - @ResourceLock(Projects.MULTI_RELEASE_JAR) + @ManagedResource + LocalMavenRepo localMavenRepo; + + @ManagedResource + MavenRepoProxy mavenRepoProxy; + @Test - void checkDefault() throws Exception { - var variant = "default"; + void checkDefault(@TempDir Path workspace, @FilePrefix("maven") OutputFiles outputFiles) throws Exception { var expectedLines = List.of( // ">> BANNER >>", // ".", // @@ -68,37 +71,26 @@ "" // ); - var result = mvn(variant); + var result = ProcessStarters.maven() // + .workingDir(copyToWorkspace(Projects.MULTI_RELEASE_JAR, workspace)) // + .addArguments(localMavenRepo.toCliArgument(), "-Dmaven.repo=" + MavenRepo.dir()) // + .addArguments("-Dsnapshot.repo.url=" + mavenRepoProxy.getBaseUri()) // + .addArguments("--update-snapshots", "--show-version", "--errors", "--batch-mode") // + .addArguments("test") // + .putEnvironment(MavenEnvVars.forJre(JRE.currentJre())) // + .redirectOutput(outputFiles) // + .startAndWait(); + + assertEquals(0, result.exitCode()); + assertEquals("", result.stdErr()); + + var outputLines = result.stdOutLines(); + assertTrue(outputLines.contains("[INFO] BUILD SUCCESS")); + assertFalse(outputLines.contains("[WARNING] "), "Warning marker detected"); + assertFalse(outputLines.contains("[ERROR] "), "Error marker detected"); - result.getOutputLines("out").forEach(System.out::println); - result.getOutputLines("err").forEach(System.err::println); - - assertEquals(0, result.getExitCode()); - assertEquals("", result.getOutput("err")); - assertTrue(result.getOutputLines("out").contains("[INFO] BUILD SUCCESS")); - - var workspace = Path.of("build/test-workspace/multi-release-jar", variant); var actualLines = Files.readAllLines(workspace.resolve("target/junit-platform/console-launcher.out.log")); assertLinesMatch(expectedLines, actualLines); } - private Result mvn(String variant) { - Map environmentVars = MavenEnvVars.FOR_JDK24_AND_LATER; - - var builder = Request.builder() // - .setTool(Request.maven()) // - .setProject(Projects.MULTI_RELEASE_JAR) // - .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // - .addArguments("--update-snapshots", "--show-version", "--errors", "--batch-mode", "--file", variant, - "test") // - .setTimeout(TOOL_TIMEOUT); - environmentVars.forEach(builder::putEnvironment); - - var result = builder.build().run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - - return result; - } - } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/OutputAttachingExtension.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/OutputAttachingExtension.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/OutputAttachingExtension.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/OutputAttachingExtension.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,100 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support.tests; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; + +import org.junit.jupiter.api.MediaType; +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.platform.tests.process.OutputFiles; +import org.junit.platform.tests.process.ProcessStarter; + +class OutputAttachingExtension implements ParameterResolver, AfterTestExecutionCallback { + + private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create( + OutputAttachingExtension.class); + private static final MediaType MEDIA_TYPE = MediaType.create("text", "plain", ProcessStarter.OUTPUT_ENCODING); + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return parameterContext.isAnnotated(FilePrefix.class); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + var outputDir = extensionContext.getStore(NAMESPACE).getOrComputeIfAbsent("outputDir", __ -> { + try { + return new OutputDir(Files.createTempDirectory("output")); + } + catch (Exception e) { + throw new ParameterResolutionException("Failed to create temp directory", e); + } + }, OutputDir.class); + var prefix = parameterContext.findAnnotation(FilePrefix.class) // + .map(FilePrefix::value) // + .orElseThrow(); + return outputDir.toOutputFiles(prefix); + } + + @Override + public void afterTestExecution(ExtensionContext context) throws Exception { + var outputDir = context.getStore(NAMESPACE).get("outputDir", OutputDir.class); + if (outputDir != null) { + try (var stream = Files.list(outputDir.root()).filter(Files::isRegularFile).sorted()) { + stream.filter(OutputAttachingExtension::notEmpty).forEach(file -> { + var fileName = file.getFileName().toString(); + context.publishFile(fileName, MEDIA_TYPE, target -> Files.copy(file, target)); + }); + } + } + } + + private static boolean notEmpty(Path file) { + try { + return Files.size(file) > 0; + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @SuppressWarnings("try") + record OutputDir(Path root) implements AutoCloseable { + + @Override + public void close() throws Exception { + try (var stream = Files.walk(root).sorted(Comparator. naturalOrder().reversed())) { + stream.forEach(path -> { + try { + Files.delete(path); + } + catch (IOException e) { + throw new UncheckedIOException("Failed to delete " + path, e); + } + }); + } + } + + private OutputFiles toOutputFiles(String prefix) { + return new OutputFiles(root.resolve(prefix + "-stdout.txt"), root.resolve(prefix + "-stderr.txt")); + } + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/PackageCyclesDetectionTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/PackageCyclesDetectionTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/PackageCyclesDetectionTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/PackageCyclesDetectionTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package platform.tooling.support.tests; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import de.sormuras.bartholdy.Configuration; -import de.sormuras.bartholdy.tool.CyclesDetector; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import platform.tooling.support.MavenRepo; - -/** - * @since 1.3 - */ -class PackageCyclesDetectionTests { - - @ParameterizedTest - @MethodSource("platform.tooling.support.Helper#loadModuleDirectoryNames") - @Disabled("Need to pass --module-path...") - void moduleDoesNotContainCyclicPackageReferences(String module) { - var jar = MavenRepo.jar(module); - var result = new CyclesDetector(jar, this::ignore).run(Configuration.of()); - assertEquals(0, result.getExitCode(), "result=" + result); - } - - private boolean ignore(String source, String target) { - if (source.equals(target)) { - return true; - } - if (source.startsWith("org.junit.jupiter.params.shadow.com.univocity.parsers.")) { - return true; - } - //noinspection RedundantIfStatement - if (!target.startsWith("org.junit.")) { - return true; - } - return false; - } - -} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/Projects.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/Projects.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/Projects.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/Projects.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,16 +10,19 @@ package platform.tooling.support.tests; +import java.io.IOException; +import java.nio.file.Path; + +import org.apache.commons.io.file.PathUtils; + public class Projects { - public static final String ANT_STARTER = "ant-starter"; public static final String GRAALVM_STARTER = "graalvm-starter"; public static final String GRADLE_KOTLIN_EXTENSIONS = "gradle-kotlin-extensions"; public static final String GRADLE_MISSING_ENGINE = "gradle-missing-engine"; - public static final String GRADLE_STARTER = "gradle-starter"; public static final String JAR_DESCRIBE_MODULE = "jar-describe-module"; public static final String JAVA_VERSIONS = "java-versions"; - public static final String MAVEN_STARTER = "maven-starter"; + public static final String JUPITER_STARTER = "jupiter-starter"; public static final String MAVEN_SUREFIRE_COMPATIBILITY = "maven-surefire-compatibility"; public static final String MULTI_RELEASE_JAR = "multi-release-jar"; public static final String REFLECTION_TESTS = "reflection-tests"; @@ -28,4 +31,13 @@ private Projects() { } + + static Path copyToWorkspace(String project, Path workspace) throws IOException { + PathUtils.copyDirectory(getSourceDirectory(project), workspace); + return workspace; + } + + static Path getSourceDirectory(String project) { + return Path.of("projects").resolve(project); + } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ReflectionCompatibilityTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ReflectionCompatibilityTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ReflectionCompatibilityTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ReflectionCompatibilityTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -12,45 +12,37 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; -import java.nio.file.Paths; - -import de.sormuras.bartholdy.tool.GradleWrapper; +import java.nio.file.Path; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.tests.process.OutputFiles; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; /** * @since 1.11 */ class ReflectionCompatibilityTests { - @ResourceLock(Projects.REFLECTION_TESTS) @Test - void gradle_wrapper() { - var request = Request.builder() // - .setTool(new GradleWrapper(Paths.get(".."))) // - .setProject(Projects.REFLECTION_TESTS) // + void gradle_wrapper(@TempDir Path workspace, @FilePrefix("gradle") OutputFiles outputFiles) throws Exception { + var result = ProcessStarters.gradlew() // + .workingDir(copyToWorkspace(Projects.REFLECTION_TESTS, workspace)) // .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // - .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache") // - .setTimeout(TOOL_TIMEOUT) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .build(); - - var result = request.run(); - - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - - assertEquals(0, result.getExitCode()); - assertTrue(result.getOutputLines("out").stream().anyMatch(line -> line.contains("BUILD SUCCESSFUL"))); - assertThat(result.getOutput("out")).contains("Using Java version: 1.8"); + .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache", "--warning-mode=fail") // + .putEnvironment("JDK8", Helper.getJavaHome(8).orElseThrow(TestAbortedException::new).toString()) // + .redirectOutput(outputFiles) // + .startAndWait(); + + assertEquals(0, result.exitCode()); + assertTrue(result.stdOut().lines().anyMatch(line -> line.contains("BUILD SUCCESSFUL"))); + assertThat(result.stdOut()).contains("Using Java version: 1.8"); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -15,6 +15,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT; +import static org.junit.jupiter.api.parallel.ExecutionMode.SAME_THREAD; +import static platform.tooling.support.tests.Projects.copyToWorkspace; +import static platform.tooling.support.tests.Projects.getSourceDirectory; import java.io.File; import java.io.IOException; @@ -25,31 +29,37 @@ import java.util.List; import java.util.stream.Stream; -import de.sormuras.bartholdy.Result; -import de.sormuras.bartholdy.jdk.Jar; -import de.sormuras.bartholdy.jdk.Javac; -import de.sormuras.bartholdy.tool.Java; - -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.platform.tests.process.OutputFiles; +import org.junit.platform.tests.process.ProcessResult; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; import platform.tooling.support.ThirdPartyJars; /** * @since 1.4 */ @TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@Execution(CONCURRENT) class StandaloneTests { - @ResourceLock(Projects.STANDALONE) + @TempDir + static Path workspace; + + @BeforeAll + static void prepareWorkspace() throws IOException { + copyToWorkspace(Projects.STANDALONE, workspace); + } + @Test void jarFileWithoutCompiledModuleDescriptorClass() throws Exception { var jar = MavenRepo.jar("junit-platform-console-standalone"); @@ -66,17 +76,16 @@ assertTrue(found.isEmpty(), jar + " must not contain any " + name + " files: " + found); } - @ResourceLock(Projects.STANDALONE) @Test - void listAllObservableEngines() { - var result = Request.builder() // - .setTool(new Java()) // - .setProject(Projects.STANDALONE) // - .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone")) // - .addArguments("engines", "--disable-ansi-colors", "--disable-banner").build() // - .run(false); + void listAllObservableEngines(@FilePrefix("java") OutputFiles outputFiles) throws Exception { + var result = ProcessStarters.java() // + .workingDir(getSourceDirectory(Projects.STANDALONE)) // + .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone").toString()) // + .addArguments("engines", "--disable-ansi-colors", "--disable-banner") // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); + assertEquals(0, result.exitCode()); var jupiterVersion = Helper.version("junit-jupiter-engine"); var suiteVersion = Helper.version("junit-platform-suite-engine"); @@ -86,22 +95,20 @@ junit-platform-suite (org.junit.platform:junit-platform-suite-engine:%s) junit-vintage (org.junit.vintage:junit-vintage-engine:%s) """.formatted(jupiterVersion, suiteVersion, vintageVersion).lines(), // - result.getOutput("out").lines()); + result.stdOut().lines()); } - @ResourceLock(Projects.STANDALONE) @Test - void printVersionViaJar() { - var result = Request.builder() // - .setTool(new Java()) // - .setProject(Projects.STANDALONE) // - .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone")) // + void printVersionViaJar(@FilePrefix("java") OutputFiles outputFiles) throws Exception { + var result = ProcessStarters.java() // + .workingDir(getSourceDirectory(Projects.STANDALONE)) // + .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone").toString()) // .addArguments("--version", "--disable-ansi-colors") // .putEnvironment("CLICOLOR_FORCE", "1") // enable ANSI colors by default (see https://picocli.info/#_heuristics_for_enabling_ansi) - .build() // - .run(); + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); + assertEquals(0, result.exitCode()); var version = Helper.version("junit-platform-console"); assertLinesMatch(""" @@ -109,30 +116,31 @@ JVM: .* OS: .* """.formatted(version).lines(), // - result.getOutputLines("out").stream()); + result.stdOut().lines()); } - @ResourceLock(Projects.STANDALONE) @Test - void printVersionViaModule() { + void printVersionViaModule(@FilePrefix("java") OutputFiles outputFiles) throws Exception { var junitJars = Stream.of("junit-platform-console", "junit-platform-reporting", "junit-platform-engine", "junit-platform-launcher", "junit-platform-commons") // .map(MavenRepo::jar); - var thirdPartyJars = Stream.of(ThirdPartyJars.find("org.opentest4j", "opentest4j")); + var thirdPartyJars = Stream.of( // + ThirdPartyJars.find("org.opentest4j", "opentest4j"), // + ThirdPartyJars.find("org.opentest4j.reporting", "open-test-reporting-tooling-spi") // + ); var modulePath = Stream.concat(junitJars, thirdPartyJars) // .map(String::valueOf) // .collect(joining(File.pathSeparator)); - var result = Request.builder() // - .setTool(new Java()) // - .setProject(Projects.STANDALONE) // + var result = ProcessStarters.java() // + .workingDir(getSourceDirectory(Projects.STANDALONE)) // .addArguments("--module-path", modulePath) // .addArguments("--module", "org.junit.platform.console") // .addArguments("--version", "--disable-ansi-colors") // .putEnvironment("CLICOLOR_FORCE", "1") // enable ANSI colors by default (see https://picocli.info/#_heuristics_for_enabling_ansi) - .build() // - .run(); + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); + assertEquals(0, result.exitCode()); var version = Helper.version("junit-platform-console"); assertLinesMatch(""" @@ -140,49 +148,38 @@ JVM: .* OS: .* """.formatted(version).lines(), // - result.getOutputLines("out").stream()); + result.stdOut().lines()); } - @ResourceLock(Projects.STANDALONE) @Test @Order(1) - void compile() throws Exception { - var workspace = Request.WORKSPACE.resolve(Projects.STANDALONE); - var result = Request.builder() // - .setTool(new Javac()) // - .setProject(Projects.STANDALONE) // + @Execution(SAME_THREAD) + void compile(@FilePrefix("javac") OutputFiles javacOutputFiles) throws Exception { + var result = ProcessStarters.javaCommand("javac") // + .workingDir(workspace) // .addArguments("-Xlint:-options") // .addArguments("--release", "8") // .addArguments("-proc:none") // - .addArguments("-d", workspace.resolve("bin")) // - .addArguments("--class-path", MavenRepo.jar("junit-platform-console-standalone")) // - .addArguments(workspace.resolve("src/standalone/JupiterIntegration.java")) // - .addArguments(workspace.resolve("src/standalone/JupiterParamsIntegration.java")) // - .addArguments(workspace.resolve("src/standalone/SuiteIntegration.java")) // - .addArguments(workspace.resolve("src/standalone/VintageIntegration.java")).build() // - .run(); - - assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); - assertTrue(result.getOutput("out").isEmpty()); - assertTrue(result.getOutput("err").isEmpty()); - - // create "tests.jar" that'll be picked-up by "testWithJarredTestClasses()" later - var jarFolder = Files.createDirectories(workspace.resolve("jar")); - var jarResult = Request.builder() // - .setTool(new Jar()) // - .setProject(Projects.STANDALONE) // - .addArguments("--create") // - .addArguments("--file", jarFolder.resolve("tests.jar")) // - .addArguments("-C", workspace.resolve("bin"), ".") // - .build().run(false); - assertEquals(0, jarResult.getExitCode(), String.join("\n", jarResult.getOutputLines("out"))); + .addArguments("-d", workspace.resolve("bin").toString()) // + .addArguments("--class-path", MavenRepo.jar("junit-platform-console-standalone").toString()) // + .addArguments(workspace.resolve("src/other/OtherwiseNotReferencedClass.java").toString()) // + .addArguments(workspace.resolve("src/standalone/JupiterIntegration.java").toString()) // + .addArguments(workspace.resolve("src/standalone/JupiterParamsIntegration.java").toString()) // + .addArguments(workspace.resolve("src/standalone/SuiteIntegration.java").toString()) // + .addArguments(workspace.resolve("src/standalone/VintageIntegration.java").toString()) // + .redirectOutput(javacOutputFiles) // + .startAndWait(); + + assertEquals(0, result.exitCode()); + assertTrue(result.stdOut().isEmpty()); + assertTrue(result.stdErr().isEmpty()); } - @ResourceLock(Projects.STANDALONE) @Test @Order(2) - void discoverTree() { - Result result = discover("--details-theme=ascii"); + @Execution(SAME_THREAD) + void discoverTree(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var result = discover(outputFiles, "--details-theme=ascii"); var expected = """ . @@ -211,14 +208,14 @@ [ 9 tests found ] """.stripIndent(); - assertLinesMatch(expected.lines(), result.getOutputLines("out").stream()); + assertLinesMatch(expected.lines(), result.stdOut().lines()); } - @ResourceLock(Projects.STANDALONE) @Test @Order(2) - void discoverFlat() { - Result result = discover("--details=flat"); + @Execution(SAME_THREAD) + void discoverFlat(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var result = discover(outputFiles, "--details=flat"); var expected = """ JUnit Platform Suite ([engine:junit-platform-suite]) @@ -246,13 +243,14 @@ [ 9 tests found ] """.stripIndent(); - assertLinesMatch(expected.lines(), result.getOutputLines("out").stream()); + assertLinesMatch(expected.lines(), result.stdOut().lines()); } @Test @Order(2) - void discoverVerbose() { - Result result = discover("--details=verbose", "--details-theme=ascii"); + @Execution(SAME_THREAD) + void discoverVerbose(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var result = discover(outputFiles, "--details=verbose", "--details-theme=ascii"); var expected = """ +-- JUnit Platform Suite @@ -330,23 +328,23 @@ [ 9 tests found ] """.stripIndent(); - assertLinesMatch(expected.lines(), result.getOutputLines("out").stream()); + assertLinesMatch(expected.lines(), result.stdOut().lines()); } - @ResourceLock(Projects.STANDALONE) @Test @Order(2) - void discoverNone() { - Result result = discover("--details=none"); + @Execution(SAME_THREAD) + void discoverNone(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var result = discover(outputFiles, "--details=none"); - assertThat(result.getOutputLines("out")).isEmpty(); + assertThat(result.stdOut()).isEmpty(); } - @ResourceLock(Projects.STANDALONE) @Test @Order(2) - void discoverSummary() { - Result result = discover("--details=summary"); + @Execution(SAME_THREAD) + void discoverSummary(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var result = discover(outputFiles, "--details=summary"); var expected = """ @@ -354,14 +352,14 @@ [ 9 tests found ] """.stripIndent(); - assertLinesMatch(expected.lines(), result.getOutputLines("out").stream()); + assertLinesMatch(expected.lines(), result.stdOut().lines()); } - @ResourceLock(Projects.STANDALONE) @Test @Order(2) - void discoverTestFeed() { - Result result = discover("--details=testfeed"); + @Execution(SAME_THREAD) + void discoverTestFeed(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var result = discover(outputFiles, "--details=testfeed"); var expected = """ JUnit Platform Suite > SuiteIntegration > JUnit Jupiter > SuiteIntegration$SingleTestContainer > successful() JUnit Jupiter > JupiterIntegration > successful() @@ -378,142 +376,120 @@ """.stripIndent(); - assertLinesMatch(expected.lines(), result.getOutputLines("out").stream()); + assertLinesMatch(expected.lines(), result.stdOut().lines()); } - private static Result discover(String... args) { - var result = Request.builder() // + private static ProcessResult discover(OutputFiles outputFiles, String... args) throws Exception { + var result = ProcessStarters.java() // + .workingDir(workspace) // .putEnvironment("NO_COLOR", "1") // --disable-ansi-colors - .setTool(new Java()) // - .setProject(Projects.STANDALONE) // - .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone")) // + .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone").toString()) // .addArguments("discover") // .addArguments("--scan-class-path") // .addArguments("--disable-banner") // .addArguments("--include-classname", "standalone.*") // .addArguments("--classpath", "bin") // - .addArguments((Object[]) args) // - .build() // - .run(false); + .addArguments(args) // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); + assertEquals(0, result.exitCode()); return result; } - @ResourceLock(Projects.STANDALONE) @Test @Order(3) - void execute() throws IOException { - var result = Request.builder() // + @Execution(SAME_THREAD) + void execute(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var result = ProcessStarters.java() // + .workingDir(workspace) // .putEnvironment("NO_COLOR", "1") // --disable-ansi-colors - .setTool(new Java()) // - .setProject(Projects.STANDALONE) // .addArguments("--show-version") // .addArguments("-enableassertions") // .addArguments("-Djava.util.logging.config.file=logging.properties") // .addArguments("-Djunit.platform.launcher.interceptors.enabled=true") // - .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone")) // + .addArguments("-Duser.language=en", "-Duser.country=US") // + .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone").toString()) // .addArguments("execute") // .addArguments("--scan-class-path") // .addArguments("--disable-banner") // .addArguments("--include-classname", "standalone.*") // - .addArguments("--classpath", "bin").build() // - .run(false); + .addArguments("--classpath", "bin") // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); + assertEquals(1, result.exitCode()); - var workspace = Request.WORKSPACE.resolve(Projects.STANDALONE); - var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); - var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err.txt")); - assertLinesMatch(expectedOutLines, result.getOutputLines("out")); - List actualErrLines = result.getOutputLines("err"); - if (actualErrLines.getFirst().contains("stty: /dev/tty: No such device or address")) { - // Happens intermittently on GitHub Actions on Windows - actualErrLines = new ArrayList<>(actualErrLines); - actualErrLines.removeFirst(); - } - assertLinesMatch(expectedErrLines, actualErrLines); - - var jupiterVersion = Helper.version("junit-jupiter-engine"); - var vintageVersion = Helper.version("junit-vintage-engine"); - assertTrue(result.getOutput("err").contains("junit-jupiter" - + " (group ID: org.junit.jupiter, artifact ID: junit-jupiter-engine, version: " + jupiterVersion)); - assertTrue(result.getOutput("err").contains("junit-vintage" - + " (group ID: org.junit.vintage, artifact ID: junit-vintage-engine, version: " + vintageVersion)); + assertOutputOnCurrentJvm(result); } - @ResourceLock(Projects.STANDALONE) @Test @Order(4) - void executeOnJava8() throws IOException { - Java java8 = getJava8(); - var result = Request.builder() // - .setTool(java8) // - .setJavaHome(java8.getHome()) // - .setProject(Projects.STANDALONE) // + @Execution(SAME_THREAD) + void executeOnJava8(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var java8Home = Helper.getJavaHome(8).orElseThrow(TestAbortedException::new); + var result = ProcessStarters.java(java8Home) // + .workingDir(workspace) // .addArguments("-showversion") // .addArguments("-enableassertions") // .addArguments("-Djava.util.logging.config.file=logging.properties") // .addArguments("-Djunit.platform.launcher.interceptors.enabled=true") // - .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone")) // + .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone").toString()) // .addArguments("execute") // .addArguments("--scan-class-path") // .addArguments("--disable-banner") // .addArguments("--include-classname", "standalone.*") // - .addArguments("--classpath", "bin").build() // - .run(false); + .addArguments("--classpath", "bin") // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); + assertEquals(1, result.exitCode()); - var workspace = Request.WORKSPACE.resolve(Projects.STANDALONE); var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); var expectedErrLines = getExpectedErrLinesOnJava8(workspace); - assertLinesMatch(expectedOutLines, result.getOutputLines("out")); - assertLinesMatch(expectedErrLines, result.getOutputLines("err")); + assertLinesMatch(expectedOutLines, result.stdOutLines()); + assertLinesMatch(expectedErrLines, result.stdErrLines()); var jupiterVersion = Helper.version("junit-jupiter-engine"); var vintageVersion = Helper.version("junit-vintage-engine"); - assertTrue(result.getOutput("err").contains("junit-jupiter" + assertTrue(result.stdErr().contains("junit-jupiter" + " (group ID: org.junit.jupiter, artifact ID: junit-jupiter-engine, version: " + jupiterVersion)); - assertTrue(result.getOutput("err").contains("junit-vintage" + assertTrue(result.stdErr().contains("junit-vintage" + " (group ID: org.junit.vintage, artifact ID: junit-vintage-engine, version: " + vintageVersion)); } - @ResourceLock(Projects.STANDALONE) @Test @Order(5) - // https://github.com/junit-team/junit5/issues/2600 - void executeOnJava8SelectPackage() throws IOException { - Java java8 = getJava8(); - var result = Request.builder() // - .setTool(java8) // - .setJavaHome(java8.getHome()) // - .setProject(Projects.STANDALONE) // - .addArguments("-showversion") // + @Execution(SAME_THREAD) + // https://github.com/junit-team/junit-framework/issues/2600 + void executeOnJava8SelectPackage(@FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var java8Home = Helper.getJavaHome(8).orElseThrow(TestAbortedException::new); + var result = ProcessStarters.java(java8Home) // + .workingDir(workspace).addArguments("-showversion") // .addArguments("-enableassertions") // .addArguments("-Djava.util.logging.config.file=logging.properties") // .addArguments("-Djunit.platform.launcher.interceptors.enabled=true") // - .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone")) // + .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone").toString()) // .addArguments("execute") // .addArguments("--select-package", Projects.STANDALONE) // .addArguments("--disable-banner") // .addArguments("--include-classname", "standalone.*") // - .addArguments("--classpath", "bin").build() // - .run(false); + .addArguments("--classpath", "bin") // + .redirectOutput(outputFiles) // + .startAndWait(); - assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); + assertEquals(1, result.exitCode()); - var workspace = Request.WORKSPACE.resolve(Projects.STANDALONE); var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); var expectedErrLines = getExpectedErrLinesOnJava8(workspace); - assertLinesMatch(expectedOutLines, result.getOutputLines("out")); - assertLinesMatch(expectedErrLines, result.getOutputLines("err")); + assertLinesMatch(expectedOutLines, result.stdOutLines()); + assertLinesMatch(expectedErrLines, result.stdErrLines()); var jupiterVersion = Helper.version("junit-jupiter-engine"); var vintageVersion = Helper.version("junit-vintage-engine"); - assertTrue(result.getOutput("err").contains("junit-jupiter" + assertTrue(result.stdErr().contains("junit-jupiter" + " (group ID: org.junit.jupiter, artifact ID: junit-jupiter-engine, version: " + jupiterVersion)); - assertTrue(result.getOutput("err").contains("junit-vintage" + assertTrue(result.stdErr().contains("junit-vintage" + " (group ID: org.junit.vintage, artifact ID: junit-vintage-engine, version: " + vintageVersion)); } @@ -524,55 +500,61 @@ return expectedErrLines; } - @ResourceLock(Projects.STANDALONE) @Test @Order(6) - @Disabled("https://github.com/junit-team/junit5/issues/1724") - void executeWithJarredTestClasses() { - var jar = MavenRepo.jar("junit-platform-console-standalone"); - var path = new ArrayList(); - // path.add("bin"); // "exploded" test classes are found, see also test() above - path.add(Request.WORKSPACE.resolve("standalone/jar/tests.jar").toAbsolutePath().toString()); - path.add(jar.toString()); - var result = Request.builder() // - .setTool(new Java()) // - .setProject(Projects.STANDALONE) // + @Execution(SAME_THREAD) + void executeWithJarredTestClasses(@FilePrefix("jar") OutputFiles jarOutputFiles, + @FilePrefix("console-launcher") OutputFiles outputFiles) throws Exception { + var jar = workspace.resolve("tests.jar"); + var jarResult = ProcessStarters.javaCommand("jar") // + .workingDir(workspace) // + .addArguments("--create") // + .addArguments("--file", jar.toAbsolutePath().toString()) // + .addArguments("-C", workspace.resolve("bin").toString(), ".") // + .redirectOutput(jarOutputFiles) // + .startAndWait(); + + assertEquals(0, jarResult.exitCode()); + + var result = ProcessStarters.java() // + .workingDir(workspace) // + .putEnvironment("NO_COLOR", "1") // --disable-ansi-colors .addArguments("--show-version") // .addArguments("-enableassertions") // .addArguments("-Djava.util.logging.config.file=logging.properties") // - .addArguments("--class-path", String.join(File.pathSeparator, path)) // - .addArguments("org.junit.platform.console.ConsoleLauncher") // + .addArguments("-Djunit.platform.launcher.interceptors.enabled=true") // + .addArguments("-Duser.language=en", "-Duser.country=US") // + .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone").toString()) // .addArguments("execute") // .addArguments("--scan-class-path") // .addArguments("--disable-banner") // .addArguments("--include-classname", "standalone.*") // - .addArguments("--fail-if-no-tests") // - .build() // - .run(false); - - assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); - } - - private static String getExitCodeMessage(Result result) { - return "Exit codes don't match. Stdout:\n" + result.getOutput("out") + // - "\n\nStderr:\n" + result.getOutput("err") + "\n"; - } - - /** - * Special override of class {@link Java} to resolve against a different {@code JAVA_HOME}. - */ - private static Java getJava8() { - Path java8Home = Helper.getJavaHome("8").orElseThrow(TestAbortedException::new); - return new Java() { - @Override - public Path getHome() { - return java8Home; - } + .addArguments("--classpath", jar.toAbsolutePath().toString()) // + .redirectOutput(outputFiles) // + .startAndWait(); - @Override - public String getVersion() { - return "8"; - } - }; + assertEquals(1, result.exitCode()); + + assertOutputOnCurrentJvm(result); + } + + private static void assertOutputOnCurrentJvm(ProcessResult result) throws IOException { + var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); + var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err.txt")); + assertLinesMatch(expectedOutLines, result.stdOutLines()); + var actualErrLines = result.stdErrLines(); + if (actualErrLines.getFirst().contains("stty: /dev/tty: No such device or address")) { + // Happens intermittently on GitHub Actions on Windows + actualErrLines = new ArrayList<>(actualErrLines); + actualErrLines.removeFirst(); + } + assertLinesMatch(expectedErrLines, actualErrLines); + + var jupiterVersion = Helper.version("junit-jupiter-engine"); + var vintageVersion = Helper.version("junit-vintage-engine"); + assertTrue(result.stdErr().contains("junit-jupiter" + + " (group ID: org.junit.jupiter, artifact ID: junit-jupiter-engine, version: " + jupiterVersion)); + assertTrue(result.stdErr().contains("junit-vintage" + + " (group ID: org.junit.vintage, artifact ID: junit-vintage-engine, version: " + vintageVersion)); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ToolProviderTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ToolProviderTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ToolProviderTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ToolProviderTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -31,17 +31,18 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.spi.ToolProvider; -import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.DisabledOnOpenJ9; +import org.junit.jupiter.api.io.TempDir; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; import platform.tooling.support.ThirdPartyJars; /** @@ -50,12 +51,13 @@ @Order(Integer.MAX_VALUE) class ToolProviderTests { - private static final Path LIB = Request.WORKSPACE.resolve("tool-provider-tests/lib"); + @TempDir + static Path lib; @BeforeAll static void prepareLocalLibraryDirectoryWithJUnitPlatformModules() { try { - var lib = Files.createDirectories(LIB); + Files.createDirectories(lib); try (var directoryStream = Files.newDirectoryStream(lib, "*.jar")) { for (Path jarFile : directoryStream) { Files.delete(jarFile); @@ -69,19 +71,28 @@ } ThirdPartyJars.copy(lib, "org.apiguardian", "apiguardian-api"); ThirdPartyJars.copy(lib, "org.opentest4j", "opentest4j"); + ThirdPartyJars.copy(lib, "org.opentest4j.reporting", "open-test-reporting-tooling-spi"); } catch (Exception e) { throw new AssertionError("Preparing local library folder failed", e); } } + @AfterAll + static void triggerReleaseOfFileHandlesOnWindows() throws Exception { + if (OS.current() == OS.WINDOWS) { + System.gc(); + Thread.sleep(1_000); + } + } + @Test void findAndRunJUnitOnTheClassPath() { - try (var loader = new URLClassLoader("junit", urls(LIB), ClassLoader.getPlatformClassLoader())) { + try (var loader = new URLClassLoader("junit", urls(lib), ClassLoader.getPlatformClassLoader())) { var sl = ServiceLoader.load(ToolProvider.class, loader); var junit = StreamSupport.stream(sl.spliterator(), false).filter(p -> p.name().equals("junit")).findFirst(); - assertTrue(junit.isPresent(), "Tool 'junit' not found in: " + LIB); + assertTrue(junit.isPresent(), "Tool 'junit' not found in: " + lib); assertJUnitPrintsHelpMessage(junit.get()); } catch (IOException e) { @@ -92,12 +103,12 @@ @Test @DisabledOnOpenJ9 void findAndRunJUnitOnTheModulePath() { - var finder = ModuleFinder.of(LIB); + var finder = ModuleFinder.of(lib); var modules = finder.findAll().stream() // .map(ModuleReference::descriptor) // .map(ModuleDescriptor::toNameAndVersion) // .sorted() // - .collect(Collectors.toList()); + .toList(); // modules.forEach(System.out::println); var bootLayer = ModuleLayer.boot(); @@ -139,7 +150,7 @@ ">> USAGE >>", // "Launches the JUnit Platform for test discovery and execution.", // ">> OPTIONS >>"), // - out.toString().lines().collect(Collectors.toList())), // + out.toString().lines().toList()), // () -> assertEquals("", err.toString()), // () -> assertEquals(0, code, "Expected exit of 0, but got: " + code) // ); diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/UnalignedClasspathTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/UnalignedClasspathTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/UnalignedClasspathTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/UnalignedClasspathTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright 2015-2026 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package platform.tooling.support.tests; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.parallel.ExecutionMode.SAME_THREAD; +import static platform.tooling.support.ProcessStarters.currentJdkHome; +import static platform.tooling.support.tests.Projects.copyToWorkspace; + +import java.nio.file.Path; +import java.util.stream.Stream; + +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.platform.tests.process.OutputFiles; + +import platform.tooling.support.Helper; +import platform.tooling.support.MavenRepo; +import platform.tooling.support.ProcessStarters; + +/** + * @since 1.3 + */ +class UnalignedClasspathTests { + + @ManagedResource + LocalMavenRepo localMavenRepo; + + @ManagedResource + MavenRepoProxy mavenRepoProxy; + + @ParameterizedTest + @MethodSource("javaVersions") + @Execution(SAME_THREAD) + void verifyErrorMessageForUnalignedClasspath(JRE jre, Path javaHome, @TempDir Path workspace, + @FilePrefix("maven") OutputFiles outputFiles) throws Exception { + var starter = ProcessStarters.maven(javaHome) // + .workingDir(copyToWorkspace(Projects.JUPITER_STARTER, workspace)) // + .addArguments(localMavenRepo.toCliArgument(), "-Dmaven.repo=" + MavenRepo.dir()) // + .addArguments("-Dsnapshot.repo.url=" + mavenRepoProxy.getBaseUri()) // + .addArguments("-Djunit.platform.commons.version=1.11.4") // + .addArguments("--update-snapshots", "--batch-mode", "verify") // + .putEnvironment(MavenEnvVars.forJre(jre)) // + .redirectOutput(outputFiles); + var result = starter.startAndWait(); + + assertEquals(1, result.exitCode()); + assertEquals("", result.stdErr()); + assertThat(result.stdOutLines()).contains("[INFO] BUILD FAILURE"); + assertThat(result.stdOut()) // + .contains("The wrapped NoClassDefFoundError is likely caused by the versions of JUnit jars " + + "on the classpath/module path not being properly aligned"); + } + + static Stream javaVersions() { + return Stream.concat( // + Helper.getJavaHome(8).map(path -> Arguments.of(JRE.JAVA_8, path)).stream(), // + Stream.of(Arguments.of(JRE.currentJre(), currentJdkHome())) // + ); + } +} diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageGradleIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageGradleIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageGradleIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageGradleIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,63 +11,60 @@ package platform.tooling.support.tests; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; -import java.nio.file.Paths; - -import de.sormuras.bartholdy.Result; -import de.sormuras.bartholdy.tool.GradleWrapper; +import java.nio.file.Path; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.tests.process.OutputFiles; +import org.junit.platform.tests.process.ProcessResult; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; class VintageGradleIntegrationTests { + @TempDir + Path workspace; + @Test - void unsupportedVersion() { - var result = run("4.11"); + void unsupportedVersion(@FilePrefix("gradle") OutputFiles outputFiles) throws Exception { + var result = run(outputFiles, "4.11"); - assertThat(result.getExitCode()).isGreaterThan(0); - assertThat(result.getOutput("out")) // + assertThat(result.exitCode()).isGreaterThan(0); + assertThat(result.stdOut()) // .doesNotContain("STARTED") // .contains("Unsupported version of junit:junit: 4.11"); } @ParameterizedTest(name = "{0}") @ValueSource(strings = { "4.12", "4.13.2" }) - void supportedVersions(String version) { - var result = run(version); + void supportedVersions(String version, @FilePrefix("gradle") OutputFiles outputFiles) throws Exception { + var result = run(outputFiles, version); - assertThat(result.getExitCode()).isGreaterThan(0); - assertThat(result.getOutput("out")) // + assertThat(result.exitCode()).isGreaterThan(0); + assertThat(result.stdOut()) // .contains("VintageTest > success PASSED") // .contains("VintageTest > failure FAILED"); - var testResultsDir = Request.WORKSPACE.resolve("vintage-gradle-" + version).resolve("build/test-results/test"); + var testResultsDir = workspace.resolve("build/test-results/test"); assertThat(testResultsDir.resolve("TEST-com.example.vintage.VintageTest.xml")).isRegularFile(); } - private Result run(String version) { - var result = Request.builder() // - .setTool(new GradleWrapper(Paths.get(".."))) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .setProject(Projects.VINTAGE) // - .setWorkspace("vintage-gradle-" + version) // - .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache") // + private ProcessResult run(OutputFiles outputFiles, String version) throws Exception { + return ProcessStarters.gradlew() // + .workingDir(copyToWorkspace(Projects.VINTAGE, workspace)) // + .putEnvironment("JDK8", Helper.getJavaHome(8).orElseThrow(TestAbortedException::new).toString()) // + .addArguments("build", "--no-daemon", "--stacktrace", "--no-build-cache", "--warning-mode=fail") // .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // .addArguments("-Djunit4Version=" + version) // - .setTimeout(TOOL_TIMEOUT) // - .build() // - .run(); - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - return result; + .redirectOutput(outputFiles) // + .startAndWait(); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageMavenIntegrationTests.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageMavenIntegrationTests.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageMavenIntegrationTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/VintageMavenIntegrationTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -11,62 +11,64 @@ package platform.tooling.support.tests; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static platform.tooling.support.Helper.TOOL_TIMEOUT; +import static platform.tooling.support.tests.Projects.copyToWorkspace; -import de.sormuras.bartholdy.Result; +import java.nio.file.Path; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.junit.platform.tests.process.OutputFiles; +import org.junit.platform.tests.process.ProcessResult; import org.opentest4j.TestAbortedException; import platform.tooling.support.Helper; import platform.tooling.support.MavenRepo; -import platform.tooling.support.Request; +import platform.tooling.support.ProcessStarters; class VintageMavenIntegrationTests { + @ManagedResource + LocalMavenRepo localMavenRepo; + + @TempDir + Path workspace; + @Test - void unsupportedVersion() { - var result = run("4.11"); + void unsupportedVersion(@FilePrefix("maven") OutputFiles outputFiles) throws Exception { + var result = run(outputFiles, "4.11"); - assertThat(result.getExitCode()).isEqualTo(0); - assertThat(result.getOutput("out")) // + assertThat(result.exitCode()).isEqualTo(1); + assertThat(result.stdOut()) // + .contains("TestEngine with ID 'junit-vintage' failed to discover tests") // .contains("Tests run: 0, Failures: 0, Errors: 0, Skipped: 0"); } @ParameterizedTest(name = "{0}") @ValueSource(strings = { "4.12", "4.13.2" }) - void supportedVersions(String version) { - var result = run(version); + void supportedVersions(String version, @FilePrefix("maven") OutputFiles outputFiles) throws Exception { + var result = run(outputFiles, version); - assertThat(result.getExitCode()).isGreaterThan(0); - assertThat(result.getOutput("out")) // + assertThat(result.exitCode()).isGreaterThan(0); + assertThat(result.stdOut()) // .contains("Running com.example.vintage.VintageTest") // .contains("VintageTest.failure:") // .contains("Tests run: 2, Failures: 1, Errors: 0, Skipped: 0"); - var surefireReportsDir = Request.WORKSPACE.resolve("vintage-maven-" + version).resolve( - "target/surefire-reports"); + var surefireReportsDir = workspace.resolve("target/surefire-reports"); assertThat(surefireReportsDir.resolve("com.example.vintage.VintageTest.txt")).isRegularFile(); assertThat(surefireReportsDir.resolve("TEST-com.example.vintage.VintageTest.xml")).isRegularFile(); } - private Result run(String version) { - var result = Request.builder() // - .setTool(Request.maven()) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // - .setProject(Projects.VINTAGE) // - .setWorkspace("vintage-maven-" + version) // + private ProcessResult run(OutputFiles outputFiles, String version) throws Exception { + return ProcessStarters.maven(Helper.getJavaHome(8).orElseThrow(TestAbortedException::new)) // + .workingDir(copyToWorkspace(Projects.VINTAGE, workspace)) // .addArguments("clean", "test", "--update-snapshots", "--batch-mode") // - .addArguments("-Dmaven.repo=" + MavenRepo.dir()) // + .addArguments(localMavenRepo.toCliArgument(), "-Dmaven.repo=" + MavenRepo.dir()) // .addArguments("-Djunit4Version=" + version) // - .setTimeout(TOOL_TIMEOUT) // - .build() // - .run(); - assertFalse(result.isTimedOut(), () -> "tool timed out: " + result); - return result; + .redirectOutput(outputFiles) // + .startAndWait(); } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/XmlAssertions.java jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/XmlAssertions.java --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/XmlAssertions.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/XmlAssertions.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2026 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v2.0 which @@ -10,149 +10,73 @@ package platform.tooling.support.tests; +import static de.skuzzle.test.snapshots.data.xml.XmlSnapshot.xml; +import static org.junit.platform.reporting.testutil.FileUtils.findPath; + import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; - -import org.xmlunit.assertj3.XmlAssert; -import org.xmlunit.placeholder.PlaceholderDifferenceEvaluator; +import java.util.Map; +import java.util.function.UnaryOperator; +import java.util.regex.Pattern; + +import de.skuzzle.test.snapshots.Snapshot; +import de.skuzzle.test.snapshots.SnapshotSerializer; +import de.skuzzle.test.snapshots.StructuredData; +import de.skuzzle.test.snapshots.StructuredDataProvider; class XmlAssertions { - static void verifyContainsExpectedStartedOpenTestReport(Path testResultsDir) { - try (var files = Files.list(testResultsDir)) { - Path xmlFile = files.filter(it -> it.getFileName().toString().startsWith("junit-platform-events-")) // - .findAny() // - .orElseThrow(() -> new AssertionError("Missing open-test-reporting XML file in " + testResultsDir)); - verifyContent(xmlFile); - } - catch (IOException e) { - throw new UncheckedIOException(e); - } + static void verifyContainsExpectedStartedOpenTestReport(Path testResultsDir, Snapshot snapshot) throws IOException { + var xmlFile = findPath(testResultsDir, "glob:**/open-test-report.xml"); + verifyContent(xmlFile, snapshot); + } + + private static void verifyContent(Path xmlFile, Snapshot snapshot) throws IOException { + snapshot.named("open-test-report.xml") // + .assertThat(Files.readString(xmlFile)) // + .as(obfuscated( // + xml() // + .withXPathNamespaceContext(Map.of( // + "c", "https://schemas.opentest4j.org/reporting/core/0.2.0", // + "e", "https://schemas.opentest4j.org/reporting/events/0.2.0", // + "java", "https://schemas.opentest4j.org/reporting/java/0.2.0" // + )) // + .withComparisonRules(rules -> rules // + .pathAt("//@time").mustMatch( + Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?Z")) // + .pathAt("//c:infrastructure/c:hostName/text()").ignore() // + .pathAt("//c:infrastructure/c:userName/text()").ignore() // + .pathAt("//c:infrastructure/c:operatingSystem/text()").ignore() // + .pathAt("//c:infrastructure/c:cpuCores/text()").ignore() // + .pathAt("//c:infrastructure/java:javaVersion/text()").ignore() // + .pathAt("//c:infrastructure/java:fileEncoding/text()").ignore() // + .pathAt("//c:infrastructure/java:heapSize/@max").ignore() // + ), // + text -> text // + .replaceAll(".+?", "obfuscated") // + .replaceAll(".+?", "obfuscated") // + )) // + .matchesSnapshotStructure(); + } + + private static StructuredDataProvider obfuscated(StructuredDataProvider provider, + UnaryOperator obfuscator) { + return () -> { + var structuredData = provider.build(); + var snapshotSerializer = obfuscatingSnapshotSerializer(structuredData.snapshotSerializer(), obfuscator); + return StructuredData.with(snapshotSerializer, structuredData.structuralAssertions()); + }; } - private static void verifyContent(Path xmlFile) { - var expected = """ - - - ${xmlunit.ignore} - ${xmlunit.ignore} - ${xmlunit.ignore} - ${xmlunit.ignore} - ${xmlunit.ignore} - ${xmlunit.ignore} - - - - - [engine:junit-jupiter] - JUnit Jupiter - CONTAINER - - - - - [engine:junit-jupiter]/[class:com.example.project.CalculatorTests] - com.example.project.CalculatorTests - CONTAINER - - - - - - - - [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[method:addsTwoNumbers()] - addsTwoNumbers() - TEST - - - - - - - - - - - [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)] - add(int, int, int) - CONTAINER - - - - - - - - [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#1] - add(int, int, int)[1] - TEST - - - - - - - - - - - [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#2] - add(int, int, int)[2] - TEST - - - - - - - - - - - [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#3] - add(int, int, int)[3] - TEST - - - - - - - - - - - [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#4] - add(int, int, int)[4] - TEST - - - - - - - - - - - - - - - - - - - """; - - XmlAssert.assertThat(xmlFile).and(expected) // - .withDifferenceEvaluator(new PlaceholderDifferenceEvaluator()) // - .ignoreWhitespace() // - .areIdentical(); + private static SnapshotSerializer obfuscatingSnapshotSerializer(SnapshotSerializer delegate, + UnaryOperator obfuscator) { + return testResult -> { + Object obfuscatedTestResult = testResult; + if (testResult instanceof String) { + obfuscatedTestResult = obfuscator.apply((String) testResult); + } + return delegate.serialize(obfuscatedTestResult); + }; } } diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/junit-platform.properties jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/junit-platform.properties --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/junit-platform.properties 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/junit-platform.properties 2026-06-21 20:26:05.000000000 +0000 @@ -2,6 +2,9 @@ junit.jupiter.execution.parallel.mode.default=concurrent junit.jupiter.execution.parallel.config.strategy=dynamic junit.jupiter.execution.parallel.config.dynamic.factor=0.25 +junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=1 junit.jupiter.testclass.order.default = \ org.junit.jupiter.api.ClassOrderer$OrderAnnotation + +junit.jupiter.execution.timeout.default = 3m diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/AntStarterTests_snapshots/open-test-report.xml.snapshot jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/AntStarterTests_snapshots/open-test-report.xml.snapshot --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/AntStarterTests_snapshots/open-test-report.xml.snapshot 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/AntStarterTests_snapshots/open-test-report.xml.snapshot 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,426 @@ +dynamic-directory: false +snapshot-name: open-test-report.xml +snapshot-number: 0 +test-class: platform.tooling.support.tests.AntStarterTests +test-method: ant_starter + + + + + + obfuscated + obfuscated + Linux + 16 + 21.0.6 + UTF-8 + + + + + + [engine:junit-jupiter] + JUnit Jupiter + CONTAINER + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests] + com.example.project.CalculatorParameterizedClassTests + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)] + parameterizedTest(int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)]/[test-template-invocation:#1] + parameterizedTest(int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)]/[test-template-invocation:#2] + parameterizedTest(int)[2] + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner] + com.example.project.CalculatorParameterizedClassTests$Inner + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests$Inner[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#1]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests$Inner[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#2]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)] + parameterizedTest(int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)]/[test-template-invocation:#1] + parameterizedTest(int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)]/[test-template-invocation:#2] + parameterizedTest(int)[2] + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner] + com.example.project.CalculatorParameterizedClassTests$Inner + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests$Inner[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#1]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests$Inner[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#2]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests] + com.example.project.CalculatorTests + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[method:addsTwoNumbers()] + addsTwoNumbers() + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)] + add(int, int, int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#1] + add(int, int, int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#2] + add(int, int, int)[2] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#3] + add(int, int, int)[3] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#4] + add(int, int, int)[4] + TEST + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/GradleStarterTests_snapshots/open-test-report.xml.snapshot jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/GradleStarterTests_snapshots/open-test-report.xml.snapshot --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/GradleStarterTests_snapshots/open-test-report.xml.snapshot 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/GradleStarterTests_snapshots/open-test-report.xml.snapshot 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,426 @@ +dynamic-directory: false +snapshot-name: open-test-report.xml +snapshot-number: 0 +test-class: platform.tooling.support.tests.GradleStarterTests +test-method: buildJupiterStarterProject + + + + + + obfuscated + obfuscated + Linux + 16 + 17.0.14 + UTF-8 + + + + + + [engine:junit-jupiter] + JUnit Jupiter + CONTAINER + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests] + com.example.project.CalculatorParameterizedClassTests + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)] + parameterizedTest(int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)]/[test-template-invocation:#1] + parameterizedTest(int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)]/[test-template-invocation:#2] + parameterizedTest(int)[2] + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner] + com.example.project.CalculatorParameterizedClassTests$Inner + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests$Inner[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#1]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests$Inner[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#2]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)] + parameterizedTest(int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)]/[test-template-invocation:#1] + parameterizedTest(int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)]/[test-template-invocation:#2] + parameterizedTest(int)[2] + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner] + com.example.project.CalculatorParameterizedClassTests$Inner + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests$Inner[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#1]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests$Inner[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#2]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests] + com.example.project.CalculatorTests + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[method:addsTwoNumbers()] + addsTwoNumbers() + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)] + add(int, int, int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#1] + add(int, int, int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#2] + add(int, int, int)[2] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#3] + add(int, int, int)[3] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#4] + add(int, int, int)[4] + TEST + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/MavenStarterTests_snapshots/open-test-report.xml.snapshot jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/MavenStarterTests_snapshots/open-test-report.xml.snapshot --- jtreg8-8.1+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/MavenStarterTests_snapshots/open-test-report.xml.snapshot 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/platform-tooling-support-tests/src/test/resources/platform/tooling/support/tests/MavenStarterTests_snapshots/open-test-report.xml.snapshot 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,426 @@ +dynamic-directory: false +snapshot-name: open-test-report.xml +snapshot-number: 0 +test-class: platform.tooling.support.tests.MavenStarterTests +test-method: verifyJupiterStarterProject + + + + + + obfuscated + obfuscated + Linux + 16 + 1.8.0_442 + UTF-8 + + + + + + [engine:junit-jupiter] + JUnit Jupiter + CONTAINER + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests] + com.example.project.CalculatorParameterizedClassTests + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)] + parameterizedTest(int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)]/[test-template-invocation:#1] + parameterizedTest(int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[test-template:parameterizedTest(int)]/[test-template-invocation:#2] + parameterizedTest(int)[2] + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner] + com.example.project.CalculatorParameterizedClassTests$Inner + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests$Inner[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#1]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests$Inner[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#1]/[nested-class-template:Inner]/[class-template-invocation:#2]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)] + parameterizedTest(int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)]/[test-template-invocation:#1] + parameterizedTest(int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[test-template:parameterizedTest(int)]/[test-template-invocation:#2] + parameterizedTest(int)[2] + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner] + com.example.project.CalculatorParameterizedClassTests$Inner + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#1] + com.example.project.CalculatorParameterizedClassTests$Inner[1] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#1]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#2] + com.example.project.CalculatorParameterizedClassTests$Inner[2] + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class-template:com.example.project.CalculatorParameterizedClassTests]/[class-template-invocation:#2]/[nested-class-template:Inner]/[class-template-invocation:#2]/[method:regularTest()] + regularTest() + TEST + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests] + com.example.project.CalculatorTests + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[method:addsTwoNumbers()] + addsTwoNumbers() + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)] + add(int, int, int) + CONTAINER + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#1] + add(int, int, int)[1] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#2] + add(int, int, int)[2] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#3] + add(int, int, int)[3] + TEST + + + + + + + + + + + + + [engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#4] + add(int, int, int)[4] + TEST + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/junit5/settings.gradle.kts jtreg8-8.3+1+ds1/junit5/settings.gradle.kts --- jtreg8-8.1+1+ds1/junit5/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/junit5/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -15,11 +15,6 @@ dependencyResolutionManagement { repositories { mavenCentral() - maven(url = "https://oss.sonatype.org/content/repositories/snapshots") { - mavenContent { - snapshotsOnly() - } - } } } @@ -62,7 +57,7 @@ if (useDevelocityInstance) { remote(develocity.buildCache) { server = buildCacheServer.orNull - val authenticated = System.getenv("DEVELOCITY_ACCESS_KEY") != null + val authenticated = !System.getenv("DEVELOCITY_ACCESS_KEY").isNullOrEmpty() isPush = buildParameters.ci && authenticated } } else { @@ -74,7 +69,7 @@ includeBuild("gradle/base") -rootProject.name = "junit5" +rootProject.name = "junit-framework" include("documentation") include("junit-jupiter") diff -Nru jtreg8-8.1+1+ds1/make/Makefile jtreg8-8.3+1+ds1/make/Makefile --- jtreg8-8.1+1+ds1/make/Makefile 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/make/Makefile 2026-06-21 20:26:05.000000000 +0000 @@ -60,6 +60,12 @@ ifndef JDK18HOME @echo "Warning: JDK18HOME not set; some tests may not have been executed" endif +ifndef JDK21HOME + @echo "Warning: JDK21HOME not set; some tests may not have been executed" +endif +ifndef JDK25HOME + @echo "Warning: JDK25HOME not set; some tests may not have been executed" +endif ifdef HEADLESS @echo "Warning: HEADLESS is set; some tests may not have been executed" endif @@ -110,6 +116,12 @@ ifdef JDK18HOME @echo "JDK18HOME = $(JDK18HOME)" endif +ifdef JDK21HOME + @echo "JDK21HOME = $(JDK21HOME)" +endif +ifdef JDK25HOME + @echo "JDK25HOME = $(JDK25HOME)" +endif @echo "JDKHOME = $(JDKHOME)" @echo "JAVATEST_HOME = $(JAVATEST_HOME)" ifneq ($(JTHARNESS_HOME), $(JAVATEST_HOME)) diff -Nru jtreg8-8.1+1+ds1/make/build-support/asmtools/version-numbers jtreg8-8.3+1+ds1/make/build-support/asmtools/version-numbers --- jtreg8-8.1+1+ds1/make/build-support/asmtools/version-numbers 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/make/build-support/asmtools/version-numbers 2026-06-21 20:26:05.000000000 +0000 @@ -23,8 +23,8 @@ # questions. # -DEFAULT_ASMTOOLS_SRC_TAG=8.1 -DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM=6dcd98e53131bc923df5fdd10baa42c601f1c97c +DEFAULT_ASMTOOLS_SRC_TAG=9.1-b01 +DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM=96c52b18da85490d12ad04ec0cfa71c83b67136d DEFAULT_ANT_VERSION=1.10.15 DEFAULT_ANT_ARCHIVE_CHECKSUM=1b460a543caf0b2087fef210c7b4813909901fdc diff -Nru jtreg8-8.1+1+ds1/make/build-support/version-numbers jtreg8-8.3+1+ds1/make/build-support/version-numbers --- jtreg8-8.1+1+ds1/make/build-support/version-numbers 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/make/build-support/version-numbers 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,13 @@ # questions. # -JTREG_VERSION=8.1 +JTREG_VERSION=8.3 DEFAULT_ANT_VERSION=1.10.15 DEFAULT_ANT_ARCHIVE_CHECKSUM=1b460a543caf0b2087fef210c7b4813909901fdc -DEFAULT_ASMTOOLS_SRC_TAG=8.1 -DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM=6dcd98e53131bc923df5fdd10baa42c601f1c97c +DEFAULT_ASMTOOLS_SRC_TAG=9.1-b01 +DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM=96c52b18da85490d12ad04ec0cfa71c83b67136d DEFAULT_GOOGLE_GUICE_VERSION=5.1.0 DEFAULT_GOOGLE_GUICE_JAR_CHECKSUM=da25056c694c54ba16e78e4fc35f17fc60f0d1b4 @@ -41,8 +41,8 @@ DEFAULT_JTHARNESS_SRC_ARCHIVE_CHECKSUM=3d25ddea8e59ab8ff0943bc65aebc80a2aecc4a3 # JUnit 5 = JUnit Platform 1.y.z + JUnit Jupiter 5.y.z + JUnit Vintage 5.y.z -DEFAULT_JUNIT_VERSION=1.13.4 -DEFAULT_JUNIT_JAR_CHECKSUM=62734191af1bfc78ee17181ca38b94dbb5eb7737 +DEFAULT_JUNIT_VERSION=1.14.2 +DEFAULT_JUNIT_JAR_CHECKSUM=99b3e0fe1df38e5eea763c168c033c030a4bd46c DEFAULT_JUNIT_LICENSE_FILE=LICENSE-junit.txt DEFAULT_TESTNG_VERSION=7.3.0 diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/.gitignore jtreg8-8.3+1+ds1/opentest4j-reporting/.gitignore --- jtreg8-8.1+1+ds1/opentest4j-reporting/.gitignore 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/.gitignore 2026-06-21 20:26:05.000000000 +0000 @@ -1,8 +1,5 @@ -# Ignore Gradle project-specific cache directory .gradle - -# Ignore Gradle build output directory build - -# SDKMAN! .sdkmanrc +.idea +.kotlin diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/README.adoc jtreg8-8.3+1+ds1/opentest4j-reporting/README.adoc --- jtreg8-8.1+1+ds1/opentest4j-reporting/README.adoc 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/README.adoc 2026-06-21 20:26:05.000000000 +0000 @@ -1,82 +1,47 @@ = Open Test Reporting +:schemaVersion: 0.2.0 +:openTestReportingVersion: 0.2.5 -New test reporting formats that are agnostic of testing framework and programming language. +<> and <> test reporting formats that are agnostic of testing framework and programming language. == Introduction This repository contains the definition of and tooling for two new XML-based test reporting formats that are agnostic of any testing framework and programming language yet concrete enough to be consumable by a wide range of downstream tools such as IDEs, build tools, and report generators. +Moreover, it provides a report generator that produces a <> based on the XML formats. -The link:#event-based-format[first format] is _event-based_ which is not only suitable for writing events to a file but also for streaming events over a local socket or network connection. +The <> is suitable for writing test events to a file or streaming them over a local socket or network connection. Instead of having to collect all data for a test only to write it to the report after the test has completed, testing frameworks can emit events as they occur, for example when a test is started or finished. -The link:#hierarchical-format[second format] is meant to be closer to existing _hierarchical_ representations of test results that users are familiar with. +The <> is meant to be closer to existing representations of test results that users are familiar with. For example, when executing tests in IDEs, one is usually presented with a tree of tests and their results. This same structure can be found in files that use this format. Thus, instead of requiring humans or processing tools to piece together all relevant events for a test from the event-based format, this hierarchical format collects all relevant information in a single place for each test. Besides being human-readable, this format is easier to transform into an HTML report by a downstream reporting tool or CI server. +Both XML formats are designed to complement each other such that the event-based format can be mechanically converted into the hierarchical one. -The two formats are designed to complement each other such that the event-based format can be mechanically converted into the hierarchical one. -This repository contains a reference implementation of such a converter as an executable and library. -This way, testing frameworks can focus on writing the event-based format; build tools may use the converter to write the hierarchical format; and reporting tools can consume whichever format they prefer. +This repository contains a <> of an API for <> event-based XML files (from JVM languages such as Java), as well as a <> for <> them, <> them to the hierarchical format, and generating <> from them. +This way, testing frameworks can focus on writing the event-based format; build tools may use the converter to write the hierarchical format or generate HTML reports; and reporting tools can consume whichever format they prefer. -== Prior art - -In the Java ecosystem, Ant originally defined an XML-based reporting format for tests. -Other build tools like Maven and Gradle have adopted the format and, in the case of Maven Surefire, later made changes to add additional data. -Many build servers know how to parse the XML-based format, and even non-Java tools sometimes support it. -However, it’s based on the concept of test classes and methods, so using it for frameworks and tools where those elements are not present is awkward at best. -Moreover, it does not support nested structures beyond a simple parent-child relationship. -Finally, it is not extensible: no additional attributes can be added without the risk of breaking existing tools. - -For those reasons, many testing frameworks such as TestNG and Spock have defined their own reporting formats. -This has given them the flexibility they need, but the number of tools that can parse, display, or transform their custom formats is very limited. - -To overcome the limitations described above, this document defines a new format for test reporting. -Its goal is to be platform-agnostic so that as many testing frameworks as possible can benefit from it. -Moreover, it is designed to be extensible so new data can be added as needed, without breaking consumers. -However, all well-known attributes are properly defined so it’s consumable by downstream reporting tools. - -== Design goals - -human-readable:: -The new format needs to be human-readable so it can be inspected without requiring another tool. -A format that represents the test tree via nesting is easier to understand than a flat list of events that reference their parents via IDs. - -streamable:: -Writing report files during test execution should not require keeping state about currently running tests, etc. in memory. -Instead, the new format should allow tools to write events to a file as they occur. - -machine-readable:: -At the same time, the format must be machine-readable so it can be easily parsed and transformed on a variety of platforms. - -schema-aware:: -Implementors and tools should be able to validate a given document against a well-known schema. - -extensible:: -Adding additional language- or framework-specific attributes to nodes must be possible without breaking backwards compatibility. +NOTE: Please refer to the appendix for more information about the <> and its <<#design-goals, design goals>>. -=== XML vs. JSON - -JSON is less verbose than XML, but the latter provides more expressive ways to define schemas. -Moreover, XML has typed extensions built-in via the use of multiple schemas. -Thus, the new formats use XML with accompanying XML schemas. +[#xml-formats] +== XML format specification -== Format specification - -Both formats share a set of core elements that is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/core.xsd[core.xsd]. +Both formats share a set of core elements that is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/core-{schemaVersion}.xsd[core-{schemaVersion}.xsd]. +[#event-based-format] === Event-based format -The event-based format is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/events.xsd[events.xsd]. +The event-based format is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/events-{schemaVersion}.xsd[events-{schemaVersion}.xsd]. The following example shows the result of a test run with a single top-level "container" and a "test" child. -[source,xml] +[source,xml,subs="attributes+"] ---- + xmlns="https://schemas.opentest4j.org/reporting/core/{schemaVersion}" + xmlns:e="https://schemas.opentest4j.org/reporting/events/{schemaVersion}"> wonderland alice @@ -101,17 +66,18 @@ The test framework reporting these events was able to write them as they occurred. In particular, it did not have to wait for all children of "container" to be finished. +[#hierarchical-format] === Hierarchical format -The event-based format is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy.xsd[hierarchy.xsd]. +The event-based format is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-{schemaVersion}.xsd[hierarchy-{schemaVersion}.xsd]. The following example shows the result of converting the above event-based report into the hierarchical format. -[source,xml] +[source,xml,subs="attributes+"] ---- - + wonderland alice @@ -128,28 +94,56 @@ <2> root node of "container" with timestamp, duration, and result status <3> child node of "test" with timestamp, duration, and result status -=== Java extensions +[#xml-extensions] +=== Schema extensions All schema definitions mentioned so far are language-agnostic. -In order to report Java-specific attributes, e.g. the class or method name of a test, an extension schema is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/java.xsd[java.xsd]. -NOTE: Test frameworks are encouraged to define their own similar framework-specific extensions if they want to report additional information that is not suitable to be added to the core namespace. +==== Java + +In order to report Java-specific attributes, e.g. the class or method name of a test, an extension schema is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/java-{schemaVersion}.xsd[java-{schemaVersion}.xsd]. + +[TIP] +==== +Test frameworks are encouraged to define their own similar framework-specific extensions if they want to report additional information that is not suitable to be added to the core namespace. +See the link:https://github.com/junit-team/junit5/blob/61578038ba1e7f4ea1059aea3e0589581991f531/junit-platform-reporting/src/main/resources/org/junit/platform/reporting/open/xml/junit.xsd[JUnit project] for an example of how to define an extension schema. +==== + +==== Git +In order to include Git-specific metadata, e.g. the commit hash or branch name, an extension schema is defined in link:schema/src/main/resources/org/opentest4j/reporting/schema/git-{schemaVersion}.xsd[git-{schemaVersion}.xsd]. + +[WARNING] +==== +If you're implementing support for including Git information in an XML report, you must ensure to strip any credentials from the `originUrl` before writing it to the XML file. +Moreover, since Git status output may include file names that contain personally identifiable or otherwise sensitive information, it is recommended to include Git-specific metadata in the XML report only if the requesting user has opted in explicitly. +==== + +[#reference-implementation] == Reference implementation -While the reporting formats are language-agnostic, the reference implementation is written in Java due to being the language its authors are most familiar with. +While the reporting formats are language-agnostic, the reference implementation is written in Java due to being the language its authors (the JUnit team) are most familiar with. This repository contains the following subprojects: schema:: XML schema definitions of both formats events:: - Java API for writing the event-based format without having to deal with Java's XML APIs + <> without having to deal with Java's XML APIs cli:: - Command-line interface for validating both fomats and converting from the event-based to the hierarchical format -tooling:: - Java API for validating both formats and converting from the event-based to the hierarchical format (suitable for inclusion in build tools and reporting tools) + <> (CLI) for validating both formats, converting from the event-based to the hierarchical format, and <> +tooling-core:: + Java API for validating both formats, converting from the event-based to the hierarchical format (suitable for inclusion in build tools and reporting tools), and generating HTML reports +tooling-spi:: + Java Service Provider Interface (SPI) for the <> +html-report:: + Vue.js-based HTML report single-page application (SPA) +sample-project:: + Sample project that demonstrates how to enable JUnit's event-based output and set up Gradle to convert it to the hierarchical format and generate an HTML report + +[#events] +[#events-api] === API for writing event-based format Testing frameworks that run on the JVM can use the API provided by the _events_ subprojects as follows. @@ -198,14 +192,170 @@ <5> finished event of "test" with timestamp and result status <6> finished event of "container" with timestamp and result status -=== CLI tool for validation and format conversion +==== Streaming to a Writer -The CLI tool provided by the _cli_ subprojects provides subcommands for validating both formats and converting from the event-based to the hierarchical format. +For use cases where you need to stream events over a socket or network connection instead of writing to a file, you can use a `Writer` instance: -[source,console] +[source,java] ---- -$ ./open-test-reporting convert events.xml -ℹ️ Converted events.xml to hierarchy.xml +import org.opentest4j.reporting.events.api.DocumentWriter; +import org.opentest4j.reporting.events.api.NamespaceRegistry; +import org.opentest4j.reporting.events.core.CoreFactory; +import org.opentest4j.reporting.events.root.Events; +import org.opentest4j.reporting.schema.Namespace; + +import java.io.OutputStreamWriter; +import java.time.Instant; + +import static org.opentest4j.reporting.events.core.CoreFactory.*; +import static org.opentest4j.reporting.events.core.Result.Status.SUCCESSFUL; +import static org.opentest4j.reporting.events.root.RootFactory.finished; +import static org.opentest4j.reporting.events.root.RootFactory.started; + +public class DocumentWriterStreamingSample { + + public static void main(String[] args) throws Exception { + + NamespaceRegistry namespaceRegistry = NamespaceRegistry.builder(Namespace.REPORTING_CORE) // <1> + .add("e", Namespace.REPORTING_EVENTS) // + .add("git", Namespace.REPORTING_GIT) // + .add("java", Namespace.REPORTING_JAVA) // + .build(); + + // Example: streaming events to System.out (could be a socket, network stream, etc.) + try (DocumentWriter writer = Events.createDocumentWriter(namespaceRegistry, + new OutputStreamWriter(System.out))) { + writer.append(infrastructure(), infrastructure -> infrastructure // <2> + .append(hostName("wonderland")) // + .append(userName("alice"))); + writer.append(started("1", Instant.now(), "container")); // <3> + writer.append(started("2", Instant.now(), "test"), started -> started.withParentId("1")); // <4> + writer.append(finished("2", Instant.now()), finished -> finished.append(CoreFactory.result(SUCCESSFUL))); // <5> + writer.append(finished("1", Instant.now()), finished -> finished.append(CoreFactory.result(SUCCESSFUL))); // <6> + } + } +} ---- -NOTE: Please refer to the CLI tool's `--help` option for more information. +This allows you to write test events as they occur, without having to collect all data before writing. + +TIP: See the link:https://github.com/junit-team/junit5/blob/86539a286b23b9dd192f3e54bc10e3c95f87773f/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.java[JUnit project] for an example of how to write an event-based report. + +[#cli] +=== CLI tool + +The CLI tool provided by the _cli_ subprojects provides subcommands for <> both formats, <> from the event-based to the hierarchical format, and generating an <>. + +==== Installation + +You can download the CLI tool from Maven Central using the https://repo1.maven.org/maven2/org/opentest4j/reporting/open-test-reporting-cli/{openTestReportingVersion}/open-test-reporting-cli-{openTestReportingVersion}-standalone.jar[`org.opentest4j.reporting:open-test-reporting-cli:{openTestReportingVersion}:standalone`] coordinates. + +Alternatively, you can use https://www.jbang.dev/[JBang]: + +[source,console,subs="attributes+"] +---- +$ jbang org.opentest4j.reporting:open-test-reporting-cli:{openTestReportingVersion}:standalone --help +---- + +[#cli-validate] +==== Validate XML files + +[source,console,subs="attributes+"] +---- +$ java -jar open-test-reporting-cli-{openTestReportingVersion}.jar validate events.xml +ℹ️ Valid: events.xml +---- + +NOTE: Please run `validate --help` for more information. + +[#cli-convert] +==== Convert event-based to hierarchical format + +[source,console],subs="attributes+"] +---- +$ java -jar open-test-reporting-cli-{openTestReportingVersion}.jar convert events.xml +ℹ️ Converted events.xml to file:///some/path/hierarchy.xml +---- + +NOTE: Please run `convert --help` for more information. + +[#cli-html-report] +==== HTML report + +The HTML report is a single-page application (SPA) that displays the test results in a tree-like structure and allows users to view details about each test/container. +It can be generated as follows using the <>: + +[source,console,subs="attributes+"] +---- +$ java -jar open-test-reporting-cli-{openTestReportingVersion}.jar html-report --output open-test-report.html events-1.xml hierarchical.xml +ℹ️ Wrote HTML report to file:///some/path/open-test-report.html +---- + +NOTE: Please run `html-report --help` for more information. + +The command takes one or multiple XML files in the event-based or hierarchical format as input and generates a single HTML file that can be opened in any modern web browser without requiring a server. + +.Sample HTML report where all tests pass (light theme) +-- +image::documentation/html-report-successful.png[] +-- + +.Sample HTML report with a failing test (dark theme) +-- +image::documentation/html-report-failed.png[] +-- + + +[#html-report-extension] +===== Extending the HTML report + +Since the XML formats are <>, the HTML report can be extended to display additional information that is not part of the core schemas. +In order to do so, the _tooling-spi_ subproject defines a Java Service Provider Interface (SPI) that allows developers to implement a custom extension that is automatically picked up by the HTML report generator when it is on the classpath/module path. +Please refer to the Javadoc of the `org.opentest4j.reporting.tooling.spi.htmlreport.Contributor` interface for more information. + +TIP: See the link:https://github.com/junit-team/junit5/blob/86539a286b23b9dd192f3e54bc10e3c95f87773f/junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/JUnitContributor.java[JUnit project] for an example of how to implement a `Contributor`. + + +[appendix, #prior-art] +== Prior art + +In the Java ecosystem, Ant originally defined an XML-based reporting format for tests. +Other build tools like Maven and Gradle have adopted the format and, in the case of Maven Surefire, later made changes to add additional data. +Many build servers know how to parse the XML-based format, and even non-Java tools sometimes support it. +However, it’s based on the concept of test classes and methods, so using it for frameworks and tools where those elements are not present is awkward at best. +Moreover, it does not support nested structures beyond a simple parent-child relationship. +Finally, it is not extensible: no additional attributes can be added without the risk of breaking existing tools. + +For those reasons, many testing frameworks such as TestNG and Spock have defined their own reporting formats. +This has given them the flexibility they need, but the number of tools that can parse, display, or transform their custom formats is very limited. + +To overcome the limitations described above, this document defines a new format for test reporting. +Its goal is to be platform-agnostic so that as many testing frameworks as possible can benefit from it. +Moreover, it is designed to be extensible so new data can be added as needed, without breaking consumers. +However, all well-known attributes are properly defined so it’s consumable by downstream reporting tools. + +[appendix, #design-goals] +== Design goals + +human-readable:: +The new format needs to be human-readable so it can be inspected without requiring another tool. +A format that represents the test tree via nesting is easier to understand than a flat list of events that reference their parents via IDs. + +streamable:: +Writing report files during test execution should not require keeping state about currently running tests, etc. in memory. +Instead, the new format should allow tools to write events to a file as they occur. + +machine-readable:: +At the same time, the format must be machine-readable so it can be easily parsed and transformed on a variety of platforms. + +schema-aware:: +Implementors and tools should be able to validate a given document against a well-known schema. + +extensible:: +Adding additional language- or framework-specific attributes to nodes must be possible without breaking backwards compatibility. + +=== XML vs. JSON + +JSON is less verbose than XML, but the latter provides more expressive ways to define schemas. +Moreover, XML has typed extensions built-in via the use of multiple schemas. +Thus, the new formats use XML with accompanying XML schemas. diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/SECURITY.md jtreg8-8.3+1+ds1/opentest4j-reporting/SECURITY.md --- jtreg8-8.1+1+ds1/opentest4j-reporting/SECURITY.md 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/SECURITY.md 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,15 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 0.2.x | :white_check_mark: | +| < 0.2 | :x: | + +## Reporting a Vulnerability + +To report a security vulnerability, you have two options: + +- [Privately report a vulnerability](https://github.com/ota4j-team/open-test-reporting/security/advisories/new) on GitHub (see [docs](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability) for details) +- Send an email to security@junit.org. You can use the [published OpenPGP key](https://keys.openpgp.org/search?q=security%40junit.org) with fingerprint `0152DA30EABC7ABADCB09D10D9A6B1329D191D25` to encrypt the message body. diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,10 +1,12 @@ -plugins { - id("io.github.gradle-nexus.publish-plugin") version "2.0.0" -} +import nmcp.NmcpAggregationExtension + +plugins.apply("com.gradleup.nmcp.aggregation") -nexusPublishing { - packageGroup.set("org.opentest4j") - repositories { - sonatype() +configure { + centralPortal { + username = providers.gradleProperty("mavenCentralUsername") + password = providers.gradleProperty("mavenCentralPassword") + publishingType = providers.gradleProperty("mavenCentralPublishingType").orElse("USER_MANAGED") } + publishAllProjectsProbablyBreakingProjectIsolation() } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21 + plugins { `kotlin-dsl` } @@ -8,14 +10,20 @@ } dependencies { - implementation("com.diffplug.spotless:spotless-plugin-gradle:6.25.0") + implementation(libs.plugins.bnd.markerCoordinates) + implementation(libs.plugins.nmcp.markerCoordinates) + implementation(libs.plugins.spotless.markerCoordinates) } tasks { compileKotlin { - kotlinOptions.jvmTarget = "17" + compilerOptions.jvmTarget = JVM_21 } compileJava { - options.release.convention(17) + options.release.convention(21) } } + +// see https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_markers +val Provider.markerCoordinates: Provider + get() = map { "${it.pluginId}:${it.pluginId}.gradle.plugin:${it.version}" } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/settings.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/settings.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/settings.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,9 @@ +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "buildSrc" diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/UpdateJarAction.kt jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/UpdateJarAction.kt --- jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/UpdateJarAction.kt 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/UpdateJarAction.kt 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +import org.gradle.api.Action +import org.gradle.api.Task +import org.gradle.api.internal.file.archive.ZipEntryConstants +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.process.ExecOperations +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import java.time.ZoneOffset +import javax.inject.Inject + +abstract class UpdateJarAction @Inject constructor(private val operations: ExecOperations): Action { + + companion object { + // Since ZipCopyAction.CONSTANT_TIME_FOR_ZIP_ENTRIES is in the default time zone (see its Javadoc), + // we're converting it to the same time in UTC here to make the jar reproducible regardless of the + // build's time zone. + private val CONSTANT_TIME_FOR_ZIP_ENTRIES = LocalDateTime.ofInstant(Instant.ofEpochMilli(ZipEntryConstants.CONSTANT_TIME_FOR_ZIP_ENTRIES), ZoneId.systemDefault()) + .toInstant(ZoneOffset.UTC) + .toString() + } + + abstract val javaLauncher: Property + + abstract val args: ListProperty + + init { + args.addAll( + "--update", + // Use a constant time to make the JAR reproducible. + "--date=$CONSTANT_TIME_FOR_ZIP_ENTRIES", + ) + } + + override fun execute(t: Task) { + operations.exec { + executable = javaLauncher.get() + .metadata.installationPath.file("bin/jar").asFile.absolutePath + args = this@UpdateJarAction.args.get() + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-basics.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-basics.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-basics.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-basics.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ +plugins { + `java-library` +} + +normalization { + runtimeClasspath { + metaInf { + ignoreAttribute("Bnd-LastModified") + ignoreAttribute("Created-By") + ignoreAttribute("Tool") + } + } +} + +tasks.withType().configureEach { + options.compilerArgs.addAll(listOf("-Xlint:all", "-Werror")) +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-conventions.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-conventions.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-conventions.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/java-conventions.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -2,13 +2,14 @@ import java.nio.file.Files plugins { - `java-library` + id("biz.aQute.bnd.builder") id("com.diffplug.spotless") + id("java-basics") id("publishing-conventions") } base { - archivesName.set("open-test-reporting-${project.name}") + archivesName = "open-test-reporting-${project.name}" } java { @@ -24,32 +25,100 @@ java { licenseHeaderFile(licenseHeaderFile, "(package|import|open|module) ") - eclipse().configFile(javaFormatterConfigFile) + val fullVersion = requiredVersionFromLibs("eclipse") + val majorMinorVersion = "([0-9]+\\.[0-9]+).*".toRegex().matchEntire(fullVersion)!!.let { it.groups[1]!!.value } + eclipse(majorMinorVersion).configFile(javaFormatterConfigFile) + trimTrailingWhitespace() + endWithNewline() + } + + format("moduleDescriptor") { + target(fileTree(layout.projectDirectory.dir("src/module")) { + include("**/module-info.java") + }) + licenseHeaderFile(licenseHeaderFile, "^$") trimTrailingWhitespace() endWithNewline() } } +fun Project.requiredVersionFromLibs(name: String) = + libsVersionCatalog.findVersion(name).get().requiredVersion + +fun Project.dependencyFromLibs(name: String) = + libsVersionCatalog.findLibrary(name).get() + +private val Project.libsVersionCatalog: VersionCatalog + get() = the().named("libs") + val cli by configurations.creating { isCanBeResolved = true isCanBeConsumed = false - isVisible = false } dependencies { cli(project(":cli")) + cli(dependencyFromLibs("junit-platform-reporting")) +} + +configurations { + all { + resolutionStrategy.dependencySubstitution { + substitute(module("${group}:open-test-reporting-tooling-spi")) + .using(project(":tooling-spi")) + } + } + compileClasspath { + attributes { + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR)) + } + } } tasks { compileJava { options.release.convention(8) + options.javaModuleVersion.convention(provider { project.version.toString() }) } compileTestJava { options.release.convention(17) } + val moduleName = "org.opentest4j.reporting.${project.name.replace('-', '.')}" + val compileModule by registering(JavaCompile::class) { + val moduleSrcDir = file("src/module/java") + source(moduleSrcDir) + destinationDirectory.set(layout.buildDirectory.dir("classes/java/modules")) + classpath = configurations.compileClasspath.get() + inputs.property("moduleName", moduleName) + inputs.property("moduleVersion", project.version) + options.release = compileJava.flatMap { it.options.release }.map { if (it > 9) it else 9 } + options.compilerArgs = listOf( + "--module-version", project.version as String, + "--module-path", classpath.asPath, + "--module-source-path", moduleSrcDir.toString(), + "--patch-module", "$moduleName=${files(sourceSets.main.get().allJava.srcDirs).asPath}", + "--module", moduleName, + ) + } jar { + from(files(compileModule.map { it.destinationDirectory.dir(moduleName) })) { + include("module-info.class") + } manifest { - attributes("Automatic-Module-Name" to "org.opentest4j.reporting.${project.name}") + attributes( + "Bundle-Name" to project.name, + "Bundle-Description" to project.name, + "Bundle-DocURL" to "https://github.com/ota4j-team/open-test-reporting", + "Bundle-Vendor" to "opentest4j.org", + "Bundle-SymbolicName" to moduleName, + ) + } + bundle { + properties.empty() // see https://github.com/bndtools/bnd/tree/master/gradle-plugins#gradle-configuration-cache-support + bnd( + "-exportcontents: org.opentest4j.reporting.*", + "Import-Package: org.apiguardian.*;resolution:=\"optional\",*", + ) } } javadoc { @@ -66,10 +135,10 @@ } val eventXmlFiles = - files(test.map { it.reports.junitXml.outputLocation.get().asFileTree.matching { include("junit-platform-events-*.xml") } }) + files(test.map { it.reports.junitXml.outputLocation.get().asFileTree.matching { include("open-test-report.xml") } }) val convertTestResultXmlToHierarchicalFormat by registering(JavaExec::class) { - dependsOn(test) + mustRunAfter(test) mainClass.set("org.opentest4j.reporting.cli.ReportingCli") args("convert") classpath(cli) @@ -77,6 +146,21 @@ argumentProviders += CommandLineArgumentProvider { listOf(eventXmlFiles.singleFile.absolutePath) } + outputs.files(provider { eventXmlFiles.firstOrNull()?.resolveSibling("hierarchy.xml") }) + outputs.cacheIf { true } + } + + val generateHtmlReport by registering(JavaExec::class) { + mustRunAfter(test) + mainClass.set("org.opentest4j.reporting.cli.ReportingCli") + args("html-report") + classpath(cli) + inputs.files(eventXmlFiles).withPathSensitivity(NONE).skipWhenEmpty() + argumentProviders += CommandLineArgumentProvider { + listOf(eventXmlFiles.singleFile.absolutePath) + } + outputs.files(provider { eventXmlFiles.firstOrNull()?.let { xmlFile -> xmlFile.resolveSibling(xmlFile.nameWithoutExtension + ".html") } }) + outputs.cacheIf { true } } withType().configureEach { @@ -87,18 +171,24 @@ jvmArgumentProviders += CommandLineArgumentProvider { listOf( "-Djunit.platform.reporting.open.xml.enabled=true", + "-Djunit.platform.reporting.open.xml.git.enabled=true", + "-Djunit.platform.output.capture.stdout=true", + "-Djunit.platform.output.capture.stderr=true", "-Djunit.platform.reporting.output.dir=${reports.junitXml.outputLocation.get().asFile.absolutePath}" ) } doFirst { - // Delete existing event-based report files - eventXmlFiles.files.forEach { + files(reports.junitXml.outputLocation.get().asFileTree.matching { + include("open-test-report.xml") + include("open-test-report.html") + include("hierarchy.xml") + }).files.forEach { Files.delete(it.toPath()) } } - finalizedBy(convertTestResultXmlToHierarchicalFormat) + finalizedBy(convertTestResultXmlToHierarchicalFormat, generateHtmlReport) } } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -3,6 +3,7 @@ plugins { `maven-publish` signing + id("com.gradleup.nmcp") } val isSnapshot = project.version.toString().contains("SNAPSHOT") @@ -22,30 +23,41 @@ publishing { publications { - create("maven") { + register("maven") + withType().configureEach { pom { - name.set(provider { artifactId }) - description.set(provider { "Module \"${project.name}\" of open-test-reporting" }) - url.set("https://github.com/ota4j-team/open-test-reporting") + name = provider { artifactId } + description = provider { "Module \"${project.name}\" of open-test-reporting" } + url = "https://github.com/ota4j-team/open-test-reporting" scm { - connection.set("scm:git:git://github.com/ota4j-team/open-test-reporting.git") - developerConnection.set("scm:git:git://github.com/ota4j-team/open-test-reporting.git") - url.set("https://github.com/ota4j-team/open-test-reporting") + connection = "scm:git:git://github.com/ota4j-team/open-test-reporting.git" + developerConnection = "scm:git:git://github.com/ota4j-team/open-test-reporting.git" + url = "https://github.com/ota4j-team/open-test-reporting" } licenses { license { - name.set("The Apache License, Version 2.0") - url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") + name = "The Apache License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" } } developers { developer { - id.set("marcphilipp") - name.set("Marc Philipp") - email.set("marc@junit.org") + id = "marcphilipp" + name = "Marc Philipp" + email = "marc@junit.org" } } } } } + repositories { + maven { + name = "mavenCentralSnapshots" + url = uri("https://central.sonatype.com/repository/maven-snapshots/") + credentials { + username = providers.gradleProperty("mavenCentralUsername").orNull + password = providers.gradleProperty("mavenCentralPassword").orNull + } + } + } } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/cli/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/cli/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/cli/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/cli/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,23 +1,42 @@ plugins { `java-conventions` - application -} - -application { - applicationName = "open-test-reporting" - mainClass.set("org.opentest4j.reporting.cli.ReportingCli") + alias(libs.plugins.shadow) } dependencies { - implementation(projects.events) - implementation(projects.tooling) + implementation(projects.toolingCore) implementation(libs.picocli) implementation(libs.slf4j.api) - runtimeOnly(libs.log4j.slf4j.impl) + compileOnlyApi(libs.apiguardian) + runtimeOnly(libs.log4j.slf4j2.impl) } +val mainClassName = "org.opentest4j.reporting.cli.ReportingCli" + tasks { compileJava { - options.release.set(11) + options.release = 17 + } + jar { + doLast(objects.newInstance(UpdateJarAction::class).apply { + javaLauncher = project.javaToolchains.launcherFor(java.toolchain) + args.addAll( + "--file", archiveFile.get().asFile.absolutePath, + "--main-class", mainClassName, + ) + }) + } + shadowJar { + manifest { + attributes("Main-Class" to mainClassName) + } + archiveClassifier = "standalone" + exclude("META-INF/maven/**") + exclude("META-INF/LICENSE*") + exclude("META-INF/NOTICE*") + exclude("**/module-info.class") + } + assemble { + dependsOn(shadowJar) } } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ConvertCommand.java jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ConvertCommand.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ConvertCommand.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ConvertCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,8 @@ package org.opentest4j.reporting.cli; -import org.opentest4j.reporting.tooling.converter.DefaultConverter; +import org.apiguardian.api.API; +import org.opentest4j.reporting.tooling.core.converter.DefaultConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import picocli.CommandLine.Command; @@ -25,10 +26,15 @@ import java.nio.file.Path; import java.util.concurrent.Callable; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Converts from the event-based to the hierarchical XML format. + * + * @since 0.1.0 */ @Command(name = "convert", description = "Converts from the event-based to the hierarchical XML format") +@API(status = EXPERIMENTAL, since = "0.1.0") public class ConvertCommand implements Callable { private static final Logger LOG = LoggerFactory.getLogger(ConvertCommand.class); @@ -36,12 +42,16 @@ @Parameters(arity = "1") Path eventsXml; + // Make constructor package-private + ConvertCommand() { + } + @Override public Integer call() throws Exception { var targetFile = eventsXml.resolveSibling("hierarchy.xml"); var converter = new DefaultConverter(); converter.convert(eventsXml, targetFile); - LOG.info("Converted {} to {}", eventsXml, targetFile); + LOG.info("Converted {} to {}", eventsXml, targetFile.toUri()); return 0; } } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/HtmlReportCommand.java jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/HtmlReportCommand.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/HtmlReportCommand.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/HtmlReportCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.cli; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.tooling.core.htmlreport.DefaultHtmlReportWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import picocli.CommandLine.Parameters; + +import java.awt.*; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.Callable; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Converts from the event-based to the hierarchical XML format. + * + * @since 0.2.0 + */ +@Command(name = "html-report", description = "Creates an HTML report from a event-based or hierarchical XML file") +@API(status = EXPERIMENTAL, since = "0.2.0") +public class HtmlReportCommand implements Callable { + + private static final Logger LOG = LoggerFactory.getLogger(HtmlReportCommand.class); + + @Parameters(arity = "1..*", description = "The XML file(s) to convert") + List xmlFiles; + + @Option(names = { "-o", "--output" }, description = "The target HTML file") + Path targetFile; + + @Option(names = "--open", description = "Open the generated HTML report in the default browser") + boolean open; + + // Make constructor package-private + HtmlReportCommand() { + } + + @Override + public Integer call() throws Exception { + if (targetFile == null) { + var firstXmlFile = xmlFiles.get(0); + var sourceFileName = firstXmlFile.getFileName().getFileName().toString(); + var targetFileName = (sourceFileName.endsWith(".xml") + ? sourceFileName.substring(0, sourceFileName.length() - 4) + : sourceFileName) + ".html"; + targetFile = firstXmlFile.resolveSibling(targetFileName); + } + + new DefaultHtmlReportWriter().writeHtmlReport(xmlFiles, targetFile); + + LOG.info("Wrote HTML report to {}", targetFile.toUri()); + if (open) { + LOG.info("Opening HTML report in default browser..."); + Desktop.getDesktop().browse(targetFile.toUri()); + } + return 0; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ReportingCli.java jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ReportingCli.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ReportingCli.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ReportingCli.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +16,32 @@ package org.opentest4j.reporting.cli; +import org.apiguardian.api.API; import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.HelpCommand; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Main entrypoint into the reporting CLI * * @see ConvertCommand * @see ValidateCommand + * @see HtmlReportCommand + * @since 0.1.0 */ @Command(// name = "open-test-reporting", // mixinStandardHelpOptions = true, // - subcommands = { HelpCommand.class, ConvertCommand.class, ValidateCommand.class } // + subcommands = { HelpCommand.class, ConvertCommand.class, ValidateCommand.class, HtmlReportCommand.class } // ) +@API(status = EXPERIMENTAL, since = "0.1.0") public class ReportingCli { + private ReportingCli() { + } + /** * Run the reporting CLI. * diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ValidateCommand.java jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ValidateCommand.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ValidateCommand.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/java/org/opentest4j/reporting/cli/ValidateCommand.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ package org.opentest4j.reporting.cli; -import org.opentest4j.reporting.tooling.validator.DefaultValidator; -import org.opentest4j.reporting.tooling.validator.ValidationResult; -import org.opentest4j.reporting.tooling.validator.Validator; +import org.apiguardian.api.API; +import org.opentest4j.reporting.tooling.core.validator.DefaultValidator; +import org.opentest4j.reporting.tooling.core.validator.ValidationResult; +import org.opentest4j.reporting.tooling.core.validator.Validator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import picocli.CommandLine.Command; @@ -30,13 +31,17 @@ import java.util.List; import java.util.concurrent.Callable; -import static org.opentest4j.reporting.tooling.validator.Severity.ERROR; -import static org.opentest4j.reporting.tooling.validator.Severity.WARNING; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.opentest4j.reporting.tooling.core.validator.Severity.ERROR; +import static org.opentest4j.reporting.tooling.core.validator.Severity.WARNING; /** * Validates XML report files of both formats. + * + * @since 0.1.0 */ @Command(name = "validate", description = "Validates XML report files of both formats") +@API(status = EXPERIMENTAL, since = "0.1.0") public class ValidateCommand implements Callable { private static final Logger LOG = LoggerFactory.getLogger(ValidateCommand.class); @@ -52,6 +57,10 @@ return validateAll() ? 0 : 1; } + // Make constructor package-private + ValidateCommand() { + } + private boolean validateAll() { var validator = new DefaultValidator(catalogs.stream().map(Path::toUri).toArray(URI[]::new)); boolean allValid = true; @@ -83,11 +92,11 @@ private void logValidationMessages(ValidationResult validationResult) { validationResult.forEach(message -> { - if (message.getSeverity() == WARNING) { - LOG.warn("{}\n{}", message.getLocation(), message.getMessage()); + if (message.severity() == WARNING) { + LOG.warn("{}\n{}", message.location(), message.message()); } else { - LOG.error("{}\n{}", message.getLocation(), message.getMessage()); + LOG.error("{}\n{}", message.location(), message.message()); } }); } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/resources/log4j2.xml jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/resources/log4j2.xml --- jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/main/resources/log4j2.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/main/resources/log4j2.xml 2026-06-21 20:26:05.000000000 +0000 @@ -2,7 +2,7 @@ - + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/module/java/org.opentest4j.reporting.cli/module-info.java jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/module/java/org.opentest4j.reporting.cli/module-info.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/cli/src/module/java/org.opentest4j.reporting.cli/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/cli/src/module/java/org.opentest4j.reporting.cli/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Command-line interface (CLI) for validating both XML formats, converting from + * the event-based to the hierarchical format, and generating HTML reports + * + * @since 0.2.0 + */ +module org.opentest4j.reporting.cli { + + requires static org.apiguardian.api; + requires info.picocli; + requires java.desktop; + requires org.opentest4j.reporting.tooling.core; + requires org.slf4j; + + exports org.opentest4j.reporting.cli; + + opens org.opentest4j.reporting.cli to info.picocli; +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/documentation/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/documentation/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ plugins { - id("org.ajoberstar.git-publish") version "4.2.2" + id("org.ajoberstar.git-publish") version "5.1.3" } val schemas by configurations.creating { @@ -12,8 +12,13 @@ } gitPublish { - repoUri.set("https://github.com/ota4j-team/open-test-reporting.git") - branch.set("gh-pages") + repoUri = "https://github.com/ota4j-team/open-test-reporting.git" + referenceRepoUri = rootDir.toURI().toString() + + branch = "gh-pages" + + username = providers.environmentVariable("GIT_USERNAME") + password = providers.environmentVariable("GIT_PASSWORD") contents { from(schemas) diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/documentation/component-diagram.puml jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/component-diagram.puml --- jtreg8-8.1+1+ds1/opentest4j-reporting/documentation/component-diagram.puml 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/component-diagram.puml 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +@startuml + +skinparam { + defaultFontName sans-serif +} + +package org.opentest4j.reporting { + frame "Java 17+" { + [open-test-reporting-cli] as cli + [open-test-reporting-tooling-core] as tooling_core + } + frame "Java 8+" { + [open-test-reporting-events] as events + [open-test-reporting-schema] as schema + [open-test-reporting-tooling-spi] as tooling_spi + } +} + +cli ..> tooling_core + +events ..> schema + +tooling_core ..> schema +tooling_core ..> events +tooling_core ..> tooling_spi + +@enduml Binary files /srv/release.debian.org/tmp/VijDAKK687/jtreg8-8.1+1+ds1/opentest4j-reporting/documentation/html-report-failed.png and /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/html-report-failed.png differ Binary files /srv/release.debian.org/tmp/VijDAKK687/jtreg8-8.1+1+ds1/opentest4j-reporting/documentation/html-report-successful.png and /srv/release.debian.org/tmp/vEI3dGP0gz/jtreg8-8.3+1+ds1/opentest4j-reporting/documentation/html-report-successful.png differ diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/events/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -8,13 +8,22 @@ extendsFrom(woodstox.get()) } +val saxon = configurations.dependencyScope("saxon") +val saxonRuntimeClasspath = configurations.resolvable("saxonRuntimeClasspath") { + extendsFrom(configurations.testRuntimeClasspath.get()) + extendsFrom(saxon.get()) +} + dependencies { api(projects.schema) + compileOnlyApi(libs.apiguardian) testImplementation(libs.archunit) testImplementation(libs.assertj.core) testImplementation(libs.bundles.junit) testImplementation(libs.xmlunit.assertj) + testCompileOnly(libs.jetbrains.annotations) woodstox(libs.woodstox.core) + saxon(libs.saxon) } tasks { @@ -24,7 +33,13 @@ classpath = files(sourceSets.main.map { it.output }) + files(test.map { it.sources.output }) + woodstoxRuntimeClasspath.get() group = JavaBasePlugin.VERIFICATION_GROUP } + val testSaxon by registering(Test::class) { + val test by testing.suites.existing(JvmTestSuite::class) + testClassesDirs = files(test.map { it.sources.output.classesDirs }) + classpath = files(sourceSets.main.map { it.output }) + files(test.map { it.sources.output }) + saxonRuntimeClasspath.get() + group = JavaBasePlugin.VERIFICATION_GROUP + } check { - dependsOn(testWoodstox) + dependsOn(testWoodstox, testSaxon) } } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Appendable.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Appendable.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Appendable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Appendable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,19 @@ package org.opentest4j.reporting.events.api; +import org.apiguardian.api.API; + import java.util.function.Consumer; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Interface for objects that support appending child {@linkplain Element elements}. * * @param parent element type + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public interface Appendable> { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/AttributeValueEscapingWriter.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/AttributeValueEscapingWriter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/AttributeValueEscapingWriter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/AttributeValueEscapingWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,152 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.api; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Collections.unmodifiableMap; + +class AttributeValueEscapingWriter extends Writer { + + private static final Map REPLACEMENTS_IN_ATTRIBUTE_VALUES; + static { + Map tmp = new HashMap<>(3); + tmp.put('\n', " "); + tmp.put('\r', " "); + tmp.put('\t', " "); + REPLACEMENTS_IN_ATTRIBUTE_VALUES = unmodifiableMap(tmp); + } + + private final BufferedWriter delegate; + private boolean whitespaceReplacingEnabled; + + AttributeValueEscapingWriter(BufferedWriter delegate) { + this.delegate = delegate; + } + + void setWhitespaceReplacingEnabled(boolean whitespaceReplacingEnabled) { + this.whitespaceReplacingEnabled = whitespaceReplacingEnabled; + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + if (!whitespaceReplacingEnabled) { + delegate.write(cbuf, off, len); + return; + } + StringBuilder stringBuilder = new StringBuilder(len * 2); + for (int i = off; i < off + len; i++) { + char c = cbuf[i]; + String replacement = REPLACEMENTS_IN_ATTRIBUTE_VALUES.get(c); + if (replacement != null) { + stringBuilder.append(replacement); + } + else { + stringBuilder.append(c); + } + } + delegate.write(stringBuilder.toString()); + } + + @Override + public void write(int c) throws IOException { + if (whitespaceReplacingEnabled) { + super.write(c); + } + else { + delegate.write(c); + } + } + + @Override + public void write(char[] cbuf) throws IOException { + if (whitespaceReplacingEnabled) { + super.write(cbuf); + } + else { + delegate.write(cbuf); + } + } + + @Override + public void write(String str) throws IOException { + if (whitespaceReplacingEnabled) { + super.write(str); + } + else { + delegate.write(str); + } + } + + @Override + public void write(String str, int off, int len) throws IOException { + if (whitespaceReplacingEnabled) { + super.write(str, off, len); + } + else { + delegate.write(str, off, len); + } + } + + @Override + public Writer append(CharSequence csq) throws IOException { + if (whitespaceReplacingEnabled) { + return super.append(csq); + } + else { + return delegate.append(csq); + } + } + + @Override + public Writer append(CharSequence csq, int start, int end) throws IOException { + if (whitespaceReplacingEnabled) { + return super.append(csq, start, end); + } + else { + return delegate.append(csq, start, end); + } + } + + @Override + public Writer append(char c) throws IOException { + if (whitespaceReplacingEnabled) { + return super.append(c); + } + else { + return delegate.append(c); + } + } + + public void newLine() throws IOException { + delegate.newLine(); + } + + @Override + public void flush() throws IOException { + delegate.flush(); + } + + @Override + public void close() throws IOException { + delegate.close(); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/ChildElement.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/ChildElement.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/ChildElement.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/ChildElement.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,19 @@ package org.opentest4j.reporting.events.api; +import org.apiguardian.api.API; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Base class for child elements with well-known parent types. * * @param

    parent element type * @param child element type + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class ChildElement

    , T extends ChildElement> extends Element { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Context.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Context.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Context.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Context.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.api; +import org.apiguardian.api.API; import org.opentest4j.reporting.schema.QualifiedName; import org.w3c.dom.Document; @@ -25,9 +26,14 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Context encapsulating a single XML document along with its namespace configuration. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Context { static Context create(QualifiedName rootElement, NamespaceRegistry namespaceRegistry) { diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DefaultDocumentWriter.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DefaultDocumentWriter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DefaultDocumentWriter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DefaultDocumentWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; -import javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; @@ -41,17 +40,17 @@ class DefaultDocumentWriter> implements DocumentWriter { - private final BufferedWriter bufferedWriter; + private final AttributeValueEscapingWriter out; private final XMLStreamWriter xmlWriter; private final Context context; private final Transformer transformer; - private final SingleElementStreamWriter elementXmlWriter; + private final SingleElementXMLStreamWriter elementXmlWriter; DefaultDocumentWriter(QualifiedName rootElementName, NamespaceRegistry namespaceRegistry, Writer writer) throws Exception { XMLOutputFactory factory = XMLOutputFactory.newInstance(); - bufferedWriter = buffered(writer); - xmlWriter = factory.createXMLStreamWriter(writer); + out = new AttributeValueEscapingWriter(buffered(writer)); + xmlWriter = new EscapingXMLStreamWriter(out, factory.createXMLStreamWriter(out)); xmlWriter.writeStartDocument(); writeNewLine(); writeStartElement(rootElementName, namespaceRegistry); @@ -59,7 +58,7 @@ writeSchemaLocations(namespaceRegistry); xmlWriter.writeCharacters(""); - elementXmlWriter = new SingleElementStreamWriter(xmlWriter, namespaceRegistry); + elementXmlWriter = new SingleElementXMLStreamWriter(xmlWriter, namespaceRegistry); context = Context.create(rootElementName, namespaceRegistry); TransformerFactory transformerFactory = TransformerFactory.newInstance(); @@ -131,182 +130,14 @@ throw new IOException("Failed to write XML", e); } finally { - bufferedWriter.close(); + out.close(); } } private void writeNewLine() throws IOException, XMLStreamException { xmlWriter.flush(); - bufferedWriter.newLine(); - bufferedWriter.flush(); + out.newLine(); + out.flush(); } - private static class SingleElementStreamWriter implements XMLStreamWriter { - - private final XMLStreamWriter delegate; - private final NamespaceRegistry namespaceRegistry; - - public SingleElementStreamWriter(XMLStreamWriter delegate, NamespaceRegistry namespaceRegistry) { - this.delegate = delegate; - this.namespaceRegistry = namespaceRegistry; - } - - @Override - public void writeStartElement(String localName) throws XMLStreamException { - delegate.writeStartElement(localName); - } - - @Override - public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { - delegate.writeStartElement(namespaceURI, localName); - } - - @Override - public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { - delegate.writeStartElement(prefix, localName, namespaceURI); - } - - @Override - public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { - delegate.writeEmptyElement(namespaceURI, localName); - } - - @Override - public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { - delegate.writeEmptyElement(prefix, localName, namespaceURI); - } - - @Override - public void writeEmptyElement(String localName) throws XMLStreamException { - delegate.writeEmptyElement(localName); - } - - @Override - public void writeEndElement() throws XMLStreamException { - delegate.writeEndElement(); - } - - @Override - public void writeEndDocument() { - } - - @Override - public void close() throws XMLStreamException { - delegate.close(); - } - - @Override - public void flush() throws XMLStreamException { - delegate.flush(); - } - - @Override - public void writeAttribute(String localName, String value) throws XMLStreamException { - delegate.writeAttribute(localName, value); - } - - @Override - public void writeAttribute(String prefix, String namespaceURI, String localName, String value) - throws XMLStreamException { - delegate.writeAttribute(prefix, namespaceURI, localName, value); - } - - @Override - public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException { - delegate.writeAttribute(namespaceURI, localName, value); - } - - @Override - public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException { - if (!namespaceRegistry.containsUri(namespaceURI)) { - delegate.writeNamespace(prefix, namespaceURI); - } - } - - @Override - public void writeDefaultNamespace(String namespaceURI) { - } - - @Override - public void writeComment(String data) throws XMLStreamException { - delegate.writeComment(data); - } - - @Override - public void writeProcessingInstruction(String target) throws XMLStreamException { - delegate.writeProcessingInstruction(target); - } - - @Override - public void writeProcessingInstruction(String target, String data) throws XMLStreamException { - delegate.writeProcessingInstruction(target, data); - } - - @Override - public void writeCData(String data) throws XMLStreamException { - delegate.writeCData(data); - } - - @Override - public void writeDTD(String dtd) throws XMLStreamException { - delegate.writeDTD(dtd); - } - - @Override - public void writeEntityRef(String name) throws XMLStreamException { - delegate.writeEntityRef(name); - } - - @Override - public void writeStartDocument() { - } - - @Override - public void writeStartDocument(String version) { - } - - @Override - public void writeStartDocument(String encoding, String version) { - } - - @Override - public void writeCharacters(String text) throws XMLStreamException { - delegate.writeCharacters(text); - } - - @Override - public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { - delegate.writeCharacters(text, start, len); - } - - @Override - public String getPrefix(String uri) throws XMLStreamException { - return delegate.getPrefix(uri); - } - - @Override - public void setPrefix(String prefix, String uri) throws XMLStreamException { - delegate.setPrefix(prefix, uri); - } - - @Override - public void setDefaultNamespace(String uri) throws XMLStreamException { - delegate.setDefaultNamespace(uri); - } - - @Override - public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { - delegate.setNamespaceContext(context); - } - - @Override - public NamespaceContext getNamespaceContext() { - return delegate.getNamespaceContext(); - } - - @Override - public Object getProperty(String name) throws IllegalArgumentException { - return delegate.getProperty(name); - } - } } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DocumentWriter.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DocumentWriter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DocumentWriter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/DocumentWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,24 @@ package org.opentest4j.reporting.events.api; +import org.apiguardian.api.API; import org.opentest4j.reporting.schema.QualifiedName; import java.io.Closeable; +import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.util.function.Consumer; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Writer for documents with a certain root element type. * * @param root element type + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public interface DocumentWriter> extends Closeable, Appendable { /** @@ -67,4 +73,22 @@ return new DefaultDocumentWriter<>(rootElementName, namespaceRegistry, Files.newBufferedWriter(xmlFile)); } + /** + * Create a new document writer with the supplied root {@linkplain QualifiedName element name} and + * {@linkplain NamespaceRegistry namespace registry} that will write to the supplied {@linkplain Writer}. + * + * @param rootElementName root element name + * @param namespaceRegistry namespace registry + * @param writer target {@link Writer}, the writer will be closed when the returned {@link DocumentWriter} is closed. + * @param root element type + * @return new document writer + * @throws Exception in case there's an error preparing the XML writing infrastructure + * @since 0.2.5 + */ + @API(status = EXPERIMENTAL, since = "0.2.5") + static > DocumentWriter create(QualifiedName rootElementName, + NamespaceRegistry namespaceRegistry, Writer writer) throws Exception { + return new DefaultDocumentWriter<>(rootElementName, namespaceRegistry, writer); + } + } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Element.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Element.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Element.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Element.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,32 @@ package org.opentest4j.reporting.events.api; +import org.apiguardian.api.API; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; import org.w3c.dom.Attr; import org.w3c.dom.Document; +import java.util.UUID; import java.util.function.Consumer; +import java.util.regex.Pattern; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; /** * Base class for elements. * * @param element type + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Element> implements Appendable { + // Using zero-width assertions in the split pattern simplifies the splitting process: All split parts + // (including the first and last one) can be used directly, without having to re-add separator characters. + private static final Pattern CDATA_SPLIT_PATTERN = Pattern.compile("(?<=]])(?=>)"); + static final String CDATA_WORKAROUND_COMMENT = "CDATA-WORKAROUND-" + UUID.randomUUID(); + private final Context context; private final Namespace namespace; final org.w3c.dom.Element domElement; @@ -69,7 +81,14 @@ */ @SuppressWarnings("UnusedReturnValue") public Element withCDataSection(String value) { - domElement.appendChild(document().createCDATASection(value)); + String[] parts = CDATA_SPLIT_PATTERN.split(value); + domElement.appendChild(document().createCDATASection(parts[0])); + for (int i = 1; i < parts.length; i++) { + // Force XML serializer to create a new CDATA section by inserting a comment node in between + // that is filtered out in DefaultDocumentWriter.SingleElementStreamWriter#writeComment. + domElement.appendChild(document().createComment(CDATA_WORKAROUND_COMMENT)); + domElement.appendChild(document().createCDATASection(parts[i])); + } return this; } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/EscapingXMLStreamWriter.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/EscapingXMLStreamWriter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/EscapingXMLStreamWriter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/EscapingXMLStreamWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,241 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.api; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import static org.opentest4j.reporting.events.api.Element.CDATA_WORKAROUND_COMMENT; + +class EscapingXMLStreamWriter implements XMLStreamWriter { + + static final char ILLEGAL_CHARACTER_REPLACEMENT = '\uFFFD'; + + private final AttributeValueEscapingWriter out; + private final XMLStreamWriter delegate; + + EscapingXMLStreamWriter(AttributeValueEscapingWriter out, XMLStreamWriter delegate) { + this.out = out; + this.delegate = delegate; + } + + @Override + public void writeStartElement(String localName) throws XMLStreamException { + delegate.writeStartElement(localName); + } + + @Override + public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { + delegate.writeStartElement(namespaceURI, localName); + } + + @Override + public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + delegate.writeStartElement(prefix, localName, namespaceURI); + } + + @Override + public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { + delegate.writeEmptyElement(namespaceURI, localName); + } + + @Override + public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + delegate.writeEmptyElement(prefix, localName, namespaceURI); + } + + @Override + public void writeEmptyElement(String localName) throws XMLStreamException { + delegate.writeEmptyElement(localName); + } + + @Override + public void writeEndElement() throws XMLStreamException { + delegate.writeEndElement(); + } + + @Override + public void writeEndDocument() throws XMLStreamException { + delegate.writeEndDocument(); + } + + @Override + public void close() throws XMLStreamException { + delegate.close(); + } + + @Override + public void flush() throws XMLStreamException { + delegate.flush(); + } + + @Override + public void writeAttribute(String localName, String value) throws XMLStreamException { + withWhitespaceReplacingEnabled(() -> delegate.writeAttribute(localName, replaceIllegalCharacters(value))); + } + + @Override + public void writeAttribute(String prefix, String namespaceURI, String localName, String value) + throws XMLStreamException { + withWhitespaceReplacingEnabled( + () -> delegate.writeAttribute(prefix, namespaceURI, localName, replaceIllegalCharacters(value))); + } + + @Override + public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException { + withWhitespaceReplacingEnabled( + () -> delegate.writeAttribute(namespaceURI, localName, replaceIllegalCharacters(value))); + } + + @Override + public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException { + delegate.writeNamespace(prefix, namespaceURI); + } + + @Override + public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException { + delegate.writeDefaultNamespace(namespaceURI); + } + + @Override + public void writeComment(String data) throws XMLStreamException { + // Remove bogus comment that avoids CDATA sections from being merged + if (!CDATA_WORKAROUND_COMMENT.equals(data)) { + delegate.writeComment(replaceIllegalCharacters(data)); + } + } + + @Override + public void writeProcessingInstruction(String target) throws XMLStreamException { + delegate.writeProcessingInstruction(target); + } + + @Override + public void writeProcessingInstruction(String target, String data) throws XMLStreamException { + delegate.writeProcessingInstruction(target, data); + } + + @Override + public void writeCData(String data) throws XMLStreamException { + delegate.writeCData(replaceIllegalCharacters(data)); + } + + @Override + public void writeDTD(String dtd) throws XMLStreamException { + delegate.writeDTD(dtd); + } + + @Override + public void writeEntityRef(String name) throws XMLStreamException { + delegate.writeEntityRef(name); + } + + @Override + public void writeStartDocument() throws XMLStreamException { + delegate.writeStartDocument(); + } + + @Override + public void writeStartDocument(String version) throws XMLStreamException { + delegate.writeStartDocument(version); + } + + @Override + public void writeStartDocument(String encoding, String version) throws XMLStreamException { + delegate.writeStartDocument(encoding, version); + } + + @Override + public void writeCharacters(String text) throws XMLStreamException { + delegate.writeCharacters(replaceIllegalCharacters(text)); + } + + @Override + public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { + writeCharacters(new String(text, start, len)); + } + + @Override + public String getPrefix(String uri) throws XMLStreamException { + return delegate.getPrefix(uri); + } + + @Override + public void setPrefix(String prefix, String uri) throws XMLStreamException { + delegate.setPrefix(prefix, uri); + } + + @Override + public void setDefaultNamespace(String uri) throws XMLStreamException { + delegate.setDefaultNamespace(uri); + } + + @Override + public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { + delegate.setNamespaceContext(context); + } + + @Override + public NamespaceContext getNamespaceContext() { + return delegate.getNamespaceContext(); + } + + @Override + public Object getProperty(String name) throws IllegalArgumentException { + return delegate.getProperty(name); + } + + private static String replaceIllegalCharacters(String text) { + if (text.codePoints().allMatch(EscapingXMLStreamWriter::isAllowedXmlCharacter)) { + return text; + } + StringBuilder result = new StringBuilder(text.length() * 2); + text.codePoints().forEach(codePoint -> { + if (isAllowedXmlCharacter(codePoint)) { + result.appendCodePoint(codePoint); + } + else { + result.append(ILLEGAL_CHARACTER_REPLACEMENT); + } + }); + return result.toString(); + } + + private static boolean isAllowedXmlCharacter(int codePoint) { + // source: https://www.w3.org/TR/xml/#charsets + return codePoint == 0x9 // + || codePoint == 0xA // + || codePoint == 0xD // + || (codePoint >= 0x20 && codePoint <= 0xD7FF) // + || (codePoint >= 0xE000 && codePoint <= 0xFFFD) // + || (codePoint >= 0x10000 && codePoint <= 0x10FFFF); + } + + private void withWhitespaceReplacingEnabled(XmlStreamOperation operation) throws XMLStreamException { + delegate.flush(); + out.setWhitespaceReplacingEnabled(true); + operation.execute(); + delegate.flush(); + out.setWhitespaceReplacingEnabled(false); + } + + @FunctionalInterface + private interface XmlStreamOperation { + void execute() throws XMLStreamException; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Factory.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Factory.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Factory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/Factory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,20 @@ package org.opentest4j.reporting.events.api; +import org.apiguardian.api.API; + import java.util.function.Consumer; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Factory for creating elements of a certain type for a given {@linkplain Context context}. * * @param the type of element to create + * @since 0.1.0 */ @FunctionalInterface +@API(status = EXPERIMENTAL, since = "0.1.0") public interface Factory { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/NamespaceRegistry.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/NamespaceRegistry.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/NamespaceRegistry.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/NamespaceRegistry.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.api; +import org.apiguardian.api.API; import org.opentest4j.reporting.schema.Namespace; import java.util.Collections; @@ -24,12 +25,16 @@ import java.util.Optional; import java.util.Set; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Registry of namespaces for writing a document. * * @see Namespace * @see DocumentWriter + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class NamespaceRegistry { static final String XSI_PREFIX = "xsi"; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/SingleElementXMLStreamWriter.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/SingleElementXMLStreamWriter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/SingleElementXMLStreamWriter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/api/SingleElementXMLStreamWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,190 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.api; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +class SingleElementXMLStreamWriter implements XMLStreamWriter { + + private final XMLStreamWriter delegate; + private final NamespaceRegistry namespaceRegistry; + + SingleElementXMLStreamWriter(XMLStreamWriter delegate, NamespaceRegistry namespaceRegistry) { + this.delegate = delegate; + this.namespaceRegistry = namespaceRegistry; + } + + @Override + public void writeStartElement(String localName) throws XMLStreamException { + delegate.writeStartElement(localName); + } + + @Override + public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { + delegate.writeStartElement(namespaceURI, localName); + } + + @Override + public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + delegate.writeStartElement(prefix, localName, namespaceURI); + } + + @Override + public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { + delegate.writeEmptyElement(namespaceURI, localName); + } + + @Override + public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + delegate.writeEmptyElement(prefix, localName, namespaceURI); + } + + @Override + public void writeEmptyElement(String localName) throws XMLStreamException { + delegate.writeEmptyElement(localName); + } + + @Override + public void writeEndElement() throws XMLStreamException { + delegate.writeEndElement(); + } + + @Override + public void writeEndDocument() { + } + + @Override + public void close() { + // do not forward close to prevent closing the underlying writer too early + } + + @Override + public void flush() throws XMLStreamException { + delegate.flush(); + } + + @Override + public void writeAttribute(String localName, String value) throws XMLStreamException { + delegate.writeAttribute(localName, value); + } + + @Override + public void writeAttribute(String prefix, String namespaceURI, String localName, String value) + throws XMLStreamException { + delegate.writeAttribute(prefix, namespaceURI, localName, value); + } + + @Override + public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException { + delegate.writeAttribute(namespaceURI, localName, value); + } + + @Override + public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException { + if (!namespaceRegistry.containsUri(namespaceURI)) { + delegate.writeNamespace(prefix, namespaceURI); + } + } + + @Override + public void writeDefaultNamespace(String namespaceURI) { + } + + @Override + public void writeComment(String data) throws XMLStreamException { + delegate.writeComment(data); + } + + @Override + public void writeProcessingInstruction(String target) throws XMLStreamException { + delegate.writeProcessingInstruction(target); + } + + @Override + public void writeProcessingInstruction(String target, String data) throws XMLStreamException { + delegate.writeProcessingInstruction(target, data); + } + + @Override + public void writeCData(String data) throws XMLStreamException { + delegate.writeCData(data); + } + + @Override + public void writeDTD(String dtd) throws XMLStreamException { + delegate.writeDTD(dtd); + } + + @Override + public void writeEntityRef(String name) throws XMLStreamException { + delegate.writeEntityRef(name); + } + + @Override + public void writeStartDocument() { + } + + @Override + public void writeStartDocument(String version) { + } + + @Override + public void writeStartDocument(String encoding, String version) { + } + + @Override + public void writeCharacters(String text) throws XMLStreamException { + delegate.writeCharacters(text); + } + + @Override + public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { + delegate.writeCharacters(text, start, len); + } + + @Override + public String getPrefix(String uri) throws XMLStreamException { + return delegate.getPrefix(uri); + } + + @Override + public void setPrefix(String prefix, String uri) throws XMLStreamException { + delegate.setPrefix(prefix, uri); + } + + @Override + public void setDefaultNamespace(String uri) throws XMLStreamException { + delegate.setDefaultNamespace(uri); + } + + @Override + public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { + delegate.setNamespaceContext(context); + } + + @Override + public NamespaceContext getNamespaceContext() { + return delegate.getNamespaceContext(); + } + + @Override + public Object getProperty(String name) throws IllegalArgumentException { + return delegate.getProperty(name); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Attachments.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Attachments.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Attachments.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Attachments.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,27 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.root.Event; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code attachments} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Attachments extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "attachments"); + /** + * Qualified name of the {@code attachments} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "attachments"); Attachments(Context context) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CoreFactory.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CoreFactory.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CoreFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CoreFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,22 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Element; import org.opentest4j.reporting.events.api.Factory; -import java.io.File; import java.net.URI; import java.time.LocalDateTime; import java.util.Optional; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Factory for elements of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class CoreFactory { private CoreFactory() { @@ -138,6 +143,28 @@ } /** + * Create a factory for {@link File} elements. + * + * @param timestamp the timestamp of creating the file + * @return File factory + * @since 0.2.0 + */ + public static Factory file(LocalDateTime timestamp) { + return context -> new File(context).withTime(timestamp); + } + + /** + * Create a factory for {@link Output} elements. + * + * @param timestamp the timestamp the output was created + * @return Output factory + * @since 0.2.0 + */ + public static Factory output(LocalDateTime timestamp) { + return context -> new Output(context).withTime(timestamp); + } + + /** * Create a factory for {@link Result} elements. * * @param status the status of the result @@ -163,7 +190,7 @@ * @param file the source file * @return FileSource factory */ - public static Factory fileSource(File file) { + public static Factory fileSource(java.io.File file) { return context -> new FileSource(context).withPath(file); } @@ -173,7 +200,7 @@ * @param dir the source directory * @return DirectorySource factory */ - public static Factory directorySource(File dir) { + public static Factory directorySource(java.io.File dir) { return context -> new DirectorySource(context).withPath(dir); } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CpuCores.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CpuCores.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CpuCores.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/CpuCores.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,26 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code cpuCores} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class CpuCores extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "cpuCores"); + /** + * Qualified name of the {@code cpuCores} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "cpuCores"); CpuCores(Context context, int value) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Data.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Data.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Data.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Data.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; @@ -23,13 +24,25 @@ import java.time.LocalDateTime; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code data} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Data extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "data"); - private static final QualifiedName TIME = QualifiedName.of(Namespace.REPORTING_CORE, "time"); + /** + * Qualified name of the {@code data} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "data"); + + /** + * Qualified name of the {@code time} attribute. + */ + public static final QualifiedName TIME = QualifiedName.of(Namespace.REPORTING_CORE, "time"); Data(Context context) { super(context, ELEMENT); @@ -56,9 +69,21 @@ append(context -> new Entry(context, key, value)); } - private static class Entry extends ChildElement { + /** + * The {@code entry} element of the core namespace. + * + * @since 0.2.0 + */ + public static class Entry extends ChildElement { + /** + * Qualified name of the {@code entry} element. + */ public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "entry"); + + /** + * Qualified name of the {@code key} attribute. + */ public static final QualifiedName KEY = QualifiedName.of(Namespace.REPORTING_CORE, "key"); Entry(Context context, String key, String value) { diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/DirectorySource.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/DirectorySource.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/DirectorySource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/DirectorySource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; @@ -23,9 +24,14 @@ import java.io.File; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code directorySource} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class DirectorySource extends ChildElement { private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "directorySource"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/File.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/File.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/File.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/File.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.core; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.api.ChildElement; +import org.opentest4j.reporting.events.api.Context; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; + +import java.time.LocalDateTime; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * The {@code file} element of the core namespace. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class File extends ChildElement { + + /** + * Qualified name of the {@code file} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "file"); + + /** + * Qualified name of the {@code time} attribute. + */ + public static final QualifiedName TIME = QualifiedName.of(Namespace.REPORTING_CORE, "time"); + + /** + * Qualified name of the {@code path} attribute. + */ + public static final QualifiedName PATH = QualifiedName.of(Namespace.REPORTING_CORE, "path"); + + /** + * Qualified name of the {@code path} attribute. + */ + public static final QualifiedName MEDIA_TYPE = QualifiedName.of(Namespace.REPORTING_CORE, "mediaType"); + + File(Context context) { + super(context, ELEMENT); + } + + /** + * Set the {@code time} attribute of this element. + * + * @param timestamp the timestamp to set + * @return this element + */ + public File withTime(LocalDateTime timestamp) { + withAttribute(TIME, timestamp.toString()); + return this; + } + + /** + * Set the {@code path} attribute of this element. + * + * @param path the path to set + * @return this element + */ + public File withPath(String path) { + withAttribute(PATH, path); + return this; + } + + /** + * Set the {@code mediaType} attribute of this element. + * + * @param mediaType the media type to set + * @return this element + */ + public File withMediaType(String mediaType) { + withAttribute(MEDIA_TYPE, mediaType); + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FilePosition.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FilePosition.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FilePosition.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FilePosition.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,38 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.api.Element; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code filePosition} element of the core namespace. + * + * @param

    the type of the parent element + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class FilePosition

    > extends ChildElement> { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "filePosition"); - static final QualifiedName LINE = QualifiedName.of(Namespace.REPORTING_CORE, "line"); - static final QualifiedName COLUMN = QualifiedName.of(Namespace.REPORTING_CORE, "column"); + /** + * Qualified name of the {@code filePosition} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "filePosition"); + + /** + * Qualified name of the {@code line} attribute. + */ + public static final QualifiedName LINE = QualifiedName.of(Namespace.REPORTING_CORE, "line"); + + /** + * Qualified name of the {@code column} attribute. + */ + public static final QualifiedName COLUMN = QualifiedName.of(Namespace.REPORTING_CORE, "column"); FilePosition(Context context) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FileSource.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FileSource.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FileSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/FileSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Appendable; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; @@ -25,9 +26,14 @@ import java.io.File; import java.util.Optional; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code fileSource} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class FileSource extends ChildElement { private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "fileSource"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/HostName.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/HostName.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/HostName.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/HostName.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,26 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code hostName} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class HostName extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "hostName"); + /** + * Qualified name of the {@code hostName} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "hostName"); HostName(Context context, String value) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Infrastructure.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Infrastructure.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Infrastructure.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Infrastructure.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,21 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.root.Events; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code infrastructure} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public final class Infrastructure extends ChildElement { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Metadata.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Metadata.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Metadata.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Metadata.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,27 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.root.Event; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code metadata} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Metadata extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "metadata"); + /** + * Qualified name of the {@code metadata} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "metadata"); Metadata(Context context) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/OperatingSystem.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/OperatingSystem.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/OperatingSystem.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/OperatingSystem.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,26 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code operatingSystem} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class OperatingSystem extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "operatingSystem"); + /** + * Qualified name of the {@code operatingSystem} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "operatingSystem"); OperatingSystem(Context context, String value) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Output.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Output.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Output.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Output.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.core; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.api.ChildElement; +import org.opentest4j.reporting.events.api.Context; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; + +import java.time.LocalDateTime; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * The {@code output} element of the core namespace. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class Output extends ChildElement { + + /** + * Qualified name of the {@code output} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "output"); + + /** + * Qualified name of the {@code time} attribute. + */ + public static final QualifiedName TIME = QualifiedName.of(Namespace.REPORTING_CORE, "time"); + + /** + * Qualified name of the {@code source} attribute. + */ + public static final QualifiedName SOURCE = QualifiedName.of(Namespace.REPORTING_CORE, "source"); + + Output(Context context) { + super(context, ELEMENT); + } + + /** + * Set the {@code time} attribute of this element. + * + * @param timestamp the timestamp to set + * @return this element + */ + public Output withTime(LocalDateTime timestamp) { + withAttribute(TIME, timestamp.toString()); + return this; + } + + /** + * Set the {@code source} attribute of this element. + * + * @param source the source to set + * @return this element + */ + public Output withSource(String source) { + withAttribute(SOURCE, source); + return this; + } + + /** + * Set the content of this element. + * + * @param content the content to set + * @return this element + */ + public Output withContent(String content) { + withCDataSection(content); + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Reason.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Reason.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Reason.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Reason.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,26 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code reason} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Reason extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "reason"); + /** + * Qualified name of the {@code reason} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "reason"); Reason(Context context, String content) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Result.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Result.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Result.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Result.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,32 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.root.Event; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code result} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Result extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "result"); - private static final QualifiedName STATUS = QualifiedName.of(Namespace.REPORTING_CORE, "status"); + /** + * Qualified name of the {@code result} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "result"); + + /** + * Qualified name of the {@code status} attribute. + */ + public static final QualifiedName STATUS = QualifiedName.of(Namespace.REPORTING_CORE, "status"); Result(Context context) { super(context, ELEMENT); @@ -62,6 +75,11 @@ /** * The test failed. */ - FAILED + FAILED, + + /** + * The test errored for a different reason than an assertion failure. + */ + ERRORED } } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Sources.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Sources.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Sources.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Sources.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,27 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.root.Event; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code sources} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Sources extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "sources"); + /** + * Qualified name of the {@code sources} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "sources"); Sources(Context context) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tag.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tag.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tag.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tag.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,26 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code tag} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Tag extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "tag"); + /** + * Qualified name of the {@code tag} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "tag"); Tag(Context context, String value) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tags.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tags.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tags.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/Tags.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,26 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code tags} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Tags extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "tags"); + /** + * Qualified name of the {@code tags} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "tags"); Tags(Context context) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UriSource.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UriSource.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UriSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UriSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; @@ -23,9 +24,14 @@ import java.net.URI; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code uriSource} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class UriSource extends ChildElement { private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "uriSource"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UserName.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UserName.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UserName.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/core/UserName.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,26 @@ package org.opentest4j.reporting.events.core; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code userName} element of the core namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class UserName extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "userName"); + /** + * Qualified name of the {@code userName} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_CORE, "userName"); UserName(Context context, String value) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Branch.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Branch.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Branch.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Branch.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.git; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.api.ChildElement; +import org.opentest4j.reporting.events.api.Context; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * The {code branch} element of the Git namespace. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class Branch extends ChildElement { + + /** + * Qualified name of the {@code branch} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_GIT, "branch"); + + Branch(Context context, String value) { + super(context, ELEMENT); + withContent(value); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Commit.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Commit.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Commit.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Commit.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.git; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.api.ChildElement; +import org.opentest4j.reporting.events.api.Context; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * The {@code commit} element of the Git namespace. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class Commit extends ChildElement { + + /** + * Qualified name of the {@code commit} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_GIT, "commit"); + + Commit(Context context, String hash) { + super(context, ELEMENT); + withContent(hash); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/GitFactory.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/GitFactory.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/GitFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/GitFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.git; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.api.Factory; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Factory for elements of the Git namespace. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class GitFactory { + + private GitFactory() { + } + + /** + * Create a factory for {@link Repository} elements. + * + * @return Repository factory + */ + public static Factory repository() { + return Repository::new; + } + + /** + * Create a factory for {@link Branch} elements. + * + * @param name the branch name + * @return Branch factory + */ + public static Factory branch(String name) { + return context -> new Branch(context, name); + } + + /** + * Create a factory for {@link Commit} elements. + * + * @param hash the commit hash + * @return Commit factory + */ + public static Factory commit(String hash) { + return context -> new Commit(context, hash); + } + + /** + * Create a factory for {@link Status} elements. + * + * @param output the status output of Git + * @return Status factory + */ + public static Factory status(String output) { + return context -> new Status(context, output); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Repository.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Repository.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Repository.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Repository.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.git; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.api.ChildElement; +import org.opentest4j.reporting.events.api.Context; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * The {@code repository} element of the Git namespace. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class Repository extends ChildElement { + + /** + * Qualified name of the {@code repository} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_GIT, "repository"); + + /** + * Qualified name of the {@code originUrl} attribute. + */ + public static final QualifiedName ORIGIN_URL = QualifiedName.of(Namespace.REPORTING_GIT, "originUrl"); + + Repository(Context context) { + super(context, ELEMENT); + } + + /** + * Set the {@code originUrl} attribute of this element. + * + * @param originUrl the URL of the 'origin' remote + * @return this element + */ + public Repository withOriginUrl(String originUrl) { + withAttribute(ORIGIN_URL, originUrl); + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Status.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Status.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Status.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/git/Status.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.events.git; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.api.ChildElement; +import org.opentest4j.reporting.events.api.Context; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * The {@code status} element of the Git namespace. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class Status extends ChildElement { + + /** + * Qualified name of the {@code status} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_GIT, "status"); + + /** + * Qualified name of the {@code clean} attribute. + */ + public static final QualifiedName CLEAN = QualifiedName.of(Namespace.REPORTING_GIT, "clean"); + + Status(Context context, String output) { + super(context, ELEMENT); + withCDataSection(output); + } + + /** + * Set the {@code clean} attribute of this element. + * + * @param clean whether the working directory clean contains no changes or untracked files + * @return this element + */ + public Status withClean(boolean clean) { + withAttribute(CLEAN, String.valueOf(clean)); + return this; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClassSource.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClassSource.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClassSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClassSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Appendable; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; @@ -26,9 +27,14 @@ import java.util.Optional; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code classSource} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class ClassSource extends ChildElement { private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "classSource"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClasspathResourceSource.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClasspathResourceSource.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClasspathResourceSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/ClasspathResourceSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Appendable; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; @@ -26,9 +27,14 @@ import java.util.Optional; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code classpathResourceSource} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class ClasspathResourceSource extends ChildElement { private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "classpathResourceSource"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/FileEncoding.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/FileEncoding.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/FileEncoding.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/FileEncoding.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,27 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.core.Infrastructure; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code fileEncoding} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class FileEncoding extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "fileEncoding"); + /** + * Qualified name of the {@code fileEncoding} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "fileEncoding"); FileEncoding(Context context, String value) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/HeapSize.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/HeapSize.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/HeapSize.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/HeapSize.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,32 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.core.Infrastructure; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code heapSize} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class HeapSize extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "heapSize"); - private static final QualifiedName MAX = QualifiedName.of(Namespace.REPORTING_JAVA, "max"); + /** + * Qualified name of the {@code heapSize} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "heapSize"); + + /** + * Qualified name of the {@code max} attribute. + */ + public static final QualifiedName MAX = QualifiedName.of(Namespace.REPORTING_JAVA, "max"); HeapSize(Context context) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaFactory.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaFactory.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,17 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Factory; -import org.opentest4j.reporting.events.core.Infrastructure; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; /** * Factory for elements of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class JavaFactory { private JavaFactory() { diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaVersion.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaVersion.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaVersion.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/JavaVersion.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,27 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.core.Infrastructure; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code javaVersion} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class JavaVersion extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "javaVersion"); + /** + * Qualified name of the {@code javaVersion} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "javaVersion"); JavaVersion(Context context, String value) { super(context, ELEMENT); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/MethodSource.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/MethodSource.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/MethodSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/MethodSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,21 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.core.Sources; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code methodSource} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class MethodSource extends ChildElement { private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "methodSource"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/PackageSource.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/PackageSource.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/PackageSource.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/PackageSource.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,21 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.core.Sources; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code packageSource} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class PackageSource extends ChildElement { private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "packageSource"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/Throwable.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/Throwable.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/Throwable.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/java/Throwable.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.java; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.core.Result; @@ -25,13 +26,25 @@ import java.io.PrintWriter; import java.io.StringWriter; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code throwable} element of the Java namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Throwable extends ChildElement { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "throwable"); - private static final QualifiedName TYPE = QualifiedName.of(Namespace.REPORTING_JAVA, "type"); + /** + * Qualified name of the {@code throwable} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_JAVA, "throwable"); + + /** + * Qualified name of the {@code type} attribute. + */ + public static final QualifiedName TYPE = QualifiedName.of(Namespace.REPORTING_JAVA, "type"); private static final QualifiedName ASSERTION_ERROR = QualifiedName.of(Namespace.REPORTING_JAVA, "assertionError"); Throwable(Context context) { diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Event.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Event.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Event.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Event.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.root; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.ChildElement; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; @@ -23,9 +24,14 @@ import java.time.Instant; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Abstract base class for all events in the events namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public abstract class Event extends ChildElement { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Events.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Events.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Events.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Events.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opentest4j.reporting.events.root; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.events.api.DocumentWriter; import org.opentest4j.reporting.events.api.Element; @@ -23,14 +24,23 @@ import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import java.io.Writer; import java.nio.file.Path; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code events} element of the events namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Events extends Element { - private static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_EVENTS, "events"); + /** + * Qualified name of the {@code events} element. + */ + public static final QualifiedName ELEMENT = QualifiedName.of(Namespace.REPORTING_EVENTS, "events"); private Events(Context context) { super(context, ELEMENT); @@ -49,4 +59,19 @@ return DocumentWriter.create(ELEMENT, namespaceRegistry, xmlFile); } + /** + * Create a new {@link DocumentWriter} for the event-based reporting format. + * + * @param namespaceRegistry the namespace registry to use + * @param writer the writer to write to, the writer will be closed when the returned {@link DocumentWriter} is closed. + * @return the new {@link DocumentWriter} + * @throws Exception if an error initializing the XML writing infrastructure occurs + * @since 0.2.5 + */ + @API(status = EXPERIMENTAL, since = "0.2.5") + public static DocumentWriter createDocumentWriter(NamespaceRegistry namespaceRegistry, Writer writer) + throws Exception { + return DocumentWriter.create(ELEMENT, namespaceRegistry, writer); + } + } diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Finished.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Finished.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Finished.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Finished.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,21 @@ package org.opentest4j.reporting.events.root; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; import java.time.Instant; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code finished} element of the events namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public final class Finished extends Event { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Reported.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Reported.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Reported.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Reported.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,21 @@ package org.opentest4j.reporting.events.root; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; import java.time.Instant; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code reported} element of the events namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public final class Reported extends Event { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/RootFactory.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/RootFactory.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/RootFactory.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/RootFactory.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,19 @@ package org.opentest4j.reporting.events.root; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Factory; -import org.opentest4j.reporting.events.java.HeapSize; import java.time.Instant; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * Factory for elements of the events namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class RootFactory { private RootFactory() { diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Started.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Started.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Started.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/main/java/org/opentest4j/reporting/events/root/Started.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,21 @@ package org.opentest4j.reporting.events.root; +import org.apiguardian.api.API; import org.opentest4j.reporting.events.api.Context; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; import java.time.Instant; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * The {@code started} element of the events namespace. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public final class Started extends Event { /** diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/module/java/org.opentest4j.reporting.events/module-info.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/module/java/org.opentest4j.reporting.events/module-info.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/module/java/org.opentest4j.reporting.events/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/module/java/org.opentest4j.reporting.events/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Java API for writing the event-based format without having to deal with + * Java’s XML APIs + * + * @since 0.2.0 + */ +module org.opentest4j.reporting.events { + requires static org.apiguardian.api; + requires java.xml; + requires transitive org.opentest4j.reporting.schema; + exports org.opentest4j.reporting.events.api; + exports org.opentest4j.reporting.events.core; + exports org.opentest4j.reporting.events.git; + exports org.opentest4j.reporting.events.java; + exports org.opentest4j.reporting.events.root; +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterSample.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterSample.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterSample.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterSample.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ NamespaceRegistry namespaceRegistry = NamespaceRegistry.builder(Namespace.REPORTING_CORE) // <1> .add("e", Namespace.REPORTING_EVENTS) // + .add("git", Namespace.REPORTING_GIT) // .add("java", Namespace.REPORTING_JAVA) // .build(); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterStreamingSample.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterStreamingSample.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterStreamingSample.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/DocumentWriterStreamingSample.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,53 @@ + +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import org.opentest4j.reporting.events.api.DocumentWriter; +import org.opentest4j.reporting.events.api.NamespaceRegistry; +import org.opentest4j.reporting.events.core.CoreFactory; +import org.opentest4j.reporting.events.root.Events; +import org.opentest4j.reporting.schema.Namespace; + +import java.io.OutputStreamWriter; +import java.time.Instant; + +import static org.opentest4j.reporting.events.core.CoreFactory.*; +import static org.opentest4j.reporting.events.core.Result.Status.SUCCESSFUL; +import static org.opentest4j.reporting.events.root.RootFactory.finished; +import static org.opentest4j.reporting.events.root.RootFactory.started; + +public class DocumentWriterStreamingSample { + + public static void main(String[] args) throws Exception { + + NamespaceRegistry namespaceRegistry = NamespaceRegistry.builder(Namespace.REPORTING_CORE) // <1> + .add("e", Namespace.REPORTING_EVENTS) // + .add("git", Namespace.REPORTING_GIT) // + .add("java", Namespace.REPORTING_JAVA) // + .build(); + + // Example: streaming events to System.out (could be a socket, network stream, etc.) + try (DocumentWriter writer = Events.createDocumentWriter(namespaceRegistry, + new OutputStreamWriter(System.out))) { + writer.append(infrastructure(), infrastructure -> infrastructure // <2> + .append(hostName("wonderland")) // + .append(userName("alice"))); + writer.append(started("1", Instant.now(), "container")); // <3> + writer.append(started("2", Instant.now(), "test"), started -> started.withParentId("1")); // <4> + writer.append(finished("2", Instant.now()), finished -> finished.append(CoreFactory.result(SUCCESSFUL))); // <5> + writer.append(finished("1", Instant.now()), finished -> finished.append(CoreFactory.result(SUCCESSFUL))); // <6> + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/ArchitectureTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/ArchitectureTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/ArchitectureTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/ArchitectureTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/events/api/DocumentWriterTest.java jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/events/api/DocumentWriterTest.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/events/api/DocumentWriterTest.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/events/src/test/java/org/opentest4j/reporting/events/api/DocumentWriterTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,16 @@ package org.opentest4j.reporting.events.api; +import org.intellij.lang.annotations.Language; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.opentest4j.reporting.schema.Namespace; import org.opentest4j.reporting.schema.QualifiedName; +import java.io.StringWriter; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; import static org.xmlunit.assertj3.XmlAssert.assertThat; @@ -43,20 +47,69 @@ try (var writer = DocumentWriter. create(Root.ELEMENT, NAMESPACE_REGISTRY, targetFile)) { writer.append(Child::new, child -> child // .withAttribute(QualifiedName.of(NAMESPACE_A, "a"), "1") // - .withAttribute(QualifiedName.of(NAMESPACE_B, "b"), "2") // - .append(Extension::new, extension -> extension.withContent("conent"))); + .withAttribute(QualifiedName.of(NAMESPACE_B, "b"), "2\r\n\t&< 3 >\0") // + .append(Extension::new, extension -> extension.withContent("conent\1"))); } + @Language("xml") var expected = """ - - con<t>ent + + con<t>ent� """; assertThat(targetFile).and(expected).ignoreWhitespace().areIdentical(); + assertThat(targetFile).withNamespaceContext(Map.of("a", "urn::a", "b", "urn::b")) // + .valueByXPath("//a:child/@b:b").isEqualTo("2\r\n\t&< 3 >\uFFFD"); + + } + + @Test + void escapesNestedCDataSections() throws Exception { + var targetFile = tempDir.resolve("test.xml"); + + var message = ""; + + try (var writer = DocumentWriter. create(Root.ELEMENT, NamespaceRegistry.builder(NAMESPACE_A).build(), + targetFile)) { + writer.append(Child::new, child -> child // + .withAttribute(QualifiedName.of(NAMESPACE_A, "a"), message) // + .withCDataSection(message)); + } + + assertThat(targetFile).withNamespaceContext(Map.of("a", "urn::a")) // + .valueByXPath("//a:child").isEqualTo(message); + assertThat(targetFile).withNamespaceContext(Map.of("a", "urn::a")) // + .valueByXPath("//a:child/@a").isEqualTo(message); + } + + @Test + void producesWellFormedNamespacedXmlWithWriter() throws Exception { + var stringWriter = new StringWriter(); + + try (var writer = DocumentWriter. create(Root.ELEMENT, NAMESPACE_REGISTRY, stringWriter)) { + writer.append(Child::new, child -> child // + .withAttribute(QualifiedName.of(NAMESPACE_A, "a"), "1") // + .withAttribute(QualifiedName.of(NAMESPACE_B, "b"), "2\r\n\t&< 3 >\0") // + .append(Extension::new, extension -> extension.withContent("conent\1"))); + } + + @Language("xml") + var expected = """ + + + con<t>ent� + + + """; + assertThat(stringWriter.toString()).and(expected).ignoreWhitespace().areIdentical(); + assertThat(stringWriter.toString()).withNamespaceContext(Map.of("a", "urn::a", "b", "urn::b")) // + .valueByXPath("//a:child/@b:b").isEqualTo("2\r\n\t&< 3 >\uFFFD"); } static class Root extends Element { diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/gradle.properties jtreg8-8.3+1+ds1/opentest4j-reporting/gradle.properties --- jtreg8-8.1+1+ds1/opentest4j-reporting/gradle.properties 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/gradle.properties 2026-06-21 20:26:05.000000000 +0000 @@ -1,2 +1,6 @@ group = org.opentest4j.reporting -version = 0.1.0-M2 +version = 0.2.5 + +org.gradle.caching=true +org.gradle.parallel=true +org.gradle.configuration-cache.parallel=true diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/.gitignore jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.gitignore --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.gitignore 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +.gradle +node_modules +dist +dist-ssr +*.local +*.tsbuildinfo + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.vite +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/.prettierrc jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.prettierrc --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/.prettierrc 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.prettierrc 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +{} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/.tool-versions jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.tool-versions --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/.tool-versions 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/.tool-versions 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +nodejs 22.21.0 diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,75 @@ +import com.github.gradle.node.npm.task.NpmTask +import com.github.gradle.node.npm.task.NpxTask +import java.util.* + +plugins { + base + alias(libs.plugins.node) + id("com.diffplug.spotless") +} + +node { + download = providers.gradleProperty("openTestReporting.nodeDownload").map { it.toBoolean() }.orElse(true) + version = providers.fileContents(layout.projectDirectory.file(".tool-versions")).asText.map { + it.substringAfter("nodejs").trim() + } + npmInstallCommand = providers.environmentVariable("CI").map { "ci" }.orElse("install") +} + +val distIncludes = arrayOf("public/**", "src/**", "*.html", "*.js", "*.json", "*.ts") + +spotless { + format("prettier") { + target(*distIncludes) + prettier(readVersionFromPackageJson("prettier")).apply { + if (node.download.get()) { + val npmExec = if (System.getProperty("os.name").lowercase(Locale.ROOT).contains("windows")) "/npm.cmd" else "/bin/npm" + npmExecutable("${tasks.npmSetup.get().npmDir.get()}${npmExec}") + } + } + } +} + +val eslintCheck by tasks.registering(NpxTask::class) { + dependsOn(tasks.npmInstall) + command = "eslint" +} + +tasks.check { + dependsOn(eslintCheck) +} + +val eslintFix by tasks.registering(NpxTask::class) { + dependsOn(tasks.npmInstall) + command = "eslint" + args.addAll("--fix") +} + +val buildVueDist by tasks.registering(NpmTask::class) { + dependsOn(tasks.npmInstall) + shouldRunAfter("spotlessPrettierCheck") + inputs.files(fileTree(node.nodeProjectDir) { + include(*distIncludes) + exclude("public/init.js") + }) + outputs.file(node.nodeProjectDir.file("dist/index.html")) + outputs.cacheIf { true } + npmCommand.addAll("run", "build") +} + +tasks.named("spotlessPrettier") { + dependsOn(tasks.npmInstall) +} + +configurations.consumable("htmlReportTemplate") { + outgoing { + artifact(buildVueDist) + } + attributes { + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.RESOURCES)) + } +} + +fun readVersionFromPackageJson(packageName: String) = resources.text.fromFile("package.json").asReader().useLines { lines -> + lines.first { it.contains("\"${packageName}\":") } + }.substringAfter("\"${packageName}\": \"").substringBefore("\"") diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/eslint.config.js jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/eslint.config.js --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/eslint.config.js 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/eslint.config.js 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; +import pluginVue from "eslint-plugin-vue"; +import prettier from "eslint-config-prettier"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { files: ["**/*.{js,mjs,cjs,ts,vue}"] }, + { ignores: ["build/"] }, + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + ...pluginVue.configs["flat/recommended"], + { + files: ["**/*.vue"], + languageOptions: { parserOptions: { parser: tseslint.parser } }, + }, + prettier, +]; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/index.html jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/index.html --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/index.html 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/index.html 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ + + + + + + Open Test Report + + + + + +

    + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/package-lock.json jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/package-lock.json --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/package-lock.json 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/package-lock.json 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,4093 @@ +{ + "name": "html-report", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "html-report", + "version": "0.0.0", + "dependencies": { + "@vueuse/core": "^14.0.0", + "lucide-vue-next": "^0.548.0", + "vue": "^3.4.37", + "vue-easy-lightbox": "^1.19.0", + "vue-i18n": "^11.0.0", + "vue-resizables": "^0.7.1" + }, + "devDependencies": { + "@eslint/js": "9.38.0", + "@tailwindcss/vite": "4.1.16", + "@vitejs/plugin-vue": "6.0.1", + "eslint": "9.38.0", + "eslint-config-prettier": "10.1.8", + "eslint-plugin-vue": "10.5.1", + "globals": "16.4.0", + "prettier": "3.6.2", + "tailwindcss": "4.1.16", + "typescript": "5.9.3", + "typescript-eslint": "8.46.2", + "vite": "7.1.12", + "vite-plugin-singlefile": "2.3.0", + "vue-tsc": "3.1.2" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.1.tgz", + "integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", + "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@intlify/core-base": { + "version": "11.1.12", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.1.12.tgz", + "integrity": "sha512-whh0trqRsSqVLNEUCwU59pyJZYpU8AmSWl8M3Jz2Mv5ESPP6kFh4juas2NpZ1iCvy7GlNRffUD1xr84gceimjg==", + "license": "MIT", + "dependencies": { + "@intlify/message-compiler": "11.1.12", + "@intlify/shared": "11.1.12" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "11.1.12", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.1.12.tgz", + "integrity": "sha512-Fv9iQSJoJaXl4ZGkOCN1LDM3trzze0AS2zRz2EHLiwenwL6t0Ki9KySYlyr27yVOj5aVz0e55JePO+kELIvfdQ==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "11.1.12", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "11.1.12", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.1.12.tgz", + "integrity": "sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.29", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz", + "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz", + "integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz", + "integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz", + "integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz", + "integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz", + "integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz", + "integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz", + "integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz", + "integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz", + "integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz", + "integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz", + "integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz", + "integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz", + "integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz", + "integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz", + "integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz", + "integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz", + "integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz", + "integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz", + "integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz", + "integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz", + "integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.16" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz", + "integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-x64": "4.1.16", + "@tailwindcss/oxide-freebsd-x64": "4.1.16", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-x64-musl": "4.1.16", + "@tailwindcss/oxide-wasm32-wasi": "4.1.16", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz", + "integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz", + "integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz", + "integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz", + "integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz", + "integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz", + "integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz", + "integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz", + "integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz", + "integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz", + "integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.7", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz", + "integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz", + "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.16.tgz", + "integrity": "sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.16", + "@tailwindcss/oxide": "4.1.16", + "tailwindcss": "4.1.16" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", + "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/type-utils": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.46.2", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", + "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", + "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", + "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", + "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", + "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.29" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", + "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.23" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", + "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", + "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz", + "integrity": "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "@vue/shared": "3.5.22", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz", + "integrity": "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.22.tgz", + "integrity": "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "@vue/compiler-core": "3.5.22", + "@vue/compiler-dom": "3.5.22", + "@vue/compiler-ssr": "3.5.22", + "@vue/shared": "3.5.22", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.19", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.22.tgz", + "integrity": "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.1.2.tgz", + "integrity": "sha512-PyFDCqpdfYUT+oMLqcc61oHfJlC6yjhybaefwQjRdkchIihToOEpJ2Wu/Ebq2yrnJdd1EsaAvZaXVAqcxtnDxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.0.0", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz", + "integrity": "sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.22.tgz", + "integrity": "sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.22", + "@vue/shared": "3.5.22" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.22.tgz", + "integrity": "sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.22", + "@vue/runtime-core": "3.5.22", + "@vue/shared": "3.5.22", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.22.tgz", + "integrity": "sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.22", + "@vue/shared": "3.5.22" + }, + "peerDependencies": { + "vue": "3.5.22" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz", + "integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.0.0.tgz", + "integrity": "sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.0.0", + "@vueuse/shared": "14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.0.0.tgz", + "integrity": "sha512-6yoGqbJcMldVCevkFiHDBTB1V5Hq+G/haPlGIuaFZHpXC0HADB0EN1ryQAAceiW+ryS3niUwvdFbGiqHqBrfVA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.0.0.tgz", + "integrity": "sha512-mTCA0uczBgurRlwVaQHfG0Ja7UdGe4g9mwffiJmvLiTtp1G4AQyIjej6si/k8c8pUwTfVpNufck+23gXptPAkw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/alien-signals": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.0.0.tgz", + "integrity": "sha512-JHoRJf18Y6HN4/KZALr3iU+0vW9LKG+8FMThQlbn4+gv8utsLIkwpomjElGPccGeNwh0FI2HN6BLnyFLo6OyLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", + "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.1", + "@eslint/core": "^0.16.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.38.0", + "@eslint/plugin-kit": "^0.4.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "10.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.5.1.tgz", + "integrity": "sha512-SbR9ZBUFKgvWAbq3RrdCtWaW0IKm6wwUiApxf3BVTNfqUIo4IQQmreMg2iHFJJ6C/0wss3LXURBJ1OwS/MhFcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "@stylistic/eslint-plugin": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "vue-eslint-parser": "^10.0.0" + }, + "peerDependenciesMeta": { + "@stylistic/eslint-plugin": { + "optional": true + }, + "@typescript-eslint/parser": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lucide-vue-next": { + "version": "0.548.0", + "resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-0.548.0.tgz", + "integrity": "sha512-VtL3HkoPOhrhBkJdLWm6JY1kmCetsri1lvoaenem5PQagO2cjR1sNENNnuLJHzl/l0IcFg8RKJyiHt2GZtvj2A==", + "license": "ISC", + "peerDependencies": { + "vue": ">=3.0.1" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz", + "integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.44.1", + "@rollup/rollup-android-arm64": "4.44.1", + "@rollup/rollup-darwin-arm64": "4.44.1", + "@rollup/rollup-darwin-x64": "4.44.1", + "@rollup/rollup-freebsd-arm64": "4.44.1", + "@rollup/rollup-freebsd-x64": "4.44.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.1", + "@rollup/rollup-linux-arm-musleabihf": "4.44.1", + "@rollup/rollup-linux-arm64-gnu": "4.44.1", + "@rollup/rollup-linux-arm64-musl": "4.44.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.1", + "@rollup/rollup-linux-riscv64-gnu": "4.44.1", + "@rollup/rollup-linux-riscv64-musl": "4.44.1", + "@rollup/rollup-linux-s390x-gnu": "4.44.1", + "@rollup/rollup-linux-x64-gnu": "4.44.1", + "@rollup/rollup-linux-x64-musl": "4.44.1", + "@rollup/rollup-win32-arm64-msvc": "4.44.1", + "@rollup/rollup-win32-ia32-msvc": "4.44.1", + "@rollup/rollup-win32-x64-msvc": "4.44.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz", + "integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.2.tgz", + "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.46.2", + "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-singlefile": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.0.tgz", + "integrity": "sha512-DAcHzYypM0CasNLSz/WG0VdKOCxGHErfrjOoyIPiNxTPTGmO6rRD/te93n1YL/s+miXq66ipF1brMBikf99c6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">18.0.0" + }, + "peerDependencies": { + "rollup": "^4.44.1", + "vite": "^5.4.11 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz", + "integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.22", + "@vue/compiler-sfc": "3.5.22", + "@vue/runtime-dom": "3.5.22", + "@vue/server-renderer": "3.5.22", + "@vue/shared": "3.5.22" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-easy-lightbox": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/vue-easy-lightbox/-/vue-easy-lightbox-1.19.0.tgz", + "integrity": "sha512-YxLXgjEn91UF3DuK1y8u3Pyx2sJ7a/MnBpkyrBSQkvU1glzEJASyAZ7N+5yDpmxBQDVMwCsL2VmxWGIiFrWCgA==", + "license": "MIT", + "engines": { + "node": ">=14.18.3" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-eslint-parser": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.0.0.tgz", + "integrity": "sha512-xGtmOQJzWUIi6opA7CfJTJsJyCRjibJKHNzq39yqJ/f4AJ+N7Ngr7lDZMl/9ePaobBnsZgifu+7G6bST+gaYJA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.6.0", + "lodash": "^4.17.21", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/vue-i18n": { + "version": "11.1.12", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.1.12.tgz", + "integrity": "sha512-BnstPj3KLHLrsqbVU2UOrPmr0+Mv11bsUZG0PyCOzsawCivk8W00GMXHeVUWIDOgNaScCuZah47CZFE+Wnl8mw==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.1.12", + "@intlify/shared": "11.1.12", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-resizables": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/vue-resizables/-/vue-resizables-0.7.1.tgz", + "integrity": "sha512-sKG0QvbQE+sTKQtuXAnkjA2GTNZIt25LeaGDavA76tMJVUASpJ9+4cFWxZEJLfxBNJ4SX3e1qup/IUI4AUJWjg==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-tsc": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.1.2.tgz", + "integrity": "sha512-3fd4DY0rFczs5f+VB3OhcLU83V6+3Puj2yLBe0Ak65k7ERk+STVNKaOAi0EBo6Lc15UiJB6LzU6Mxy4+h/pKew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.23", + "@vue/language-core": "3.1.2" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/package.json jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/package.json --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/package.json 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/package.json 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ +{ + "name": "html-report", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@vueuse/core": "^14.0.0", + "lucide-vue-next": "^0.548.0", + "vue": "^3.4.37", + "vue-easy-lightbox": "^1.19.0", + "vue-i18n": "^11.0.0", + "vue-resizables": "^0.7.1" + }, + "devDependencies": { + "@eslint/js": "9.38.0", + "@tailwindcss/vite": "4.1.16", + "@vitejs/plugin-vue": "6.0.1", + "eslint": "9.38.0", + "eslint-config-prettier": "10.1.8", + "eslint-plugin-vue": "10.5.1", + "globals": "16.4.0", + "prettier": "3.6.2", + "tailwindcss": "4.1.16", + "typescript": "5.9.3", + "typescript-eslint": "8.46.2", + "vite": "7.1.12", + "vite-plugin-singlefile": "2.3.0", + "vue-tsc": "3.1.2" + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/public/init.js jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/public/init.js --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/public/init.js 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/public/init.js 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,467 @@ +globalThis.testExecutions = [ + { + id: "1", + name: "open-test-report.xml", + durationMillis: 85, + sections: [ + { + title: "Infrastructure", + blocks: [ + { + type: "kvp", + content: { + Hostname: "coriol", + Username: "marc", + "Operating system": "Linux", + "CPU cores": "16", + }, + }, + ], + }, + { + title: "Java Virtual Machine", + blocks: [ + { + type: "kvp", + content: { + "Java version": "21.0.5", + "File encoding": "UTF-8", + "Max heap size": "512 MiB (536870912 bytes)", + }, + }, + ], + }, + { + title: "Git", + blocks: [ + { + type: "kvp", + content: { + Origin: "https://github.com/ota4j-team/open-test-reporting.git", + Branch: "main", + "Commit hash": "95a3fcc4e967f93e01ca54eac9077901e682a411", + Clean: "true", + }, + }, + ], + }, + ], + roots: ["2"], + children: { + 2: { + ids: ["3"], + childStatuses: ["FAILED", "SUCCESSFUL", "SKIPPED", "ABORTED"], + }, + 3: { + ids: ["4", "5", "6", "7"], + childStatuses: ["FAILED", "SUCCESSFUL", "SKIPPED", "ABORTED"], + }, + }, + testNodes: [ + { + id: "2", + name: "JUnit Jupiter", + durationMillis: 85, + status: "SUCCESSFUL", + sections: [ + { + title: "JUnit metadata", + blocks: [ + { + type: "kvp", + content: { + Type: "CONTAINER", + "Unique ID": "[engine:junit-jupiter]", + "Legacy reporting name": "JUnit Jupiter", + }, + }, + ], + }, + ], + }, + { + id: "3", + name: "KitchenSinkTests", + durationMillis: 70, + status: "SUCCESSFUL", + sections: [ + { + title: "Tags", + blocks: [{ type: "labels", content: ["inherited"] }], + }, + { + title: "Sources", + blocks: [ + { + type: "sub", + content: [ + { + title: "Class", + blocks: [ + { + type: "kvp", + content: { + "Class name": "org.example.KitchenSinkTests", + }, + }, + ], + }, + ], + }, + ], + }, + { + title: "JUnit metadata", + blocks: [ + { + type: "kvp", + content: { + Type: "CONTAINER", + "Unique ID": + "[engine:junit-jupiter]/[class:org.example.KitchenSinkTests]", + "Legacy reporting name": "org.example.KitchenSinkTests", + }, + }, + ], + }, + { + title: "Attachments", + blocks: [ + { + type: "sub", + content: [ + { + title: "Data", + metaInfo: "2025-01-04T13:42:08.569908895", + blocks: [{ type: "kvp", content: { value: "beforeAll" } }], + }, + ], + }, + ], + }, + ], + }, + { + id: "4", + name: "successful test", + durationMillis: 13, + status: "SUCCESSFUL", + sections: [ + { + title: "Tags", + blocks: [{ type: "labels", content: ["inherited", "success"] }], + }, + { + title: "Sources", + blocks: [ + { + type: "sub", + content: [ + { + title: "Method", + blocks: [ + { + type: "kvp", + content: { + "Class name": "org.example.KitchenSinkTests", + "Method name": "successful", + "Method parameter types": + "org.junit.jupiter.api.TestReporter", + }, + }, + ], + }, + ], + }, + ], + }, + { + title: "JUnit metadata", + blocks: [ + { + type: "kvp", + content: { + Type: "TEST", + "Unique ID": + "[engine:junit-jupiter]/[class:org.example.KitchenSinkTests]/[method:successful(org.junit.jupiter.api.TestReporter)]", + "Legacy reporting name": "successful(TestReporter)", + }, + }, + ], + }, + { + title: "Attachments", + blocks: [ + { + type: "sub", + content: [ + { + title: "Data", + metaInfo: "2025-01-04T13:42:08.581025508", + blocks: [{ type: "kvp", content: { value: "✅" } }], + }, + ], + }, + ], + }, + ], + }, + { + id: "5", + name: "skipped()", + durationMillis: 1, + status: "SKIPPED", + sections: [ + { + title: "Tags", + blocks: [{ type: "labels", content: ["aborted", "inherited"] }], + }, + { + title: "Sources", + blocks: [ + { + type: "sub", + content: [ + { + title: "Method", + blocks: [ + { + type: "kvp", + content: { + "Class name": "org.example.KitchenSinkTests", + "Method name": "skipped", + }, + }, + ], + }, + ], + }, + ], + }, + { + title: "JUnit metadata", + blocks: [ + { + type: "kvp", + content: { + Type: "TEST", + "Unique ID": + "[engine:junit-jupiter]/[class:org.example.KitchenSinkTests]/[method:skipped()]", + "Legacy reporting name": "skipped()", + }, + }, + ], + }, + { + title: "Reason", + blocks: [{ type: "p", content: "for demonstration purposes" }], + }, + ], + }, + { + id: "6", + name: "aborted(TestReporter)", + durationMillis: 7, + status: "ABORTED", + sections: [ + { + title: "Tags", + blocks: [{ type: "labels", content: ["aborted", "inherited"] }], + }, + { + title: "Sources", + blocks: [ + { + type: "sub", + content: [ + { + title: "Method", + blocks: [ + { + type: "kvp", + content: { + "Class name": "org.example.KitchenSinkTests", + "Method name": "aborted", + "Method parameter types": + "org.junit.jupiter.api.TestReporter", + }, + }, + ], + }, + ], + }, + ], + }, + { + title: "JUnit metadata", + blocks: [ + { + type: "kvp", + content: { + Type: "TEST", + "Unique ID": + "[engine:junit-jupiter]/[class:org.example.KitchenSinkTests]/[method:aborted(org.junit.jupiter.api.TestReporter)]", + "Legacy reporting name": "aborted(TestReporter)", + }, + }, + ], + }, + { + title: "Result", + blocks: [ + { + type: "sub", + content: [ + { + title: "org.opentest4j.TestAbortedException", + blocks: [ + { + type: "pre", + content: + "org.opentest4j.TestAbortedException: for demonstration purposes\n\tat org.junit.jupiter.api.Assumptions.abort(Assumptions.java:300)\n\tat org.example.KitchenSinkTests.aborted(KitchenSinkTests.java:55)\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:580)\n\tat java.base/java.util.ArrayList.forEach(ArrayList.java:1596)\n\tat java.base/java.util.ArrayList.forEach(ArrayList.java:1596)\n", + }, + ], + }, + ], + }, + ], + }, + { + title: "Attachments", + blocks: [ + { + type: "sub", + content: [ + { + title: "Data", + metaInfo: "2025-01-04T13:42:08.598566069", + blocks: [{ type: "kvp", content: { foo: "bar" } }], + }, + { + title: "Data", + metaInfo: "2025-01-04T13:42:08.599224439", + blocks: [{ type: "kvp", content: { baz: "qux" } }], + }, + ], + }, + ], + }, + ], + }, + { + id: "7", + name: "failed(TestReporter)", + durationMillis: 15, + status: "FAILED", + sections: [ + { + title: "Tags", + blocks: [{ type: "labels", content: ["failure", "inherited"] }], + }, + { + title: "Sources", + blocks: [ + { + type: "sub", + content: [ + { + title: "Method", + blocks: [ + { + type: "kvp", + content: { + "Class name": "org.example.KitchenSinkTests", + "Method name": "failed", + "Method parameter types": + "org.junit.jupiter.api.TestReporter", + }, + }, + ], + }, + ], + }, + ], + }, + { + title: "JUnit metadata", + blocks: [ + { + type: "kvp", + content: { + Type: "TEST", + "Unique ID": + "[engine:junit-jupiter]/[class:org.example.KitchenSinkTests]/[method:failed(org.junit.jupiter.api.TestReporter)]", + "Legacy reporting name": "failed(TestReporter)", + }, + }, + ], + }, + { + title: "Result", + blocks: [ + { + type: "sub", + content: [ + { + title: "org.opentest4j.AssertionFailedError", + blocks: [ + { + type: "pre", + content: + "org.opentest4j.AssertionFailedError: expected: \u003cfoo\u003e but was: \u003cbar\u003e\n\tat org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)\n\tat org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)\n\tat org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)\n\tat org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)\n\tat org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)\n\tat org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1145)\n\tat org.example.KitchenSinkTests.failed(KitchenSinkTests.java:73)\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:580)\n\tat java.base/java.util.ArrayList.forEach(ArrayList.java:1596)\n\tat java.base/java.util.ArrayList.forEach(ArrayList.java:1596)\n", + }, + ], + }, + ], + }, + ], + }, + { + title: "Attachments", + blocks: [ + { + type: "sub", + content: [ + { + title: "Data", + metaInfo: "2025-01-04T13:42:08.608483976", + blocks: [ + { type: "kvp", content: { foo: "bar", baz: "qux" } }, + ], + }, + { + title: "File", + metaInfo: "2025-01-04T13:42:08.612645162", + blocks: [ + { type: "pre", content: "Hellö, Wörld!\n" }, + { + type: "kvp", + content: { + Filename: "test.txt", + Path: "link:junit-jupiter/org.example.KitchenSinkTests/failed(org.junit.jupiter.api.TestReporter)/test.txt", + "Media type": "text/plain; charset\u003dISO-8859-1", + }, + }, + ], + }, + { + title: "Standard output", + metaInfo: "2025-01-04T13:42:08.619179136", + blocks: [ + { type: "pre", content: "some standard output\n" }, + ], + }, + { + title: "Standard error", + metaInfo: "2025-01-04T13:42:08.619179136", + blocks: [{ type: "pre", content: "some error output\n" }], + }, + ], + }, + ], + }, + ], + }, + ], + }, +]; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/App.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/App.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/App.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/App.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,40 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/ExecutionIcon.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/ExecutionIcon.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/ExecutionIcon.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/ExecutionIcon.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,17 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/Selection.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/Selection.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/Selection.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/Selection.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,11 @@ +import TestExecution from "./TestExecution.ts"; + +export default class Selection { + public readonly execution: TestExecution; + public readonly item: TestNodeData | TestExecution; + + constructor(execution: TestExecution, item: TestNodeData | TestExecution) { + this.execution = execution; + this.item = item; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/TestExecution.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestExecution.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/TestExecution.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestExecution.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,136 @@ +import Selection from "./Selection.ts"; + +export default class TestExecution { + private static readonly STATUSES = [ + "SKIPPED", + "ABORTED", + "SUCCESSFUL", + "FAILED", + "ERRORED", + ]; + + static initialSelection(executions: TestExecution[]): Selection | undefined { + const failedExecution = executions.find((e) => + this.isFailedOrErrored(e.overallStatus()), + ); + if (failedExecution) { + const failedNode = Array.from(failedExecution.testNodes.values()).find( + (n) => this.isFailedOrErrored(n.status), + ); + if (failedNode) { + return new Selection(failedExecution, failedNode); + } + } + if (executions.length > 0) { + return new Selection(executions[0], executions[0]); + } + return undefined; + } + + private static isFailedOrErrored(status: string) { + return status === "FAILED" || status == "ERRORED"; + } + + static overallStatus(executions: TestExecution[]): string { + const statuses = executions + .map((e) => TestExecution.STATUSES.indexOf(e.overallStatus())) + .sort(); + return statuses.length > 0 + ? TestExecution.STATUSES[statuses[statuses.length - 1]] + : TestExecution.STATUSES[0]; + } + + static statusCount(executions: TestExecution[]): Map { + const statusCount = new Map(); + TestExecution.STATUSES.forEach((s) => statusCount.set(s, 0)); + executions.forEach((e) => { + e.statusCount().forEach((count, status) => { + statusCount.set(status, statusCount.get(status)! + count); + }); + }); + return statusCount; + } + + public readonly id: string; + public readonly name: string; + public readonly durationMillis: number; + public readonly sections: SectionData[]; + + private readonly rootIds: string[]; + private readonly childrenMetadata: Map; + private readonly parentIds: Map; + private readonly testNodes: Map; + + constructor(execution: ExecutionData) { + this.id = execution.id; + this.name = execution.name; + this.durationMillis = execution.durationMillis; + this.sections = execution.sections || []; + this.rootIds = execution.roots || []; + this.childrenMetadata = new Map( + Object.entries(execution.children ? execution.children : []), + ); + this.parentIds = new Map(); + this.childrenMetadata.forEach((children, p) => { + children.ids?.forEach((c) => this.parentIds.set(c, p)); + }); + this.testNodes = new Map(execution.testNodes?.map((n) => [n.id, n])); + } + + size(): number { + return this.testNodes.size; + } + + nodesWithChildren(): TestNodeData[] { + return Array.from(this.childrenMetadata.keys()).map( + (id) => this.testNodes.get(id)!, + ); + } + + roots(): TestNodeData[] { + return this.rootIds.map((id) => this.testNodes.get(id)!); + } + + children(node: TestNodeData): TestNodeData[] { + if (this.childrenMetadata.has(node.id)) { + return this.childrenMetadata + .get(node.id)! + .ids!.map((id) => this.testNodes.get(id)!); + } + return []; + } + + parents(node: TestNodeData): (TestNodeData | TestExecution)[] { + if (this.parentIds.has(node.id)) { + const parentId = this.parentIds.get(node.id)!; + const parent = this.testNodes.get(parentId)!; + return [...this.parents(parent), parent]; + } + return [this]; + } + + nodeStatuses(node: TestNodeData): string[] { + if (this.childrenMetadata.has(node.id)) { + return this.childrenMetadata.get(node.id)!.childStatuses!; + } + return node.status ? [node.status] : []; + } + + overallStatus(): string { + const statuses = Array.from(this.testNodes.values()) + .map((node) => TestExecution.STATUSES.indexOf(node.status)) + .sort(); + return statuses.length > 0 + ? TestExecution.STATUSES[statuses[statuses.length - 1]] + : TestExecution.STATUSES[0]; + } + + statusCount(): Map { + const result = new Map(); + TestExecution.STATUSES.forEach((s) => result.set(s, 0)); + Array.from(this.testNodes.values()).forEach((n) => + result.set(n.status, result.get(n.status)! + 1), + ); + return result; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatus.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatus.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatus.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatus.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +export const testResultStatusForegroundColorClass = (status: string) => { + switch (status) { + case "SUCCESSFUL": + return "text-green-600"; + case "ABORTED": + return "text-yellow-600"; + case "SKIPPED": + return "text-sky-600"; + default: + return "text-red-600"; + } +}; + +export const testResultStatusBackgroundColorClasses = (status: string) => { + switch (status) { + case "SUCCESSFUL": + return [ + "border-green-600", + "bg-green-500", + "dark:border-green-500", + "dark:bg-green-600", + ]; + case "ABORTED": + return [ + "border-yellow-600", + "bg-yellow-500", + "dark:border-yellow-500", + "dark:bg-yellow-600", + ]; + case "SKIPPED": + return [ + "border-sky-600", + "bg-sky-500", + "dark:border-sky-500", + "dark:bg-sky-600", + ]; + default: + return [ + "border-red-600", + "bg-red-500", + "dark:border-red-500", + "dark:bg-red-600", + ]; + } +}; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatusIcon.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatusIcon.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatusIcon.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/TestResultStatusIcon.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,54 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/icon.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/icon.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/common/icon.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/common/icon.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,4 @@ +export const defaultIconProps = { + size: 16, + strokeWidth: 2.25, +}; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/CodeBlock.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/CodeBlock.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/CodeBlock.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/CodeBlock.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsHeader.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsHeader.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsHeader.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsHeader.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,15 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsSections.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsSections.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsSections.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DetailsSections.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,66 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/DurationLabel.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DurationLabel.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/DurationLabel.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/DurationLabel.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/ExecutionDetails.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/ExecutionDetails.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/ExecutionDetails.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/ExecutionDetails.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedBlock.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedBlock.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedBlock.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedBlock.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,78 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedSection.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedSection.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedSection.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/RenderedSection.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,38 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/TestNodeDetails.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/TestNodeDetails.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/TestNodeDetails.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/TestNodeDetails.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,68 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/keys.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/keys.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/details/keys.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/details/keys.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,3 @@ +import { InjectionKey } from "vue"; + +export const imageHandler = Symbol() as InjectionKey<(a: string) => void>; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/header/DarkModeSwitch.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/DarkModeSwitch.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/header/DarkModeSwitch.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/DarkModeSwitch.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/header/ExecutionSummary.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/ExecutionSummary.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/header/ExecutionSummary.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/ExecutionSummary.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,47 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/header/StatusBar.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/StatusBar.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/header/StatusBar.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/header/StatusBar.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,20 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ExecutionTree.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ExecutionTree.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ExecutionTree.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ExecutionTree.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,26 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/SideBar.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/SideBar.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/SideBar.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/SideBar.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,39 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TestNodeTree.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TestNodeTree.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TestNodeTree.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TestNodeTree.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,30 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBar.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBar.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBar.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBar.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,77 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBarIcon.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBarIcon.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBarIcon.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/ToolBarIcon.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,15 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeNode.vue jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeNode.vue --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeNode.vue 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeNode.vue 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,76 @@ + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeState.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeState.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeState.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/components/sidebar/TreeState.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,95 @@ +import TestExecution from "../common/TestExecution.ts"; +import { InjectionKey } from "vue"; + +export const treeStateKey = Symbol() as InjectionKey; + +export default class TreeState { + public readonly nodes: Record; + + public showAborted = true; + public showFailedAndErrored = true; + public showSkipped = true; + public showSuccessful = true; + + constructor(executions: TestExecution[]) { + this.nodes = executions.reduce( + (prev, execution) => { + return { + ...prev, + [execution.id]: { + collapsed: false, + }, + ...execution.nodesWithChildren().reduce((prev, node) => { + const statuses = execution.nodeStatuses(node); + const initiallyCollapsed = + execution.parents(node).length > 1 && + statuses.indexOf("FAILED") == -1 && + statuses.indexOf("ERRORED") == -1; + return { + ...prev, + [node.id]: { + collapsed: initiallyCollapsed, + }, + }; + }, {}), + }; + }, + {} as Record, + ); + } + + toggleShowAborted() { + this.showAborted = !this.showAborted; + } + + toggleShowFailedAndErrored() { + this.showFailedAndErrored = !this.showFailedAndErrored; + } + + toggleShowSuccessful() { + this.showSuccessful = !this.showSuccessful; + } + + toggleShowSkipped() { + this.showSkipped = !this.showSkipped; + } + + collapseAll() { + Object.keys(this.nodes).forEach((key) => { + this.nodes[key].collapsed = true; + }); + } + + expandAll() { + Object.keys(this.nodes).forEach((key) => { + this.nodes[key].collapsed = false; + }); + } + + toggleNode(id: string) { + this.nodes[id].collapsed = !this.nodes[id].collapsed; + } + + isVisible(statuses: string[]): boolean { + return ( + statuses.length == 0 || + statuses.filter((status) => { + switch (status) { + case "SUCCESSFUL": + return this.showSuccessful; + case "FAILED": + case "ERRORED": + return this.showFailedAndErrored; + case "SKIPPED": + return this.showSkipped; + case "ABORTED": + return this.showAborted; + } + }).length > 0 + ); + } +} + +type NodeState = { + collapsed: boolean; +}; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/global.d.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/global.d.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/global.d.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/global.d.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +export declare global { + interface Data { + id: string; + name: string; + durationMillis: number; + sections: SectionData[] | undefined; + } + + interface ExecutionData extends Data { + roots: string[]; + children: Record; + testNodes: TestNodeData[] | undefined; + } + + interface TestNodeData extends Data { + status: string; + } + + interface ChildMetadata { + ids: string[]; + childStatuses: string[]; + } + + interface SectionData { + title: string; + metaInfo: string; + blocks: BlockData[]; + } + + interface BlockData { + type: string; + content: never; + } + + interface ImageBlockData extends BlockData { + altText: string; + } + + declare namespace globalThis { + var testExecutions: ExecutionData[]; // eslint-disable-line no-var + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/main.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/main.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/main.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/main.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,49 @@ +import { createApp } from "vue"; +import { createI18n } from "vue-i18n"; + +import "./style.css"; +import App from "./App.vue"; +import TestExecution from "./components/common/TestExecution.ts"; +import VueEasyLightbox from "vue-easy-lightbox"; + +const app = createApp(App, { + executions: globalThis.testExecutions.map((it) => new TestExecution(it)), +}); + +app.use( + createI18n({ + messages: { + en: { + executionSummary: { + testCount: "No tests | 1 test/container | {count} tests/containers", + errored: "1 errored | {count} errored", + failed: "1 failed | {count} failed", + aborted: "1 aborted | {count} aborted", + skipped: "1 skipped | {count} skipped", + execution: "in 1 execution | in { count } executions", + }, + clipboard: { + copy: "Copy to clipboard", + }, + duration: { + hours: "{count} h", + minutes: "{count} m", + seconds: "{count} s", + millis: "{count} ms", + }, + toolbar: { + collapseAll: "Collapse all", + expandAll: "Expand all", + showAborted: "Show aborted", + showFailedAndErrored: "Show failed/errored", + showSkipped: "Show skipped", + showSuccessful: "Show successful", + }, + }, + }, + }), +); + +app.use(VueEasyLightbox); + +app.mount("#app"); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/style.css jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/style.css --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/style.css 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/style.css 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,3 @@ +@import "tailwindcss"; + +@config '../tailwind.config.js'; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/vite-env.d.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/vite-env.d.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/src/vite-env.d.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/src/vite-env.d.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1 @@ +/// diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tailwind.config.js jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tailwind.config.js --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tailwind.config.js 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tailwind.config.js 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,5 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"], + darkMode: "selector", +}; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tsconfig.app.json jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.app.json --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tsconfig.app.json 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.app.json 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tsconfig.json jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.json --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tsconfig.json 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.json 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tsconfig.node.json jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.node.json --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/tsconfig.node.json 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/tsconfig.node.json 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/vite.config.ts jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/vite.config.ts --- jtreg8-8.1+1+ds1/opentest4j-reporting/html-report/vite.config.ts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/html-report/vite.config.ts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import { viteSingleFile } from "vite-plugin-singlefile"; +import tailwindcss from "@tailwindcss/vite"; + +// https://vitejs.dev/config/ +export default defineConfig(({ command }) => { + const defaultPlugins = [vue(), tailwindcss()]; + if (command === "serve") { + return { + plugins: defaultPlugins, + }; + } else { + // command === 'build' + return { + plugins: [...defaultPlugins, viteSingleFile()], + }; + } +}); diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,116 @@ +import org.gradle.api.tasks.PathSensitivity.NONE +import org.gradle.api.tasks.PathSensitivity.RELATIVE +import java.nio.file.Files + +plugins { + `java-basics` +} + +val cli by configurations.dependencyScope("cli") +val cliClasspath by configurations.resolvable("cliClasspath") { + extendsFrom(cli) +} + +dependencies { + testImplementation(libs.junit.jupiter) + testImplementation(projects.toolingSpi) + + testRuntimeOnly(libs.junit.platform.reporting) + testRuntimeOnly(projects.toolingSpi) + + cli(projects.cli) + cli(libs.junit.platform.reporting) +} + +configurations.all { + resolutionStrategy.dependencySubstitution { + substitute(module("${group}:open-test-reporting-${projects.toolingSpi.name}")) + .using(project(projects.toolingSpi.path)) + } +} + +val htmlReportFile = tasks.test.flatMap { it.reports.junitXml.outputLocation.file("open-test-report.html") } + +tasks { + compileTestJava { + options.release = 17 + modularity.inferModulePath = true + } + + val eventXmlFile = + test.map { it.reports.junitXml.outputLocation.get().file("open-test-report.xml") } + + val convertTestResultXmlToHierarchicalFormat by registering(JavaExec::class) { + mainModule = "org.opentest4j.reporting.cli" + modularity.inferModulePath = true + args("convert") + classpath(cliClasspath) + inputs.file(eventXmlFile).withPathSensitivity(NONE).skipWhenEmpty() + argumentProviders += CommandLineArgumentProvider { + listOf(eventXmlFile.get().asFile.absolutePath) + } + outputs.files(eventXmlFile.map { it.asFile.resolveSibling("hierarchy.xml") }) + outputs.cacheIf { true } + } + + val validateTestResultXml by registering(JavaExec::class) { + mainModule = "org.opentest4j.reporting.cli" + modularity.inferModulePath = true + args("validate") + classpath(cliClasspath) + inputs.file(eventXmlFile).withPathSensitivity(NONE).skipWhenEmpty() + argumentProviders += CommandLineArgumentProvider { + listOf(eventXmlFile.get().asFile.absolutePath) + } + } + + val generateHtmlReport by registering(JavaExec::class) { + mainModule = "org.opentest4j.reporting.cli" + modularity.inferModulePath = true + args("html-report") + classpath(cliClasspath) + outputs.file(htmlReportFile) + inputs.files(eventXmlFile).withPathSensitivity(RELATIVE).skipWhenEmpty() + argumentProviders += CommandLineArgumentProvider { + listOf( + "--output", + htmlReportFile.get().asFile.absolutePath + ) + eventXmlFile.get().asFile.absolutePath + } + outputs.cacheIf { true } + } + + configurations.consumable("xmlReport") { + attributes { + outgoing.artifact(eventXmlFile) + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.RESOURCES)) + } + } + + test { + useJUnitPlatform() + + ignoreFailures = true + + jvmArgumentProviders += CommandLineArgumentProvider { + listOf( + "-Djunit.platform.reporting.open.xml.enabled=true", + "-Djunit.platform.output.capture.stdout=true", + "-Djunit.platform.output.capture.stderr=true", + "-Djunit.platform.reporting.output.dir=${reports.junitXml.outputLocation.get().asFile.absolutePath}" + ) + } + + doFirst { + files(reports.junitXml.outputLocation.get().asFileTree.matching { + include("open-test-report.xml") + include("open-test-report.html") + include("hierarchy.xml") + }).files.forEach { + Files.delete(it.toPath()) + } + } + + finalizedBy(validateTestResultXml, convertTestResultXmlToHierarchicalFormat, generateHtmlReport) + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/src/test/java/module-info.java jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/module-info.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/src/test/java/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,6 @@ +module org.example { + requires org.junit.jupiter.api; + opens org.example to org.junit.platform.commons; + requires org.opentest4j.reporting.tooling.spi; + provides org.opentest4j.reporting.tooling.spi.htmlreport.Contributor with org.example.SampleContributor; +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/KitchenSinkTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/KitchenSinkTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/KitchenSinkTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/KitchenSinkTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,75 @@ +package org.example; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MediaType; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.TestReporter; + +import java.nio.file.Files; +import java.util.LinkedHashMap; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assumptions.abort; + +@Tag("inherited") +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class KitchenSinkTests { + + @SuppressWarnings("JUnitMalformedDeclaration") + @BeforeAll + static void beforeAll(TestReporter reporter) { + reporter.publishEntry("beforeAll"); + } + + @Test + @DisplayName("successful test") + @Tag("success") + @Order(1) + void successful(TestReporter reporter) { + reporter.publishEntry("✅"); + } + + @Test + @Disabled("for demonstration purposes") + @Tag("aborted") + @Order(2) + void skipped() { + } + + @Test + @Tag("aborted") + @Order(3) + void aborted(TestReporter reporter) { + reporter.publishEntry("foo", "bar"); + reporter.publishEntry("baz", "qux"); + + abort("for demonstration purposes"); + } + + @Test + @Tag("failure") + @Order(4) + void failed(TestReporter reporter) { + Map map = new LinkedHashMap<>(); + map.put("foo", "bar"); + map.put("baz", "qux"); + reporter.publishEntry(map); + + MediaType mediaType = MediaType.create("text", "plain", ISO_8859_1); + reporter.publishFile("test.txt", mediaType, file -> Files.write(file, singletonList("Hellö, Wörld!"), ISO_8859_1)); + + System.out.println("some standard output"); + System.err.println("some error output"); + + assertEquals("foo", "bar"); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/SampleContributor.java jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/SampleContributor.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/SampleContributor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/sample-project/src/test/java/org/example/SampleContributor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,18 @@ +package org.example; + +import org.opentest4j.reporting.tooling.spi.htmlreport.Contributor; +import org.opentest4j.reporting.tooling.spi.htmlreport.Section; + +import java.util.List; + +public class SampleContributor implements Contributor { + @Override + public List
    contributeSectionsForExecution(Context context) { + return List.of(); + } + + @Override + public List
    contributeSectionsForTestNode(Context context) { + return List.of(); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/schema/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -9,3 +9,8 @@ artifact(file("src/main/resources/org/opentest4j/reporting/schema")) } } + +dependencies { + compileOnlyApi(libs.apiguardian) + testImplementation(libs.bundles.junit) +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/events.xml jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/events.xml --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/events.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/events.xml 2026-06-21 20:26:05.000000000 +0000 @@ -1,7 +1,7 @@ + xmlns="https://schemas.opentest4j.org/reporting/core/0.2.0" + xmlns:e="https://schemas.opentest4j.org/reporting/events/0.2.0"> wonderland alice diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/hierarchy.xml jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/hierarchy.xml --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/hierarchy.xml 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/docs/asciidoc/includes/hierarchy.xml 2026-06-21 20:26:05.000000000 +0000 @@ -1,6 +1,6 @@ - + wonderland alice diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Namespace.java jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Namespace.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Namespace.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Namespace.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,19 @@ package org.opentest4j.reporting.schema; +import org.apiguardian.api.API; + import java.util.Objects; import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; /** * An XML namespace identified by a URI. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class Namespace { /** @@ -31,28 +37,105 @@ public static final Namespace XML_SCHEMA_INSTANCE = Namespace.of(W3C_XML_SCHEMA_INSTANCE_NS_URI); /** - * Open Test Reporting core namespace + * Open Test Reporting core 0.1.0 namespace + * + * @since 0.2.0 */ - public static final Namespace REPORTING_CORE = Namespace.of("https://schemas.opentest4j.org/reporting/core/0.1.0"); + public static final Namespace REPORTING_CORE_0_1_0 = Namespace.of( + "https://schemas.opentest4j.org/reporting/core/0.1.0"); /** - * Open Test Reporting events namespace + * Open Test Reporting core 0.2.0 namespace + * + * @since 0.2.0 + */ + public static final Namespace REPORTING_CORE_0_2_0 = Namespace.of( + "https://schemas.opentest4j.org/reporting/core/0.2.0"); + + /** + * Latest Open Test Reporting core namespace + */ + public static final Namespace REPORTING_CORE = REPORTING_CORE_0_2_0; + + /** + * Open Test Reporting events 0.1.0 namespace + * + * @since 0.2.0 */ - public static final Namespace REPORTING_EVENTS = Namespace.of( + public static final Namespace REPORTING_EVENTS_0_1_0 = Namespace.of( "https://schemas.opentest4j.org/reporting/events/0.1.0"); /** - * Open Test Reporting Java namespace + * Open Test Reporting events 0.2.0 namespace + * + * @since 0.2.0 + */ + public static final Namespace REPORTING_EVENTS_0_2_0 = Namespace.of( + "https://schemas.opentest4j.org/reporting/events/0.2.0"); + + /** + * Latest Open Test Reporting events namespace + */ + public static final Namespace REPORTING_EVENTS = REPORTING_EVENTS_0_2_0; + + /** + * Open Test Reporting Java 0.1.0 namespace + * + * @since 0.2.0 + */ + public static final Namespace REPORTING_JAVA_0_1_0 = Namespace.of( + "https://schemas.opentest4j.org/reporting/java/0.1.0"); + + /** + * Open Test Reporting Java 0.2.0 namespace + * + * @since 0.2.0 + */ + public static final Namespace REPORTING_JAVA_0_2_0 = Namespace.of( + "https://schemas.opentest4j.org/reporting/java/0.2.0"); + + /** + * Latest Open Test Reporting Java namespace */ - public static final Namespace REPORTING_JAVA = Namespace.of("https://schemas.opentest4j.org/reporting/java/0.1.0"); + public static final Namespace REPORTING_JAVA = REPORTING_JAVA_0_2_0; /** - * Open Test Reporting hierarchical namespace + * Open Test Reporting Git 0.2.0 namespace + * + * @since 0.2.0 */ - public static final Namespace REPORTING_HIERARCHY = Namespace.of( + public static final Namespace REPORTING_GIT_0_2_0 = Namespace.of( + "https://schemas.opentest4j.org/reporting/git/0.2.0"); + + /** + * Latest Open Test Reporting Git namespace + * + * @since 0.2.0 + */ + public static final Namespace REPORTING_GIT = REPORTING_GIT_0_2_0; + + /** + * Open Test Reporting hierarchical 0.1.0 namespace + * + * @since 0.2.0 + */ + public static final Namespace REPORTING_HIERARCHY_0_1_0 = Namespace.of( "https://schemas.opentest4j.org/reporting/hierarchy/0.1.0"); /** + * Open Test Reporting hierarchical 0.2.0 namespace + * + * @since 0.2.0 + */ + public static final Namespace REPORTING_HIERARCHY_0_2_0 = Namespace.of( + "https://schemas.opentest4j.org/reporting/hierarchy/0.2.0"); + + /** + * Latest Open Test Reporting hierarchical namespace + */ + public static final Namespace REPORTING_HIERARCHY = REPORTING_HIERARCHY_0_2_0; + + /** * Create the namespace with the supplied URI. * * @param uri the namespace URI @@ -69,7 +152,7 @@ } /** - * @return the URI that identifies this namespace + * {@return the URI that identifies this namespace} */ public String getUri() { return uri; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/QualifiedName.java jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/QualifiedName.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/QualifiedName.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/QualifiedName.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 the original author or authors. + * Copyright 2021-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,18 @@ package org.opentest4j.reporting.schema; +import org.apiguardian.api.API; + import java.util.Objects; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + /** * A qualified name consisting of a namespace and a simple name. + * + * @since 0.1.0 */ +@API(status = EXPERIMENTAL, since = "0.1.0") public class QualifiedName { /** @@ -43,14 +50,14 @@ } /** - * @return the namespace of this qualified name + * {@return the namespace of this qualified name} */ public Namespace getNamespace() { return namespace; } /** - * @return the simple name of this qualified name + * {@return the simple name of this qualified name} */ public String getSimpleName() { return simpleName; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Schemas.java jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Schemas.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Schemas.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/java/org/opentest4j/reporting/schema/Schemas.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.schema; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static java.util.Collections.unmodifiableMap; + +/** + * Utility class for retrieving schema locations. + * + * @since 0.2.2 + */ +public final class Schemas { + + private static final Map SCHEMAS; + + static { + Map schemas = new HashMap<>(); + schemas.put(Namespace.REPORTING_EVENTS_0_1_0, "/org/opentest4j/reporting/schema/events-0.1.0.xsd"); + schemas.put(Namespace.REPORTING_HIERARCHY_0_1_0, "/org/opentest4j/reporting/schema/hierarchy-0.1.0.xsd"); + schemas.put(Namespace.REPORTING_CORE_0_1_0, "/org/opentest4j/reporting/schema/core-0.1.0.xsd"); + schemas.put(Namespace.REPORTING_JAVA_0_1_0, "/org/opentest4j/reporting/schema/java-0.1.0.xsd"); + schemas.put(Namespace.REPORTING_EVENTS_0_2_0, "/org/opentest4j/reporting/schema/events-0.2.0.xsd"); + schemas.put(Namespace.REPORTING_HIERARCHY_0_2_0, "/org/opentest4j/reporting/schema/hierarchy-0.2.0.xsd"); + schemas.put(Namespace.REPORTING_CORE_0_2_0, "/org/opentest4j/reporting/schema/core-0.2.0.xsd"); + schemas.put(Namespace.REPORTING_GIT_0_2_0, "/org/opentest4j/reporting/schema/git-0.2.0.xsd"); + schemas.put(Namespace.REPORTING_JAVA_0_2_0, "/org/opentest4j/reporting/schema/java-0.2.0.xsd"); + SCHEMAS = unmodifiableMap(schemas); + } + + /** + * {@return the schema location for the given built-in namespace} + * + * @param namespace the namespace to get the schema location for + */ + public static Optional getSchemaLocation(Namespace namespace) { + return Optional.ofNullable(SCHEMAS.get(namespace)) // + .map(Schemas.class::getResource); + } + + private Schemas() { + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.1.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.1.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.1.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.1.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.2.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.2.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.2.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core-0.2.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The media type of the file content, e.g. 'text/plain' or 'application/json', + see https://www.iana.org/assignments/media-types/media-types.xhtml. + For text files, the charset should be specified in the 'charset' attribute, + e.g. 'text/plain; charset=utf-8'. + + + + + + + + + + + + + + Typically 'stdout' or 'stderr' but may also be used for attaching other log output + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core.xsd 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/core.xsd 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.1.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.1.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.1.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.1.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.2.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.2.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.2.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events-0.2.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events.xsd 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/events.xsd 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/git-0.2.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/git-0.2.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/git-0.2.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/git-0.2.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,69 @@ + + + + + + + + + the URL of the 'origin' remote of the Git repository + + + + + + + + + + + + + + + + + + + + the branch the HEAD commit is pointing to, if any + + + + + + + + + + + + the commit hash + + + + + + + + + + + + the output of `git status --porcelain`, potentially empty + + + + + whether the working directory clean contains no changes or untracked files + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.1.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.1.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.1.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.1.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.2.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.2.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.2.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy-0.2.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy.xsd 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/hierarchy.xsd 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.1.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.1.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.1.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.1.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.2.0.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.2.0.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.2.0.xsd 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java-0.2.0.xsd 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java.xsd jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java.xsd --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java.xsd 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/main/resources/org/opentest4j/reporting/schema/java.xsd 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/module/java/org.opentest4j.reporting.schema/module-info.java jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/module/java/org.opentest4j.reporting.schema/module-info.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/module/java/org.opentest4j.reporting.schema/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/module/java/org.opentest4j.reporting.schema/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * XML schema definitions of both formats + * + * @since 0.2.0 + */ +module org.opentest4j.reporting.schema { + requires static org.apiguardian.api; + requires java.xml; + exports org.opentest4j.reporting.schema; +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/test/java/org/opentest4j/reporting/schema/SchemaTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/test/java/org/opentest4j/reporting/schema/SchemaTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/schema/src/test/java/org/opentest4j/reporting/schema/SchemaTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/schema/src/test/java/org/opentest4j/reporting/schema/SchemaTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.schema; + +import org.junit.jupiter.api.Named; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.xml.validation.SchemaFactory; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +import static java.util.Comparator.comparing; +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; + +public class SchemaTests { + + private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + + @ParameterizedTest + @MethodSource("schemas") + void shouldBeValidXmlSchema(Path xsdFile) throws Exception { + SCHEMA_FACTORY.newSchema(xsdFile.toFile()); + } + + @SuppressWarnings("resource") // JUnit will close the stream + static Stream> schemas() throws IOException { + return Files.list(Path.of("src/main/resources/org/opentest4j/reporting/schema")) // + .filter(path -> path.toString().endsWith(".xsd")) // + .map(file -> Named.of(file.getFileName().toString(), file)) // + .sorted(comparing(Named::getName)); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/settings.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/settings.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/settings.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/settings.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -1,3 +1,8 @@ +plugins { + id("com.gradle.develocity") version "4.2.2" + id("com.gradle.common-custom-user-data-gradle-plugin") version "2.4.0" +} + rootProject.name = "open-test-reporting" dependencyResolutionManagement { @@ -6,10 +11,43 @@ } } +val isCiServer = System.getenv("CI") != null + +develocity { + buildScan { + server = "https://ge.junit.org" + uploadInBackground = !isCiServer + + obfuscation { + if (isCiServer) { + username { "github" } + } else { + hostname { null } + ipAddresses { emptyList() } + } + } + + publishing.onlyIf { it.isAuthenticated } + } +} + +buildCache { + local { + isEnabled = !isCiServer + } + remote(develocity.buildCache) { + val authenticated = System.getenv("DEVELOCITY_ACCESS_KEY") != null + isPush = isCiServer && authenticated + } +} + include("cli") include("documentation") include("events") +include("html-report") +include("sample-project") include("schema") -include("tooling") +include("tooling-core") +include("tooling-spi") enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/build.gradle.kts 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -plugins { - `java-conventions` -} - -dependencies { - api(projects.schema) - implementation(projects.events) - testImplementation(libs.assertj.core) - testImplementation(libs.bundles.junit) - testImplementation(libs.xmlunit.assertj) - testCompileOnly(libs.jetbrains.annotations) -} - -tasks { - compileJava { - options.release.set(11) - } -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/Converter.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/Converter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/Converter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/Converter.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.converter; - -import java.nio.file.Path; - -/** - * Converter for event-based reports into the hierarchical format. - */ -public interface Converter { - - /** - * Convert the supplied event-based report into the hierarchical format. - * - * @param eventsXmlFile the source file - * @param hierarchicalXmlFile the target file - * @throws Exception if an error occurs converting or writing to the target file - */ - void convert(Path eventsXmlFile, Path hierarchicalXmlFile) throws Exception; - -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/DefaultConverter.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/DefaultConverter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/DefaultConverter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/converter/DefaultConverter.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,240 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.converter; - -import org.opentest4j.reporting.events.core.Infrastructure; -import org.opentest4j.reporting.events.root.Event; -import org.opentest4j.reporting.events.root.Finished; -import org.opentest4j.reporting.events.root.Reported; -import org.opentest4j.reporting.events.root.Started; -import org.opentest4j.reporting.schema.Namespace; -import org.opentest4j.reporting.schema.QualifiedName; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.nio.file.Path; -import java.time.Duration; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.BiPredicate; -import java.util.function.IntFunction; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toUnmodifiableSet; -import static javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING; -import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE; -import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI; - -/** - * Default implementation of {@link Converter}. - */ -public class DefaultConverter implements Converter { - - private static final String HIERARCHY_PREFIX = "h"; - - private static final String EXECUTION_NODE_NAME = HIERARCHY_PREFIX + ":execution"; - private static final String ROOT_NODE_NAME = HIERARCHY_PREFIX + ":root"; - private static final String CHILD_NODE_NAME = HIERARCHY_PREFIX + ":child"; - - private static final String START_ATTRIBUTE_NAME = "start"; - private static final String DURATION_ATTRIBUTE_NAME = "duration"; - - private static final Set EVENT_ONLY_ATTRIBUTES = Stream.of(Event.ID, Event.TIME, Started.PARENT_ID) // - .map(QualifiedName::getSimpleName) // - .collect(toUnmodifiableSet()); - - @Override - public void convert(Path eventsXmlFile, Path hierarchicalXmlFile) throws Exception { - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - - Document sourceDocument = builder.parse(eventsXmlFile.toFile()); - Node sourceRoot = sourceDocument.getDocumentElement(); - - Document targetDocument = builder.newDocument(); - createRootElement(sourceRoot, targetDocument); - - Map nodeById = new HashMap<>(); - - for (Node child = sourceRoot.getFirstChild(); child != null; child = child.getNextSibling()) { - if (child instanceof Element) { - Element element = (Element) child; - if (matches(Started.ELEMENT, element)) { - started(targetDocument, nodeById, element); - } - else if (matches(Reported.ELEMENT, element)) { - reported(nodeById, element); - } - else if (matches(Finished.ELEMENT, element)) { - finished(nodeById, element); - } - else if (matches(Infrastructure.ELEMENT, element)) { - infrastructure(targetDocument, element); - } - } - } - - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - transformerFactory.setFeature(FEATURE_SECURE_PROCESSING, true); - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); - - transformer.transform(new DOMSource(targetDocument), new StreamResult(hierarchicalXmlFile.toFile())); - } - - private void createRootElement(Node sourceRoot, Document targetDocument) { - Element targetRoot = targetDocument.createElement(EXECUTION_NODE_NAME); - targetDocument.appendChild(targetRoot); - - copyAttributes(sourceRoot, targetRoot, (__, value) -> !Namespace.REPORTING_EVENTS.getUri().equals(value)); - targetRoot.setAttributeNS(XMLNS_ATTRIBUTE_NS_URI, XMLNS_ATTRIBUTE + ":" + HIERARCHY_PREFIX, - Namespace.REPORTING_HIERARCHY.getUri()); - } - - private boolean matches(QualifiedName qualifiedName, Element element) { - return qualifiedName.getNamespace().getUri().equals(element.getNamespaceURI()) - && qualifiedName.getSimpleName().equals(element.getLocalName()); - } - - private void infrastructure(Document targetDocument, Element sourceElement) { - Node targetElement = sourceElement.cloneNode(true); - targetDocument.adoptNode(targetElement); - targetDocument.getDocumentElement().appendChild(targetElement); - } - - private void started(Document targetDocument, Map nodeById, Element sourceElement) { - Element targetElement; - if (sourceElement.hasAttribute(Started.PARENT_ID.getSimpleName())) { - targetElement = targetDocument.createElementNS(Namespace.REPORTING_HIERARCHY.getUri(), CHILD_NODE_NAME); - nodeById.get(sourceElement.getAttribute(Started.PARENT_ID.getSimpleName())).appendChild(targetElement); - } - else { - targetElement = targetDocument.createElementNS(Namespace.REPORTING_HIERARCHY.getUri(), ROOT_NODE_NAME); - targetDocument.getDocumentElement().appendChild(targetElement); - } - - String id = sourceElement.getAttribute(Event.ID.getSimpleName()); - nodeById.put(id, targetElement); - - copyAttributes(sourceElement, targetElement, (name, __) -> !EVENT_ONLY_ATTRIBUTES.contains(name)); - copyChildren(sourceElement, targetElement); - - if (sourceElement.hasAttribute(Event.TIME.getSimpleName())) { - targetElement.setAttribute(START_ATTRIBUTE_NAME, sourceElement.getAttribute(Event.TIME.getSimpleName())); - } - } - - private void reported(Map nodeById, Element sourceElement) { - Element targetElement = nodeById.get(sourceElement.getAttribute(Event.ID.getSimpleName())); - copyAttributes(sourceElement, targetElement, (name, __) -> !EVENT_ONLY_ATTRIBUTES.contains(name)); - mergeChildren(sourceElement, targetElement); - } - - private void finished(Map nodeById, Element sourceElement) { - Element targetElement = nodeById.get(sourceElement.getAttribute(Event.ID.getSimpleName())); - - copyAttributes(sourceElement, targetElement, (name, __) -> !EVENT_ONLY_ATTRIBUTES.contains(name)); - - mergeChildren(sourceElement, targetElement); - - if (targetElement.hasAttribute(START_ATTRIBUTE_NAME) - && sourceElement.hasAttribute(Event.TIME.getSimpleName())) { - Instant start = Instant.parse(targetElement.getAttribute(START_ATTRIBUTE_NAME)); - Instant finish = Instant.parse(sourceElement.getAttribute(Event.TIME.getSimpleName())); - targetElement.setAttribute(DURATION_ATTRIBUTE_NAME, Duration.between(start, finish).toString()); - } - - moveChildrenToEnd(targetElement); - } - - private void moveChildrenToEnd(Element targetElement) { - stream(targetElement.getChildNodes()) // - .filter(child -> CHILD_NODE_NAME.equals(child.getNodeName())) // - .collect(toList()) // avoid concurrent modification - .forEach(child -> { - targetElement.removeChild(child); - targetElement.appendChild(child); - }); - } - - private void copyAttributes(Node sourceNode, Node targetNode, BiPredicate filter) { - stream(sourceNode.getAttributes()) // - .filter(sourceItem -> filter.test(sourceItem.getNodeName(), sourceItem.getNodeValue())) // - .map(sourceItem -> sourceItem.cloneNode(true)) // - .forEach(targetItem -> { - targetNode.getOwnerDocument().adoptNode(targetItem); - targetNode.getAttributes().setNamedItem(targetItem); - }); - } - - private void mergeChildren(Node sourceElement, Node targetElement) { - stream(sourceElement.getChildNodes()) // - .forEach(sourceChild -> findNode(targetElement.getChildNodes(), sourceChild.getNodeName()) // - .ifPresentOrElse( // - existingNode -> copyChildren(sourceChild, existingNode), // - () -> { - Node targetChild = sourceChild.cloneNode(true); - targetElement.getOwnerDocument().adoptNode(targetChild); - targetElement.appendChild(targetChild); - })); - } - - private Optional findNode(NodeList nodes, String name) { - return stream(nodes) // - .filter(node -> node.getNodeName().equals(name)) // - .findAny(); - } - - private void copyChildren(Node sourceElement, Node targetElement) { - stream(sourceElement.getChildNodes()) // - .map(sourceChild -> sourceChild.cloneNode(true)) // - .forEach(targetChild -> { - targetElement.getOwnerDocument().adoptNode(targetChild); - targetElement.appendChild(targetChild); - }); - } - - private static Stream stream(NodeList nodeList) { - return stream(nodeList.getLength(), nodeList::item); - } - - private static Stream stream(NamedNodeMap namedNodeMap) { - return stream(namedNodeMap.getLength(), namedNodeMap::item); - } - - private static Stream stream(int length, IntFunction item) { - return IntStream.range(0, length).mapToObj(item); - } -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/DefaultValidator.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/DefaultValidator.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/DefaultValidator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/DefaultValidator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,244 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.validator; - -import org.opentest4j.reporting.schema.Namespace; -import org.opentest4j.reporting.tooling.converter.Converter; -import org.w3c.dom.ls.LSInput; -import org.w3c.dom.ls.LSResourceResolver; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import javax.xml.catalog.CatalogFeatures; -import javax.xml.catalog.CatalogFeatures.Feature; -import javax.xml.catalog.CatalogResolver; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.SchemaFactory; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import static java.util.Objects.requireNonNull; -import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; -import static javax.xml.catalog.CatalogManager.catalogResolver; -import static org.opentest4j.reporting.tooling.validator.Severity.ERROR; -import static org.opentest4j.reporting.tooling.validator.Severity.WARNING; - -/** - * Default implementation of {@link Validator}. - */ -public class DefaultValidator implements Validator { - - private static final Map SCHEMAS = Map.of( // - Namespace.REPORTING_EVENTS, "/org/opentest4j/reporting/schema/events.xsd", // - Namespace.REPORTING_HIERARCHY, "/org/opentest4j/reporting/schema/hierarchy.xsd", // - Namespace.REPORTING_CORE, "/org/opentest4j/reporting/schema/core.xsd", // - Namespace.REPORTING_JAVA, "/org/opentest4j/reporting/schema/java.xsd"); - - private final SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); - private final CatalogResolver catalogResolver; - - /** - * Create a new instance. - * - * @param catalogs for resolving references to XML schemas - */ - public DefaultValidator(URI... catalogs) { - var features = CatalogFeatures.builder().with(Feature.RESOLVE, "continue").build(); - this.catalogResolver = catalogResolver(features, catalogs); - } - - @Override - public ValidationResult validate(Path xmlFile) { - try (var in = Files.newInputStream(xmlFile)) { - return validateSafely(xmlFile, new StreamSource(in)); - } - catch (Exception e) { - throw new RuntimeException("Failure during validation: " + xmlFile, e); - } - } - - private ValidationResult validateSafely(Path xmlFile, Source source) throws SAXException, IOException { - var errorHandler = new CollectingErrorHandler(xmlFile); - validate(source, errorHandler); - return errorHandler.toValidationResult(); - } - - private void validate(Source source, ErrorHandler errorHandler) throws SAXException, IOException { - var validator = schemaFactory.newSchema().newValidator(); - validator.setResourceResolver(createResourceResolver()); - validator.setErrorHandler(errorHandler); - validator.validate(source); - } - - private LSResourceResolver createResourceResolver() { - return (type, namespaceURI, publicId, systemId, baseURI) -> { - if (namespaceURI != null) { - var namespace = Namespace.of(namespaceURI); - if (SCHEMAS.containsKey(namespace)) { - LSInputImpl input = new LSInputImpl(); - input.setPublicId(publicId); - var schema = SCHEMAS.get(namespace); - input.setSystemId(requireNonNull(Namespace.class.getResource(schema)).toExternalForm()); - input.setBaseURI(baseURI); - var stream = Namespace.class.getResourceAsStream(schema); - input.setCharacterStream(new InputStreamReader(requireNonNull(stream))); - return input; - } - } - if (systemId != null) { - return catalogResolver.resolveResource(type, namespaceURI, publicId, systemId, baseURI); - } - return null; - }; - } - - static class LSInputImpl implements LSInput { - - private Reader characterStream; - private InputStream byteStream; - private String stringData; - private String systemId; - private String publicId; - private String baseURI; - private String encoding; - private boolean certifiedText; - - @Override - public Reader getCharacterStream() { - return characterStream; - } - - @Override - public void setCharacterStream(Reader characterStream) { - this.characterStream = characterStream; - } - - @Override - public InputStream getByteStream() { - return byteStream; - } - - @Override - public void setByteStream(InputStream byteStream) { - this.byteStream = byteStream; - } - - @Override - public String getStringData() { - return stringData; - } - - @Override - public void setStringData(String stringData) { - this.stringData = stringData; - } - - @Override - public String getSystemId() { - return systemId; - } - - @Override - public void setSystemId(String systemId) { - this.systemId = systemId; - } - - @Override - public String getPublicId() { - return publicId; - } - - @Override - public void setPublicId(String publicId) { - this.publicId = publicId; - } - - @Override - public String getBaseURI() { - return baseURI; - } - - @Override - public void setBaseURI(String baseURI) { - this.baseURI = baseURI; - } - - @Override - public String getEncoding() { - return encoding; - } - - @Override - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - @Override - public boolean getCertifiedText() { - return certifiedText; - } - - @Override - public void setCertifiedText(boolean certifiedText) { - this.certifiedText = certifiedText; - } - } - - private static class CollectingErrorHandler implements ErrorHandler { - private final Path xmlFile; - private final List messages = new ArrayList<>(); - - public CollectingErrorHandler(Path xmlFile) { - this.xmlFile = xmlFile; - } - - @Override - public void warning(SAXParseException e) { - addValidationMessage(WARNING, e); - } - - @Override - public void error(SAXParseException e) { - addValidationMessage(ERROR, e); - } - - private void addValidationMessage(Severity severity, SAXParseException e) { - var path = e.getSystemId() == null ? xmlFile.toString() : e.getSystemId(); - var location = new Location(path, e.getLineNumber(), e.getColumnNumber()); - messages.add(new ValidationMessage(severity, location, e.getMessage())); - } - - @Override - public void fatalError(SAXParseException e) throws SAXParseException { - throw e; - } - - public ValidationResult toValidationResult() { - return new ValidationResult(messages); - } - } -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Location.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Location.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Location.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Location.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.validator; - -import java.util.Objects; - -/** - * Location of a {@linkplain ValidationMessage validation message}. - */ -public class Location { - - private final String path; - private final int lineNumber; - private final int column; - - Location(String path, int lineNumber, int column) { - this.path = path; - this.lineNumber = lineNumber; - this.column = column; - } - - /** - * Get the path of the file. - * - * @return the path of the file - */ - public String getPath() { - return path; - } - - /** - * Get the line number. - * - * @return the line number - */ - public int getLineNumber() { - return lineNumber; - } - - /** - * Get the column number. - * - * @return the column number - */ - public int getColumn() { - return column; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Location location = (Location) o; - return lineNumber == location.lineNumber && column == location.column && path.equals(location.path); - } - - @Override - public int hashCode() { - return Objects.hash(path, lineNumber, column); - } - - @Override - public String toString() { - return String.format("%s:%d:%d", path, lineNumber, column); - } -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Severity.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Severity.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Severity.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Severity.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.validator; - -/** - * Severity of a {@linkplain ValidationMessage validation message}. - */ -public enum Severity { - - /** - * A warning. - */ - WARNING, - - /** - * An error. - */ - ERROR -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationMessage.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationMessage.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationMessage.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationMessage.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.validator; - -import java.util.Objects; - -/** - * Validation message with severity and location. - */ -public class ValidationMessage { - - private final Severity severity; - private final Location location; - private final String message; - - ValidationMessage(Severity severity, Location location, String message) { - this.severity = severity; - this.location = location; - this.message = message; - } - - /** - * Get the severity of this validation message. - * - * @return the severity - */ - public Severity getSeverity() { - return severity; - } - - /** - * Get the location of this validation message. - * - * @return the location - */ - public Location getLocation() { - return location; - } - - /** - * Get the message of this validation message. - * - * @return the message - */ - public String getMessage() { - return message; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ValidationMessage that = (ValidationMessage) o; - return severity == that.severity && location.equals(that.location) && message.equals(that.message); - } - - @Override - public int hashCode() { - return Objects.hash(severity, location, message); - } - - @Override - public String toString() { - return String.format("[%s] %s - %s", severity, location, message); - } -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationResult.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationResult.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationResult.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/ValidationResult.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.validator; - -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - -import static java.util.stream.Collectors.joining; - -/** - * Result of validating an XML report file. - */ -public class ValidationResult implements Iterable { - - private final List messages; - - ValidationResult(List messages) { - this.messages = List.copyOf(messages); - } - - /** - * Count the number of validation messages with the supplied severity. - * - * @param severity the severity to count - * @return number of validation messages with the supplied severity - */ - public long count(Severity severity) { - return messages.stream().filter(m -> severity.equals(m.getSeverity())).count(); - } - - @Override - public Iterator iterator() { - return messages.iterator(); - } - - @Override - public String toString() { - return messages.stream() // - .map(Objects::toString) // - .collect(joining("\n")); - } -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Validator.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Validator.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Validator.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/main/java/org/opentest4j/reporting/tooling/validator/Validator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.validator; - -import java.nio.file.Path; - -/** - * Validator for event-based and hierarchical XML report files. - */ -public interface Validator { - - /** - * Validate the supplied XML file. - * - * @param xmlFile the XML file to validate - * @return validation result - */ - ValidationResult validate(Path xmlFile); - -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/converter/DefaultConverterTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/converter/DefaultConverterTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/converter/DefaultConverterTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/converter/DefaultConverterTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.converter; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.opentest4j.reporting.events.api.DocumentWriter; -import org.opentest4j.reporting.events.api.NamespaceRegistry; -import org.opentest4j.reporting.events.root.Events; -import org.opentest4j.reporting.schema.Namespace; -import org.xmlunit.assertj3.XmlAssert; -import org.xmlunit.builder.Input; -import org.xmlunit.util.Convert; - -import java.nio.file.Path; -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.Map; -import java.util.function.Consumer; - -import static org.opentest4j.reporting.events.core.CoreFactory.attachments; -import static org.opentest4j.reporting.events.core.CoreFactory.cpuCores; -import static org.opentest4j.reporting.events.core.CoreFactory.data; -import static org.opentest4j.reporting.events.core.CoreFactory.infrastructure; -import static org.opentest4j.reporting.events.core.CoreFactory.metadata; -import static org.opentest4j.reporting.events.core.CoreFactory.result; -import static org.opentest4j.reporting.events.core.CoreFactory.tag; -import static org.opentest4j.reporting.events.core.CoreFactory.tags; -import static org.opentest4j.reporting.events.core.Result.Status.SUCCESSFUL; -import static org.opentest4j.reporting.events.root.RootFactory.finished; -import static org.opentest4j.reporting.events.root.RootFactory.reported; -import static org.opentest4j.reporting.events.root.RootFactory.started; - -class DefaultConverterTests { - - static final NamespaceRegistry NAMESPACE_REGISTRY = NamespaceRegistry.builder(Namespace.REPORTING_CORE) // - .add("e", Namespace.REPORTING_EVENTS) // - .add("java", Namespace.REPORTING_JAVA) // - .build(); - - Path sourceFile; - Path targetFile; - - @BeforeEach - void setUp(@TempDir Path tempDir) { - sourceFile = tempDir.resolve("events.xml"); - targetFile = tempDir.resolve("hierarchy.xml"); - } - - @Test - void convertsInfrastructureSection() throws Exception { - writeXml(sourceFile, - writer -> writer.append(infrastructure(), infrastructure -> infrastructure.append(cpuCores(42)))); - - new DefaultConverter().convert(sourceFile, targetFile); - - assertAll(targetFile, it -> it.valueByXPath("//*/c:infrastructure/c:cpuCores").isEqualTo(42)); - } - - @Test - void convertsStartedAndFinishedEvents() throws Exception { - var duration = Duration.ofMillis(42); - var startTime = Instant.now().minus(duration); - writeXml(sourceFile, writer -> writer // - .append(started("1", startTime, "container"), started -> started // - .append(metadata(), metadata -> metadata // - .append(tags(), tags -> tags // - .append(tag("a"))))) // - .append(started("2", startTime.plus(duration), "test"), started -> started.withParentId("1")) // - .append(finished("2", startTime.plus(duration.multipliedBy(2)))) // - .append(finished("1", startTime.plus(duration.multipliedBy(3))), finished -> finished // - .append(result(SUCCESSFUL)))); - - new DefaultConverter().convert(sourceFile, targetFile); - - assertAll(targetFile, // - it -> it.nodesByXPath("//*/h:root") // - .hasSize(1) // - .haveAttribute("name", "container") // - .haveAttribute("start", startTime.toString()) // - .haveAttribute("duration", duration.multipliedBy(3).toString()), // - it -> it.valueByXPath("//*/h:root/c:metadata/c:tags/c:tag") // - .isEqualTo("a"), // - it -> it.valueByXPath("//*/h:root/c:result/@status") // - .isEqualTo("SUCCESSFUL"), // - it -> it.nodesByXPath("//*/h:root/h:child") // - .hasSize(1) // - .haveAttribute("name", "test") // - .haveAttribute("start", startTime.plus(duration).toString()) // - .haveAttribute("duration", duration.toString()) // - ); - } - - @Test - void mergesReportEntries() throws Exception { - writeXml(sourceFile, writer -> writer.append(started("1", Instant.now(), "test"), started -> started // - .append(attachments(), attachments -> attachments // - .append(data(LocalDateTime.now()), data -> data.addEntry("started", "1")))) // - .append(reported("1", Instant.now()), reported -> reported // - .append(attachments(), attachments -> attachments // - .append(data(LocalDateTime.now()), data -> data.addEntry("reported", "2")))) // - .append(finished("1", Instant.now()), finished -> finished // - .append(attachments(), attachments -> attachments // - .append(data(LocalDateTime.now()), data -> data.addEntry("finished", "3"))))); - - new DefaultConverter().convert(sourceFile, targetFile); - - assertAll(targetFile, // - it -> it.nodesByXPath("//*/h:root/c:attachments").hasSize(1), // - it -> it.nodesByXPath("//*/h:root/c:attachments/c:data").hasSize(3), // - it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/@key)[1]").isEqualTo("started"), // - it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/text())[1]").isEqualTo("1"), // - it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/@key)[2]").isEqualTo("reported"), // - it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/text())[2]").isEqualTo("2"), // - it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/@key)[3]").isEqualTo("finished"), // - it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/text())[3]").isEqualTo("3") // - ); - } - - private void writeXml(Path eventsXmlFile, Consumer> action) throws Exception { - try (var writer = Events.createDocumentWriter(NAMESPACE_REGISTRY, eventsXmlFile)) { - action.accept(writer); - } - } - - @SafeVarargs - private static void assertAll(Path targetFile, Consumer... checks) { - var document = Convert.toDocument(Input.from(targetFile).build()); - var xmlAssert = XmlAssert.assertThat(document).withNamespaceContext(Map.of( // - "h", Namespace.REPORTING_HIERARCHY.getUri(), // - "c", Namespace.REPORTING_CORE.getUri() // - )); - Assertions.assertAll(targetFile.toUri().toString(), - Arrays.stream(checks).map(it -> () -> it.accept(xmlAssert))); - } - -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/validator/DefaultValidatorTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/validator/DefaultValidatorTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/validator/DefaultValidatorTests.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling/src/test/java/org/opentest4j/reporting/tooling/validator/DefaultValidatorTests.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright 2021-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.opentest4j.reporting.tooling.validator; - -import org.intellij.lang.annotations.Language; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.opentest4j.reporting.tooling.validator.Severity.ERROR; -import static org.opentest4j.reporting.tooling.validator.Severity.WARNING; - -class DefaultValidatorTests { - - @TempDir - Path tempDir; - - @Test - void validatesEventsXmlFile() { - var xmlFile = writeXml(tempDir.resolve("events.xml"), """ - - """); - - var validationResult = new DefaultValidator().validate(xmlFile); - - assertThat(validationResult).isEmpty(); - } - - @Test - void validatesHierarchicalXmlFile() { - var xmlFile = writeXml(tempDir.resolve("hierarchy.xml"), """ - - """); - - var validationResult = new DefaultValidator().validate(xmlFile); - - assertThat(validationResult).isEmpty(); - } - - @Test - void resolvesThirdPartySchemasUsingCatalog() { - writeXml(tempDir.resolve("schema.xsd"), """ - - - - """); - var catalog = writeXml(tempDir.resolve("catalog.xml"), """ - - - - """); - var xmlFile = writeXml(tempDir.resolve("test.xml"), """ - - Hello World! - - """); - - var validationResult = new DefaultValidator(catalog.toUri()).validate(xmlFile); - - assertThat(validationResult).isEmpty(); - } - - @Test - void generatesWarningsAndErrors() { - var xmlFile = writeXml(tempDir.resolve("test.xml"), """ - - Hello World! - - """); - - var validationResult = new DefaultValidator().validate(xmlFile); - - assertThat(validationResult.count(WARNING)).isEqualTo(1); - assertThat(validationResult.count(ERROR)).isEqualTo(1); - } - - private Path writeXml(Path file, @Language("xml") String content) { - try { - return Files.writeString(file, content); - } - catch (IOException e) { - throw new UncheckedIOException(e); - } - } -} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,82 @@ +plugins { + `java-conventions` +} + +val htmlReportTemplate = configurations.dependencyScope("htmlReportTemplate") +val sampleXmlReport = configurations.dependencyScope("sampleXmlReport") + +dependencies { + api(projects.schema) + implementation(projects.events) + implementation(projects.toolingSpi) + implementation(libs.gson) + compileOnlyApi(libs.apiguardian) + + testImplementation(libs.assertj.core) + testImplementation(libs.bundles.junit) + testImplementation(libs.xmlunit.assertj) + testImplementation(libs.playwright) + testCompileOnly(libs.jetbrains.annotations) + + htmlReportTemplate(projects.htmlReport) + sampleXmlReport(project(mapOf("path" to projects.sampleProject.path, "configuration" to "xmlReport"))) +} + +tasks.compileJava { + options.release = 17 +} + +val playwrightInstallationAction = objects.newInstance(InstallPlaywrightDeps::class).apply { + classpath.from(configurations.testRuntimeClasspath) +} + +val installPlaywrightDeps by tasks.registering { + doFirst(playwrightInstallationAction) +} + +val sampleXmlReportFiles = configurations.resolvable("sampleXmlReportFiles") { + extendsFrom(sampleXmlReport.get()) +} + +tasks.test { + inputs.files(sampleXmlReportFiles).withPathSensitivity(PathSensitivity.NONE) + jvmArgumentProviders.add(CommandLineArgumentProvider { + listOf("-DsampleXmlReport=${sampleXmlReportFiles.get().singleFile.absolutePath}") + }) + if (System.getenv("CI") != null) { + doFirst(playwrightInstallationAction) + } +} + +abstract class InstallPlaywrightDeps @Inject constructor (private val execOperations: ExecOperations) : Action { + abstract val classpath: ConfigurableFileCollection + override fun execute(t: Task) { + execOperations.javaexec { + classpath(this@InstallPlaywrightDeps.classpath) + mainClass = "com.microsoft.playwright.CLI" + args("install-deps") + } + } +} + +val htmlReportTemplateFiles = configurations.resolvable("htmlReportTemplateFiles") { + extendsFrom(htmlReportTemplate.get()) +} + +val generatedResourcesDir = layout.buildDirectory.dir("generated/sources/htmlReportTemplate") + +val prepareResourceDir by tasks.registering(Sync::class) { + from(htmlReportTemplateFiles) + rename { + "template.html" + } + into(generatedResourcesDir.map { it.dir("org/opentest4j/reporting/tooling/core/htmlreport") }) +} + +sourceSets { + main { + resources { + srcDir(files(generatedResourcesDir).builtBy(prepareResourceDir)) + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/Converter.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/Converter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/Converter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/Converter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.converter; + +import org.apiguardian.api.API; + +import java.nio.file.Path; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Converter for event-based reports into the hierarchical format. + * + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public interface Converter { + + /** + * Convert the supplied event-based report into the hierarchical format. + * + * @param eventsXmlFile the source file + * @param hierarchicalXmlFile the target file + * @throws Exception if an error occurs converting or writing to the target file + */ + void convert(Path eventsXmlFile, Path hierarchicalXmlFile) throws Exception; + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverter.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,252 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.converter; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.events.root.Event; +import org.opentest4j.reporting.events.root.Finished; +import org.opentest4j.reporting.events.root.Reported; +import org.opentest4j.reporting.events.root.Started; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.nio.file.Path; +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toUnmodifiableSet; +import static javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING; +import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE; +import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.children; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.matches; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.parseNamespace; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.stream; + +/** + * Default implementation of {@link Converter}. + * + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public class DefaultConverter implements Converter { + + private static final String HIERARCHY_PREFIX = "h"; + + private static final String EXECUTION_NODE_NAME = HIERARCHY_PREFIX + ":execution"; + private static final String ROOT_NODE_NAME = HIERARCHY_PREFIX + ":root"; + private static final String CHILD_NODE_NAME = HIERARCHY_PREFIX + ":child"; + + private static final String START_ATTRIBUTE_NAME = "start"; + private static final String DURATION_ATTRIBUTE_NAME = "duration"; + + private static final Set EVENT_ONLY_ATTRIBUTES = Stream.of(Event.ID, Event.TIME, Started.PARENT_ID) // + .map(QualifiedName::getSimpleName) // + .collect(toUnmodifiableSet()); + + private final DocumentBuilderFactory factory; + + /** + * Create a new instance. + */ + public DefaultConverter() { + this.factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + } + + @Override + public void convert(Path eventsXmlFile, Path hierarchicalXmlFile) throws Exception { + + Document sourceDocument = factory.newDocumentBuilder().parse(eventsXmlFile.toFile()); + Document targetDocument = convert(sourceDocument.getDocumentElement()); + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setFeature(FEATURE_SECURE_PROCESSING, true); + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + //noinspection HttpUrlsUsage + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + + transformer.transform(new DOMSource(targetDocument), new StreamResult(hierarchicalXmlFile.toFile())); + } + + /** + * Convert the supplied event-based report into the hierarchical format. + * + * @param sourceRoot the root of the source document + * @return the converted document + * @throws Exception if an error occurs during the conversion + */ + public Document convert(Node sourceRoot) throws Exception { + Document targetDocument = factory.newDocumentBuilder().newDocument(); + + var targetNamespace = determineTargetNamespace(sourceRoot); + createRootElement(sourceRoot, targetDocument, targetNamespace); + + Map nodeById = new HashMap<>(); + + for (Node child = sourceRoot.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child instanceof Element element) { + if (matches(Started.ELEMENT, element)) { + started(targetDocument, nodeById, element, targetNamespace); + } + else if (matches(Reported.ELEMENT, element)) { + reported(nodeById, element); + } + else if (matches(Finished.ELEMENT, element)) { + finished(nodeById, element); + } + else if (matches(Infrastructure.ELEMENT, element)) { + infrastructure(targetDocument, element); + } + } + } + return targetDocument; + } + + private static Namespace determineTargetNamespace(Node sourceRoot) { + return parseNamespace(Namespace.REPORTING_HIERARCHY.getUri()).orElseThrow() // + .withVersion(parseNamespace(sourceRoot.getNamespaceURI()).orElseThrow().getVersion()) // + .toNamespace(); + } + + private void createRootElement(Node sourceRoot, Document targetDocument, Namespace targetNamespace) { + Element targetRoot = targetDocument.createElement(EXECUTION_NODE_NAME); + targetDocument.appendChild(targetRoot); + + copyAttributes(sourceRoot, targetRoot, (__, value) -> !Namespace.REPORTING_EVENTS.getUri().equals(value)); + targetRoot.setAttributeNS(XMLNS_ATTRIBUTE_NS_URI, XMLNS_ATTRIBUTE + ":" + HIERARCHY_PREFIX, + targetNamespace.getUri()); + } + + private void infrastructure(Document targetDocument, Element sourceElement) { + Node targetElement = sourceElement.cloneNode(true); + targetDocument.adoptNode(targetElement); + targetDocument.getDocumentElement().appendChild(targetElement); + } + + private void started(Document targetDocument, Map nodeById, Element sourceElement, + Namespace targetNamespace) { + Element targetElement; + if (sourceElement.hasAttribute(Started.PARENT_ID.getSimpleName())) { + targetElement = targetDocument.createElementNS(targetNamespace.getUri(), CHILD_NODE_NAME); + nodeById.get(sourceElement.getAttribute(Started.PARENT_ID.getSimpleName())).appendChild(targetElement); + } + else { + targetElement = targetDocument.createElementNS(targetNamespace.getUri(), ROOT_NODE_NAME); + targetDocument.getDocumentElement().appendChild(targetElement); + } + + String id = sourceElement.getAttribute(Event.ID.getSimpleName()); + nodeById.put(id, targetElement); + + copyAttributes(sourceElement, targetElement, (name, __) -> !EVENT_ONLY_ATTRIBUTES.contains(name)); + copyChildren(sourceElement, targetElement); + + if (sourceElement.hasAttribute(Event.TIME.getSimpleName())) { + targetElement.setAttribute(START_ATTRIBUTE_NAME, sourceElement.getAttribute(Event.TIME.getSimpleName())); + } + } + + private void reported(Map nodeById, Element sourceElement) { + Element targetElement = nodeById.get(sourceElement.getAttribute(Event.ID.getSimpleName())); + copyAttributes(sourceElement, targetElement, (name, __) -> !EVENT_ONLY_ATTRIBUTES.contains(name)); + mergeChildren(sourceElement, targetElement); + } + + private void finished(Map nodeById, Element sourceElement) { + Element targetElement = nodeById.get(sourceElement.getAttribute(Event.ID.getSimpleName())); + + copyAttributes(sourceElement, targetElement, (name, __) -> !EVENT_ONLY_ATTRIBUTES.contains(name)); + + mergeChildren(sourceElement, targetElement); + + if (targetElement.hasAttribute(START_ATTRIBUTE_NAME) + && sourceElement.hasAttribute(Event.TIME.getSimpleName())) { + Instant start = Instant.parse(targetElement.getAttribute(START_ATTRIBUTE_NAME)); + Instant finish = Instant.parse(sourceElement.getAttribute(Event.TIME.getSimpleName())); + targetElement.setAttribute(DURATION_ATTRIBUTE_NAME, Duration.between(start, finish).toString()); + } + + moveChildrenToEnd(targetElement); + } + + private void moveChildrenToEnd(Element targetElement) { + children(targetElement) // + .filter(child -> CHILD_NODE_NAME.equals(child.getNodeName())) // + .toList() // avoid concurrent modification + .forEach(child -> { + targetElement.removeChild(child); + targetElement.appendChild(child); + }); + } + + private void copyAttributes(Node sourceNode, Node targetNode, BiPredicate filter) { + stream(sourceNode.getAttributes()) // + .filter(sourceItem -> filter.test(sourceItem.getNodeName(), sourceItem.getNodeValue())) // + .map(sourceItem -> sourceItem.cloneNode(true)) // + .forEach(targetItem -> { + targetNode.getOwnerDocument().adoptNode(targetItem); + targetNode.getAttributes().setNamedItem(targetItem); + }); + } + + private void mergeChildren(Node sourceElement, Node targetElement) { + children(sourceElement) // + .forEach(sourceChild -> findNode(targetElement.getChildNodes(), sourceChild.getNodeName()) // + .ifPresentOrElse( // + existingNode -> copyChildren(sourceChild, existingNode), // + () -> { + Node targetChild = sourceChild.cloneNode(true); + targetElement.getOwnerDocument().adoptNode(targetChild); + targetElement.appendChild(targetChild); + })); + } + + private Optional findNode(NodeList nodes, String name) { + return stream(nodes) // + .filter(node -> node.getNodeName().equals(name)) // + .findAny(); + } + + private void copyChildren(Node sourceElement, Node targetElement) { + children(sourceElement) // + .map(sourceChild -> sourceChild.cloneNode(true)) // + .forEach(targetChild -> { + targetElement.getOwnerDocument().adoptNode(targetChild); + targetElement.appendChild(targetChild); + }); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/CoreContributor.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/CoreContributor.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/CoreContributor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/CoreContributor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,317 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.core.Attachments; +import org.opentest4j.reporting.events.core.CpuCores; +import org.opentest4j.reporting.events.core.Data; +import org.opentest4j.reporting.events.core.File; +import org.opentest4j.reporting.events.core.FilePosition; +import org.opentest4j.reporting.events.core.HostName; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.events.core.Metadata; +import org.opentest4j.reporting.events.core.OperatingSystem; +import org.opentest4j.reporting.events.core.Output; +import org.opentest4j.reporting.events.core.Reason; +import org.opentest4j.reporting.events.core.Result; +import org.opentest4j.reporting.events.core.Sources; +import org.opentest4j.reporting.events.core.Tag; +import org.opentest4j.reporting.events.core.Tags; +import org.opentest4j.reporting.events.core.UserName; +import org.opentest4j.reporting.schema.QualifiedName; +import org.opentest4j.reporting.tooling.core.util.DomUtils; +import org.opentest4j.reporting.tooling.spi.htmlreport.Contributor; +import org.opentest4j.reporting.tooling.spi.htmlreport.Image; +import org.opentest4j.reporting.tooling.spi.htmlreport.KeyValuePairs; +import org.opentest4j.reporting.tooling.spi.htmlreport.Labels; +import org.opentest4j.reporting.tooling.spi.htmlreport.Paragraph; +import org.opentest4j.reporting.tooling.spi.htmlreport.PreFormattedOutput; +import org.opentest4j.reporting.tooling.spi.htmlreport.Section; +import org.opentest4j.reporting.tooling.spi.htmlreport.Subsections; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.findChild; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.findChildren; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.getAttribute; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.getAttributeValue; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.matches; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.stream; + +/** + * Contributes sections to the HTML report elements in the core schema. + * + * @since 0.2.0 + */ +@API(status = INTERNAL, since = "0.2.0") +public class CoreContributor implements Contributor { + + private static final Pattern CAMEL_CASE_WORD_BOUNDARY_PATTERN = Pattern.compile("([a-z])([A-Z])"); + private static final Set SUPPORTED_IMAGE_MEDIA_TYPES = Set.of("image/png", "image/jpeg", "image/gif", + "image/avif", "image/webp", "image/svg+xml"); + private static final Set SUPPORTED_TEXT_MEDIA_TYPES = Set.of("text/csv", "text/plain", "text/html", + "text/xml", "application/xml", "application/json", "application/yaml"); + + /** + * Create a new instance. + */ + public CoreContributor() { + } + + @Override + public List
    contributeSectionsForExecution(Context context) { + var sections = new ArrayList
    (); + createInfrastructureSection(context.element()).ifPresent(sections::add); + return sections; + } + + @Override + public List
    contributeSectionsForTestNode(Context context) { + var sections = new ArrayList
    (); + createTagsSection(context.element()).ifPresent(sections::add); + createSourcesSection(context.element()).ifPresent(sections::add); + createReasonSection(context.element()).ifPresent(sections::add); + createAttachmentsSection(context).ifPresent(sections::add); + return sections; + } + + private static Optional
    createInfrastructureSection(Element element) { + return findChild(element, Infrastructure.ELEMENT) // + .map(infrastructure -> { + var table = new LinkedHashMap(); + addToTable(infrastructure, HostName.ELEMENT, "Hostname", table::put); + addToTable(infrastructure, UserName.ELEMENT, "Username", table::put); + addToTable(infrastructure, OperatingSystem.ELEMENT, "Operating system", table::put); + addToTable(infrastructure, CpuCores.ELEMENT, "CPU cores", table::put); + return table.isEmpty() ? null : table; + }) // + .map(table -> { + var keyValuePairs = KeyValuePairs.builder().content(table).build(); + return Section.builder().title("Infrastructure").addBlock(keyValuePairs).build(); + }); + } + + private static Optional
    createTagsSection(Element element) { + return findChild(element, Metadata.ELEMENT) // + .flatMap(metadata -> findChild(metadata, Tags.ELEMENT)) // + .map(tags -> findChildren(tags, Tag.ELEMENT)) // + .map(tags -> tags.map(Node::getTextContent).sorted().toList()) // + .filter(sortedTags -> !sortedTags.isEmpty()) // + .map(sortedTags -> Labels.builder().content(sortedTags).build()) // + .map(labels -> Section.builder().title("Tags").order(0).addBlock(labels).build()); + } + + private static Optional
    createSourcesSection(Element element) { + var children = findChild(element, Sources.ELEMENT) // + .map(DomUtils::children) // + .orElseGet(Stream::empty) // + .filter(Element.class::isInstance) // + .toList(); + + if (children.isEmpty()) { + return Optional.empty(); + } + var subsections = Subsections.builder(); + children.stream().map(child -> { + var type = child.getLocalName(); + if (child.getLocalName().endsWith("Source")) { + type = child.getLocalName().substring(0, child.getLocalName().length() - "Source".length()); + } + var subsection = Section.builder().title(capitalize(type)); + + var attributes = KeyValuePairs.builder(); + stream(child.getAttributes()) // + .filter(it -> it.getNodeValue() != null && !it.getNodeValue().isEmpty()) // + .forEach(it -> attributes.putContent(prettifyCamelCaseName(it.getNodeName()), it.getNodeValue())); + + findChild(child, FilePosition.ELEMENT).ifPresent(filePosition -> { + addToTable(getAttribute(filePosition, FilePosition.LINE), "line", attributes::putContent); + addToTable(getAttribute(filePosition, FilePosition.COLUMN), "column", attributes::putContent); + }); + + subsection.addBlock(attributes.build()); + return subsection.build(); + }).forEach(subsections::addContent); + + return Optional.of(Section.builder().title("Sources").order(10).addBlock(subsections.build()).build()); + } + + private static Optional
    createReasonSection(Element element) { + return findChild(element, Result.ELEMENT) // + .flatMap(result -> findChild(result, Reason.ELEMENT)) // + .map(Node::getTextContent) // + .map(reason -> { + var paragraph = Paragraph.builder().content(reason).build(); + return Section.builder().title("Reason").order(20).addBlock(paragraph).build(); + }); + } + + private static Optional
    createAttachmentsSection(Context context) { + var children = findChild(context.element(), Attachments.ELEMENT) // + .map(DomUtils::children) // + .orElseGet(Stream::empty) // + .filter(Element.class::isInstance) // + .toList(); + if (children.isEmpty()) { + return Optional.empty(); + } + + var subsections = Subsections.builder(); + children.stream().map(child -> { + var type = child.getLocalName(); + var section = Section.builder().title(capitalize(type)); + if (matches(File.ELEMENT, child)) { + addFileAttachment(context, child, section); + } + else if (matches(Data.ELEMENT, child)) { + addDataAttachment(child, section); + } + else if (matches(Output.ELEMENT, child)) { + addOutputAttachment(child, section); + } + return section.build(); + }).forEach(subsections::addContent); + + return Optional.of(Section.builder().title("Attachments").order(30).addBlock(subsections.build()).build()); + } + + private static void addFileAttachment(Context context, Node child, Section.Builder section) { + var attributes = KeyValuePairs.builder(); + getAttributeValue(child, File.TIME).ifPresent(section::metaInfo); + var mediaType = getAttributeValue(child, File.MEDIA_TYPE); + getAttributeValue(child, File.PATH).ifPresent(rawPath -> { + var pathWithNormalizedSeparators = rawPath.replace('\\', '/'); + var originalPath = context.sourceXmlFile().getParent().resolve( + pathWithNormalizedSeparators).toAbsolutePath(); + var path = context.relativizeToTargetDirectory(originalPath); + var filename = path.getFileName().toString(); + filename = filename.substring(Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\')) + 1); + attributes.putContent("Filename", filename); + attributes.putContent("Path", "link:" + path); + if (Files.isRegularFile(originalPath)) { + var resolvedMediaType = mediaType.or(() -> { + try { + return Optional.ofNullable(Files.probeContentType(path)); + } + catch (IOException e) { + return Optional.empty(); + } + }).orElse(null); + if (resolvedMediaType != null) { + addInlineFileBlock(section, resolvedMediaType, path, filename, originalPath); + } + } + }); + mediaType.ifPresent(it -> attributes.putContent("Media type", it)); + section.addBlock(attributes.build()); + } + + private static void addInlineFileBlock(Section.Builder section, String resolvedMediaType, Path path, + String filename, Path originalPath) { + if (SUPPORTED_IMAGE_MEDIA_TYPES.contains(resolvedMediaType)) { + section.addBlock(Image.builder().content(path.toString()).altText(filename).build()); + } + else if (SUPPORTED_TEXT_MEDIA_TYPES.stream().anyMatch(resolvedMediaType::startsWith)) { + try { + var charset = parseCharset(resolvedMediaType); + var content = Files.readString(originalPath, charset); + section.addBlock(PreFormattedOutput.builder().content(content).build()); + } + catch (IOException ignore) { + } + } + } + + private static void addDataAttachment(Node child, Section.Builder section) { + var attributes = KeyValuePairs.builder(); + getAttributeValue(child, Data.TIME).ifPresent(section::metaInfo); + findChildren(child, Data.Entry.ELEMENT).forEach(entry -> { + getAttributeValue(entry, Data.Entry.KEY).ifPresent(key -> { + var value = entry.getTextContent(); + attributes.putContent(key, value); + }); + }); + section.addBlock(attributes.build()); + } + + private static void addOutputAttachment(Node child, Section.Builder section) { + getAttributeValue(child, Output.SOURCE) // + .map(source -> switch (source) { + case "stdout" -> "Standard output"; + case "stderr" -> "Standard error"; + default -> "%s (%s)".formatted("Output", source); + }) // + .ifPresent(section::title); + getAttributeValue(child, Output.TIME).ifPresent(section::metaInfo); + section.addBlock(PreFormattedOutput.builder().content(child.getTextContent()).build()); + } + + private static Charset parseCharset(String resolvedMediaType) { + var mediaTypeParts = resolvedMediaType.split(";"); + for (var part : mediaTypeParts) { + if (part.trim().startsWith("charset=")) { + var charsetName = part.trim().substring("charset=".length()).trim(); + if (charsetName.startsWith("\"") && charsetName.endsWith("\"")) { + charsetName = charsetName.substring(1, charsetName.length() - 1); + } + return Charset.forName(charsetName); + } + } + return Charset.defaultCharset(); + } + + private static String prettifyCamelCaseName(String value) { + var matcher = CAMEL_CASE_WORD_BOUNDARY_PATTERN.matcher(value); + while (matcher.find()) { + value = matcher.replaceFirst(matcher.group(1) + " " + matcher.group(2).toLowerCase(Locale.ROOT)); + matcher = CAMEL_CASE_WORD_BOUNDARY_PATTERN.matcher(value); + } + return capitalize(value); + } + + static void addToTable(Node parent, QualifiedName elementName, String label, BiConsumer table) { + addToTable(findChild(parent, elementName), label, table); + } + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + static void addToTable(Optional node, String label, BiConsumer table) { + node // + .map(Node::getTextContent) // + .ifPresent(value -> table.accept(label, value)); + } + + private static String capitalize(String value) { + return value.substring(0, 1).toUpperCase(Locale.ROOT) + value.substring(1); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriter.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,330 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializer; +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.core.Result; +import org.opentest4j.reporting.events.root.Events; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; +import org.opentest4j.reporting.tooling.core.converter.DefaultConverter; +import org.opentest4j.reporting.tooling.spi.htmlreport.Block; +import org.opentest4j.reporting.tooling.spi.htmlreport.Contributor; +import org.opentest4j.reporting.tooling.spi.htmlreport.Image; +import org.opentest4j.reporting.tooling.spi.htmlreport.KeyValuePairs; +import org.opentest4j.reporting.tooling.spi.htmlreport.Labels; +import org.opentest4j.reporting.tooling.spi.htmlreport.Paragraph; +import org.opentest4j.reporting.tooling.spi.htmlreport.PreFormattedOutput; +import org.opentest4j.reporting.tooling.spi.htmlreport.Section; +import org.opentest4j.reporting.tooling.spi.htmlreport.Subsections; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static java.util.Comparator.comparing; +import static java.util.Objects.requireNonNull; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.children; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.matches; + +/** + * Default implementation of {@link HtmlReportWriter}. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public class DefaultHtmlReportWriter implements HtmlReportWriter { + + private static final QualifiedName ROOT_ELEMENT = QualifiedName.of(Namespace.REPORTING_HIERARCHY, "root"); + private static final QualifiedName CHILD_ELEMENT = QualifiedName.of(Namespace.REPORTING_HIERARCHY, "child"); + + private static final String PLACEHOLDER_SCRIPT_TAG = ""; + + private final ServiceLoader contributors = ServiceLoader.load(Contributor.class); + + /** + * Create a new instance. + */ + public DefaultHtmlReportWriter() { + } + + @Override + public void writeHtmlReport(List xmlFiles, Path htmlFile) throws Exception { + var executions = extractData(xmlFiles, htmlFile); + + try (var template = new Scanner(openTemplate()); var out = Files.newBufferedWriter(htmlFile)) { + while (template.hasNextLine()) { + var line = template.nextLine(); + var placeHolderIndex = line.indexOf(PLACEHOLDER_SCRIPT_TAG); + if (placeHolderIndex >= 0) { + var indent = " ".repeat(placeHolderIndex); + appendScriptTag(executions, indent, out); + } + else { + out.write(line); + out.newLine(); + } + } + } + } + + private List extractData(List xmlFiles, Path htmlFile) throws Exception { + var idGenerator = new IdGenerator(); + var executions = new ArrayList(); + + for (Path xmlFile : xmlFiles) { + var rootElement = parseDom(xmlFile); + var name = String.format(tryRelativize(htmlFile, xmlFile).toString()); + executions.add( + extractData(idGenerator, rootElement, name, element -> new DefaultContext(element, xmlFile, htmlFile))); + } + return executions; + } + + static Path tryRelativize(Path htmlFile, Path file) { + try { + var parent = htmlFile.toAbsolutePath().getParent(); + if (parent == null) { + return file; + } + return parent.relativize(file.toAbsolutePath()); + } + catch (IllegalArgumentException e) { + return file; + } + } + + private static void appendScriptTag(List executions, String indent, BufferedWriter out) + throws IOException { + out.append(indent).append(""); + out.newLine(); + } + + private static void appendJavaScript(List executions, Appendable out) throws IOException { + var gson = new GsonBuilder() // + .registerTypeHierarchyAdapter(Section.class, + (JsonSerializer
    ) (section, typeOfSrc, context) -> { + var jsonObject = new JsonObject(); + jsonObject.addProperty("title", section.getTitle()); + section.getMetaInfo().ifPresent(metaInfo -> jsonObject.addProperty("metaInfo", metaInfo)); + jsonObject.add("blocks", context.serialize(section.getBlocks())); + return jsonObject; + }) // + .registerTypeHierarchyAdapter(KeyValuePairs.class, blockSerializer("kvp")) // + .registerTypeHierarchyAdapter(Labels.class, blockSerializer("labels")) // + .registerTypeHierarchyAdapter(Paragraph.class, blockSerializer("p")) // + .registerTypeHierarchyAdapter(PreFormattedOutput.class, blockSerializer("pre")) // + .registerTypeHierarchyAdapter(Subsections.class, blockSerializer("sub")) // + .registerTypeHierarchyAdapter(Image.class, blockSerializer("img", + (Image image, JsonObject json) -> json.addProperty("altText", image.getAltText()))) // + .disableJdkUnsafe() // + .create(); + + out.append("globalThis.testExecutions = "); + gson.toJson(executions, out); + out.append(";"); + } + + private static > JsonSerializer blockSerializer(String type) { + return blockSerializer(type, (__, ___) -> { + }); + } + + private static > JsonSerializer blockSerializer(String type, + BiConsumer additionalElementSerializer) { + return (block, typeOfSrc, context) -> { + var jsonObject = new JsonObject(); + jsonObject.addProperty("type", type); + jsonObject.add("content", context.serialize(block.getContent())); + additionalElementSerializer.accept(block, jsonObject); + return jsonObject; + }; + } + + private Execution extractData(IdGenerator idGenerator, Element rootElement, String name, + Function contextCreator) { + var execution = new Execution(idGenerator.next(), name); + addSections(contextCreator.apply(rootElement), execution); + + for (Node child = rootElement.getFirstChild(); child != null; child = child.getNextSibling()) { + if (matches(ROOT_ELEMENT, child)) { + var root = visitNode((Element) child, idGenerator, new ArrayDeque<>(), execution, contextCreator); + execution.durationMillis += root.durationMillis; + execution.roots.add(root.id); + } + } + return execution; + } + + private TestNode visitNode(Element node, IdGenerator idGenerator, Deque parentIds, Execution execution, + Function contextCreator) { + String currentId = idGenerator.next(); + + String status = children(node) // + .filter(it -> matches(Result.ELEMENT, it)) // + .findAny() // + .map(it -> ((Element) it).getAttribute(Result.STATUS.getSimpleName())).orElse(null); + + var duration = Duration.parse(node.getAttribute("duration")); + var testNode = new TestNode(currentId, node.getAttribute("name"), duration.toMillis(), status); + execution.testNodes.add(testNode); + + addSections(contextCreator.apply(node), testNode); + + ChildMetadata parentChildMetadata = null; + if (!parentIds.isEmpty()) { + String parentId = parentIds.peek(); + parentChildMetadata = execution.children.computeIfAbsent(parentId, __ -> new ChildMetadata()); + parentChildMetadata.addChild(currentId, status); + } + parentIds.push(currentId); + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (matches(CHILD_ELEMENT, child)) { + visitNode((Element) child, idGenerator, parentIds, execution, contextCreator); + } + } + parentIds.pop(); + ChildMetadata currentNodeChildMetadata = execution.children.get(currentId); + if (currentNodeChildMetadata != null && parentChildMetadata != null) { + parentChildMetadata.childStatuses.addAll(currentNodeChildMetadata.childStatuses); + } + + return testNode; + } + + private void addSections(Contributor.Context context, Execution execution) { + contributeSections(context, Contributor::contributeSectionsForExecution, execution.sections); + } + + private void addSections(Contributor.Context context, TestNode node) { + contributeSections(context, Contributor::contributeSectionsForTestNode, node.sections); + } + + private void contributeSections(Contributor.Context context, + BiFunction> call, List
    sections) { + contributors.stream() // + .flatMap(it -> call.apply(it.get(), context).stream()).sorted(comparing(Section::getOrder)) // + .forEach(sections::add); + } + + static class IdGenerator { + private int nextId = 1; + + String next() { + return Integer.toString(nextId++); + } + } + + private static Element parseDom(Path xmlFile) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + + Document sourceDocument = builder.parse(xmlFile.toFile()); + Element element = sourceDocument.getDocumentElement(); + + if (matches(Events.ELEMENT, element)) { + return new DefaultConverter().convert(element).getDocumentElement(); + } + + return element; + } + + private InputStream openTemplate() { + return requireNonNull(getClass().getResourceAsStream("template.html")); + } + + private static class Execution { + + public final String id; + public final String name; + public long durationMillis; + + public final List
    sections = new ArrayList<>(); + + public final List roots = new ArrayList<>(); + public final Map children = new LinkedHashMap<>(); + public final List testNodes = new ArrayList<>(); + + Execution(String id, String name) { + this.id = id; + this.name = name; + } + } + + private record ChildMetadata(List ids, Set childStatuses) { + + ChildMetadata() { + this(new ArrayList<>(), new HashSet<>()); + } + + private void addChild(String childId, String status) { + ids.add(childId); + if (status != null) { + childStatuses.add(status); + } + } + } + + private record TestNode(String id, String name, long durationMillis, String status, List
    sections) { + + TestNode(String id, String name, long durationMillis, String status) { + this(id, name, durationMillis, status, new ArrayList<>()); + } + } + + private record DefaultContext(Element element, Path sourceXmlFile, Path targetHtmlFile) + implements Contributor.Context { + + @Override + public Path relativizeToTargetDirectory(Path path) { + return tryRelativize(targetHtmlFile, path); + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/GitContributor.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/GitContributor.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/GitContributor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/GitContributor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.events.git.Branch; +import org.opentest4j.reporting.events.git.Commit; +import org.opentest4j.reporting.events.git.Repository; +import org.opentest4j.reporting.events.git.Status; +import org.opentest4j.reporting.tooling.spi.htmlreport.Contributor; +import org.opentest4j.reporting.tooling.spi.htmlreport.KeyValuePairs; +import org.opentest4j.reporting.tooling.spi.htmlreport.PreFormattedOutput; +import org.opentest4j.reporting.tooling.spi.htmlreport.Section; +import org.opentest4j.reporting.tooling.spi.htmlreport.Subsections; +import org.w3c.dom.Node; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.opentest4j.reporting.tooling.core.htmlreport.CoreContributor.addToTable; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.findChild; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.getAttribute; + +/** + * Contributes sections to the HTML report elements in the git schema. + * + * @since 0.2.0 + */ +@API(status = INTERNAL, since = "0.2.0") +public class GitContributor implements Contributor { + + /** + * Create a new instance. + */ + public GitContributor() { + } + + @Override + public List
    contributeSectionsForExecution(Context context) { + var sections = new ArrayList
    (); + findChild(context.element(), Infrastructure.ELEMENT) // + .flatMap(GitContributor::createGitSection) // + .ifPresent(sections::add); + return sections; + } + + private static Optional
    createGitSection(Node infrastructure) { + + var table = KeyValuePairs.builder(); + + findChild(infrastructure, Repository.ELEMENT) // + .ifPresent(repository -> addToTable(getAttribute(repository, Repository.ORIGIN_URL), "Origin", + table::putContent)); + + addToTable(infrastructure, Branch.ELEMENT, "Branch", table::putContent); + addToTable(infrastructure, Commit.ELEMENT, "Commit hash", table::putContent); + + var status = findChild(infrastructure, Status.ELEMENT); + status.ifPresent(it -> addToTable(getAttribute(it, Status.CLEAN), "Clean", table::putContent)); + var statusBlock = status.map(Node::getTextContent) // + .filter(it -> !it.isBlank()) // + .map(statusText -> { + var codeBlock = PreFormattedOutput.builder().content(statusText).build(); + var statusSubsection = Section.builder().title("Status of working tree").addBlock( + codeBlock).build(); + return Subsections.builder().addContent(statusSubsection).build(); + }); + + var sectionBuilder = Section.builder().title("Git").order(15); + + var keyValuePairs = table.build(); + if (!keyValuePairs.getContent().isEmpty()) { + sectionBuilder.addBlock(keyValuePairs); + } + + statusBlock.ifPresent(sectionBuilder::addBlock); + + var section = sectionBuilder.build(); + + return section.getBlocks().isEmpty() ? Optional.empty() : Optional.of(section); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/HtmlReportWriter.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/HtmlReportWriter.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/HtmlReportWriter.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/HtmlReportWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import org.apiguardian.api.API; + +import java.nio.file.Path; +import java.util.List; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Writer of HTML reports for event-based and hierarchical XML report files. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface HtmlReportWriter { + + /** + * Write an HTML report for the supplied XML files. + * + *

    The supplied XML files may be in the event-based or hierarchical format. + * + * @param xmlFiles XML files in event-based or hierarchical format + * @param htmlFile the target HTML file + * @throws Exception if an error occurs during creation of the HTML report + */ + void writeHtmlReport(List xmlFiles, Path htmlFile) throws Exception; + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/JavaContributor.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/JavaContributor.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/JavaContributor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/htmlreport/JavaContributor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,124 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.events.core.Infrastructure; +import org.opentest4j.reporting.events.core.Result; +import org.opentest4j.reporting.events.java.FileEncoding; +import org.opentest4j.reporting.events.java.HeapSize; +import org.opentest4j.reporting.events.java.JavaVersion; +import org.opentest4j.reporting.events.java.Throwable; +import org.opentest4j.reporting.tooling.spi.htmlreport.Contributor; +import org.opentest4j.reporting.tooling.spi.htmlreport.KeyValuePairs; +import org.opentest4j.reporting.tooling.spi.htmlreport.PreFormattedOutput; +import org.opentest4j.reporting.tooling.spi.htmlreport.Section; +import org.opentest4j.reporting.tooling.spi.htmlreport.Subsections; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Optional; + +import static org.apiguardian.api.API.Status.INTERNAL; +import static org.opentest4j.reporting.tooling.core.htmlreport.CoreContributor.addToTable; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.findChild; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.findChildren; +import static org.opentest4j.reporting.tooling.core.util.DomUtils.getAttributeValue; + +/** + * Contributes sections to the HTML report elements in the java schema. + * + * @since 0.2.0 + */ +@API(status = INTERNAL, since = "0.2.0") +public class JavaContributor implements Contributor { + + /** + * Create a new instance. + */ + public JavaContributor() { + } + + @Override + public List

    contributeSectionsForExecution(Context context) { + var sections = new ArrayList
    (); + findChild(context.element(), Infrastructure.ELEMENT) // + .flatMap(JavaContributor::createJvmSection) // + .ifPresent(sections::add); + return sections; + } + + @Override + public List
    contributeSectionsForTestNode(Context context) { + var sections = new ArrayList
    (); + createResultSection(context.element()).ifPresent(sections::add); + return sections; + } + + private static Optional
    createJvmSection(Node infrastructure) { + var table = new LinkedHashMap(); + addToTable(infrastructure, JavaVersion.ELEMENT, "Java version", table::put); + addToTable(infrastructure, FileEncoding.ELEMENT, "File encoding", table::put); + findChild(infrastructure, HeapSize.ELEMENT) // + .flatMap(heapSize -> getAttributeValue(heapSize, HeapSize.MAX)) // + .map(maxHeapSize -> String.format("%s (%s bytes)", toHumanReadableFormat(Long.parseLong(maxHeapSize)), + maxHeapSize)) // + .ifPresent(maxHeapSize -> table.put("Max heap size", maxHeapSize)); + + if (table.isEmpty()) { + return Optional.empty(); + } + + var keyValuePairs = KeyValuePairs.builder().content(table).build(); + return Optional.of(Section.builder().title("Java Virtual Machine").order(10).addBlock(keyValuePairs).build()); + } + + private static Optional
    createResultSection(Element element) { + return findChild(element, Result.ELEMENT) // + .map(result -> findChildren(result, Throwable.ELEMENT) // + .map(throwable -> { + var type = getAttributeValue(throwable, Throwable.TYPE).orElse("Throwable"); + var stackTrace = throwable.getTextContent(); + var preFormattedOutput = PreFormattedOutput.builder().content(stackTrace).build(); + return Section.builder().title(type).addBlock(preFormattedOutput).build(); + }) // + .toList() // + ) // + .filter(content -> !content.isEmpty()) // + .map(content -> Subsections.builder().content(content).build()) // + .map(subsections -> Section.builder().title("Result").order(25).addBlock(subsections).build()); + } + + // Adapted from https://www.baeldung.com/java-human-readable-byte-size#using-the-longnumberofleadingzeros-method + private static String toHumanReadableFormat(long size) { + if (size < 1024) + return size + " B"; + int unitIdx = (63 - Long.numberOfLeadingZeros(size)) / 10; + return formatSize(size, 1L << (unitIdx * 10), " KMGTPE".charAt(unitIdx) + "iB"); + } + + private static String formatSize(long size, long divider, String unitName) { + return new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.US)).format((double) size / divider) + " " + + unitName; + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/util/DomUtils.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/util/DomUtils.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/util/DomUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/util/DomUtils.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,262 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.util; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.Arrays; +import java.util.Optional; +import java.util.function.IntFunction; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static org.apiguardian.api.API.Status.INTERNAL; + +/** + * Internal utils to work with DOM types + * + * @since 0.2.0 + */ +@API(status = INTERNAL, since = "0.2.0") +public class DomUtils { + + private static final Pattern NAMESPACE_VERSION_PATTERN = Pattern.compile("^(.+)/([0-9.]+)$"); + + private DomUtils() { + } + + /** + * Find the first child of the supplied parent node with the supplied element name. + * + * @param parent the parent node + * @param elementName the element name to find + * @return the first child node with the supplied element name + */ + public static Optional findChild(Node parent, QualifiedName elementName) { + return children(parent) // + .filter(child -> DomUtils.matches(elementName, child)) // + .findFirst(); + } + + /** + * Find the children of the supplied parent node with the supplied element name. + * + * @param parent the parent node + * @param elementName the element name to find + * @return the children nodes with the supplied element name + */ + public static Stream findChildren(Node parent, QualifiedName elementName) { + return children(parent) // + .filter(child -> DomUtils.matches(elementName, child)); + } + + /** + * Stream the children of the supplied node. + * + * @param parent the parent node + * @return a stream of the children of the node + */ + public static Stream children(Node parent) { + return stream(parent.getChildNodes()); + } + + /** + * Get the value of the attribute with the supplied element name of the supplied node. + * + * @param node the node + * @param elementName the element name of the attribute + * @return the value of the attribute + */ + public static Optional getAttributeValue(Node node, QualifiedName elementName) { + return getAttribute(node, elementName).map(Node::getNodeValue); + } + + /** + * Get the attribute with the supplied element name of the supplied node. + * + * @param node the node + * @param elementName the element name of the attribute + * @return the attribute + */ + public static Optional getAttribute(Node node, QualifiedName elementName) { + var attributes = node.getAttributes(); + var namespaceURI = elementName.getNamespace().getUri(); + var simpleName = elementName.getSimpleName(); + return Optional.ofNullable(attributes.getNamedItemNS(namespaceURI, simpleName)) // + .or(() -> Optional.ofNullable(attributes.getNamedItem(simpleName))); + } + + /** + * Stream the nodes of the supplied node list. + * + * @param nodeList the node list to stream + * @return a stream of the nodes in the node list + */ + public static Stream stream(NodeList nodeList) { + return stream(nodeList.getLength(), nodeList::item); + } + + /** + * Stream the nodes of the supplied named node map. + * + * @param namedNodeMap the named node map to stream + * @return a stream of the nodes in the named node map + */ + public static Stream stream(NamedNodeMap namedNodeMap) { + return stream(namedNodeMap.getLength(), namedNodeMap::item); + } + + private static Stream stream(int length, IntFunction item) { + return IntStream.range(0, length).mapToObj(item); + } + + /** + * Check whether the simple name of the supplied node matches the + * supplied qualified name and the namespace of the node is compatible + * with the namespace of the qualified name (same base URI and version less + * than or equal to the version of the qualified name). + * + * @param qualifiedName the qualified name to match + * @param node the node to check + * @return {@code true} if the node matches the qualified name + */ + public static boolean matches(QualifiedName qualifiedName, Node node) { + return isNamespaceCompatible(qualifiedName, node) && qualifiedName.getSimpleName().equals(node.getLocalName()); + } + + private static boolean isNamespaceCompatible(QualifiedName qualifiedName, Node node) { + return qualifiedName.getNamespace().getUri().equals(node.getNamespaceURI()) // + || parseNamespace(qualifiedName.getNamespace().getUri()) // + .flatMap(expected -> parseNamespace(node.getNamespaceURI()).filter(expected::isCompatible)) // + .isPresent(); + } + + /** + * Parse the supplied namespace URI into a base URI and a version. + * + * @param namespaceUri the namespace URI to parse + * @return the versioned namespace + */ + public static Optional parseNamespace(String namespaceUri) { + return Optional.ofNullable(namespaceUri) // + .map(NAMESPACE_VERSION_PATTERN::matcher) // + .filter(Matcher::matches) // + .map(it -> new VersionedNamespace(it.group(1), NamespaceVersion.parse(it.group(2)))); + } + + /** + * A namespace base URI and version. + */ + public static class VersionedNamespace { + + private final String baseUri; + private final NamespaceVersion version; + + VersionedNamespace(String baseUri, NamespaceVersion version) { + this.baseUri = baseUri; + this.version = version; + } + + /** + * {@return the base URI} + */ + public String getBaseUri() { + return baseUri; + } + + /** + * {@return the version} + */ + public NamespaceVersion getVersion() { + return version; + } + + boolean isCompatible(VersionedNamespace that) { + return this.getBaseUri().equals(that.getBaseUri()) // + && that.getVersion().compareTo(this.getVersion()) <= 0; + } + + /** + * Create a new versioned namespace with the supplied version. + * + * @param version the version + * @return the new versioned namespace + */ + public VersionedNamespace withVersion(NamespaceVersion version) { + return new VersionedNamespace(getBaseUri(), version); + } + + /** + * Convert this versioned namespace to a namespace. + * + * @return the namespace + */ + public Namespace toNamespace() { + return Namespace.of(getBaseUri() + "/" + getVersion()); + } + } + + /** + * Represents a namespace version. + */ + public static class NamespaceVersion implements Comparable { + + /** + * Parse the supplied version string. + * + * @param version the version string to parse + * @return the parsed version + */ + public static NamespaceVersion parse(String version) { + var parts = Arrays.stream(version.split("\\.")) // + .mapToInt(Integer::parseInt) // + .toArray(); + return new NamespaceVersion(version, parts); + } + + private final String stringValue; + private final int[] parts; + + NamespaceVersion(String stringValue, int[] parts) { + this.stringValue = stringValue; + this.parts = parts; + } + + @Override + public int compareTo(NamespaceVersion that) { + for (int i = 0; i < Math.min(this.parts.length, that.parts.length); i++) { + int comparison = Integer.compare(this.parts[i], that.parts[i]); + if (comparison != 0) { + return comparison; + } + } + return Integer.compare(this.parts.length, that.parts.length); + } + + @Override + public String toString() { + return stringValue; + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidator.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidator.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,255 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.validator; + +import org.apiguardian.api.API; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.Schemas; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.xml.catalog.CatalogFeatures; +import javax.xml.catalog.CatalogFeatures.Feature; +import javax.xml.catalog.CatalogResolver; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.SchemaFactory; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Objects.requireNonNull; +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.catalog.CatalogManager.catalogResolver; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.opentest4j.reporting.tooling.core.validator.Severity.ERROR; +import static org.opentest4j.reporting.tooling.core.validator.Severity.WARNING; + +/** + * Default implementation of {@link Validator}. + * + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public class DefaultValidator implements Validator { + + private final SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + private final CatalogResolver catalogResolver; + + /** + * Create a new instance. + * + * @param catalogs for resolving references to XML schemas + */ + public DefaultValidator(URI... catalogs) { + var features = CatalogFeatures.builder().with(Feature.RESOLVE, "continue").build(); + this.catalogResolver = catalogResolver(features, catalogs); + } + + @Override + public ValidationResult validate(Path xmlFile) { + try (var in = Files.newInputStream(xmlFile)) { + return validateSafely(xmlFile, new StreamSource(in)); + } + catch (Exception e) { + throw new RuntimeException("Failure during validation: " + xmlFile, e); + } + } + + private ValidationResult validateSafely(Path xmlFile, Source source) throws SAXException, IOException { + var errorHandler = new CollectingErrorHandler(xmlFile); + validate(source, errorHandler); + return errorHandler.toValidationResult(); + } + + private void validate(Source source, ErrorHandler errorHandler) throws SAXException, IOException { + var validator = schemaFactory.newSchema().newValidator(); + validator.setResourceResolver(createResourceResolver()); + validator.setErrorHandler(errorHandler); + validator.validate(source); + } + + private LSResourceResolver createResourceResolver() { + return (type, namespaceURI, publicId, systemId, baseURI) -> { + if (namespaceURI != null) { + var namespace = Namespace.of(namespaceURI); + var schemaLocation = Schemas.getSchemaLocation(namespace); + if (schemaLocation.isPresent()) { + LSInputImpl input = new LSInputImpl(); + input.setPublicId(publicId); + var url = schemaLocation.get(); + input.setSystemId(url.toExternalForm()); + input.setBaseURI(baseURI); + @SuppressWarnings("resource") + var stream = openStream(url); + input.setCharacterStream(new InputStreamReader(requireNonNull(stream))); + return input; + } + } + if (systemId != null) { + return catalogResolver.resolveResource(type, namespaceURI, publicId, systemId, baseURI); + } + return null; + }; + } + + private static InputStream openStream(URL url) { + try { + return url.openStream(); + } + catch (IOException e) { + throw new UncheckedIOException("Failed to read resource from " + url, e); + } + } + + static class LSInputImpl implements LSInput { + + private Reader characterStream; + private InputStream byteStream; + private String stringData; + private String systemId; + private String publicId; + private String baseURI; + private String encoding; + private boolean certifiedText; + + @Override + public Reader getCharacterStream() { + return characterStream; + } + + @Override + public void setCharacterStream(Reader characterStream) { + this.characterStream = characterStream; + } + + @Override + public InputStream getByteStream() { + return byteStream; + } + + @Override + public void setByteStream(InputStream byteStream) { + this.byteStream = byteStream; + } + + @Override + public String getStringData() { + return stringData; + } + + @Override + public void setStringData(String stringData) { + this.stringData = stringData; + } + + @Override + public String getSystemId() { + return systemId; + } + + @Override + public void setSystemId(String systemId) { + this.systemId = systemId; + } + + @Override + public String getPublicId() { + return publicId; + } + + @Override + public void setPublicId(String publicId) { + this.publicId = publicId; + } + + @Override + public String getBaseURI() { + return baseURI; + } + + @Override + public void setBaseURI(String baseURI) { + this.baseURI = baseURI; + } + + @Override + public String getEncoding() { + return encoding; + } + + @Override + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + @Override + public boolean getCertifiedText() { + return certifiedText; + } + + @Override + public void setCertifiedText(boolean certifiedText) { + this.certifiedText = certifiedText; + } + } + + private static class CollectingErrorHandler implements ErrorHandler { + private final Path xmlFile; + private final List messages = new ArrayList<>(); + + public CollectingErrorHandler(Path xmlFile) { + this.xmlFile = xmlFile; + } + + @Override + public void warning(SAXParseException e) { + addValidationMessage(WARNING, e); + } + + @Override + public void error(SAXParseException e) { + addValidationMessage(ERROR, e); + } + + private void addValidationMessage(Severity severity, SAXParseException e) { + var path = e.getSystemId() == null ? xmlFile.toString() : e.getSystemId(); + var location = new Location(path, e.getLineNumber(), e.getColumnNumber()); + messages.add(new ValidationMessage(severity, location, e.getMessage())); + } + + @Override + public void fatalError(SAXParseException e) throws SAXParseException { + throw e; + } + + public ValidationResult toValidationResult() { + return new ValidationResult(List.copyOf(messages)); + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Location.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Location.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Location.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Location.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.validator; + +import org.apiguardian.api.API; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Location of a {@linkplain ValidationMessage validation message}. + * + * @param path the path of the file + * @param lineNumber the line number + * @param column the column number + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public record Location(String path, int lineNumber, int column) { + @Override + public String toString() { + return String.format("%s:%d:%d", path, lineNumber, column); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Severity.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Severity.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Severity.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Severity.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.validator; + +import org.apiguardian.api.API; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Severity of a {@linkplain ValidationMessage validation message}. + * + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public enum Severity { + + /** + * A warning. + */ + WARNING, + + /** + * An error. + */ + ERROR +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationMessage.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationMessage.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationMessage.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationMessage.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.validator; + +import org.apiguardian.api.API; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Validation message with severity and location. + * + * @param severity the severity of the message + * @param location the location of the message + * @param message the message + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public record ValidationMessage(Severity severity, Location location, String message) { + @Override + public String toString() { + return String.format("[%s] %s - %s", severity, location, message); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationResult.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationResult.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationResult.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/ValidationResult.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.validator; + +import org.apiguardian.api.API; + +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +import static java.util.stream.Collectors.joining; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Result of validating an XML report file. + * + * @param messages the validation messages + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public record ValidationResult(List messages) implements Iterable { + + /** + * Count the number of validation messages with the supplied severity. + * + * @param severity the severity to count + * @return number of validation messages with the supplied severity + */ + public long count(Severity severity) { + return messages.stream().filter(m -> severity.equals(m.severity())).count(); + } + + @Override + public Iterator iterator() { + return messages.iterator(); + } + + @Override + public String toString() { + return messages.stream() // + .map(Objects::toString) // + .collect(joining("\n")); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Validator.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Validator.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Validator.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/java/org/opentest4j/reporting/tooling/core/validator/Validator.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.validator; + +import org.apiguardian.api.API; + +import java.nio.file.Path; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Validator for event-based and hierarchical XML report files. + * + * @since 0.1.0 + */ +@API(status = EXPERIMENTAL, since = "0.1.0") +public interface Validator { + + /** + * Validate the supplied XML file. + * + * @param xmlFile the XML file to validate + * @return validation result + */ + ValidationResult validate(Path xmlFile); + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/main/resources/META-INF/services/org.opentest4j.reporting.tooling.spi.htmlreport.Contributor 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,3 @@ +org.opentest4j.reporting.tooling.core.htmlreport.CoreContributor +org.opentest4j.reporting.tooling.core.htmlreport.GitContributor +org.opentest4j.reporting.tooling.core.htmlreport.JavaContributor diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/module/java/org.opentest4j.reporting.tooling.core/module-info.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/module/java/org.opentest4j.reporting.tooling.core/module-info.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/module/java/org.opentest4j.reporting.tooling.core/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/module/java/org.opentest4j.reporting.tooling.core/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Java API for validating both formats, converting from the event-based to the + * hierarchical format (suitable for inclusion in build tools and reporting + * tools), and generating HTML reports + * + * @since 0.2.0 + */ +module org.opentest4j.reporting.tooling.core { + + requires static org.apiguardian.api; + requires com.google.gson; + requires org.opentest4j.reporting.events; + requires org.opentest4j.reporting.tooling.spi; + + exports org.opentest4j.reporting.tooling.core.converter; + exports org.opentest4j.reporting.tooling.core.htmlreport; + exports org.opentest4j.reporting.tooling.core.validator; + + uses org.opentest4j.reporting.tooling.spi.htmlreport.Contributor; + + provides org.opentest4j.reporting.tooling.spi.htmlreport.Contributor with + org.opentest4j.reporting.tooling.core.htmlreport.CoreContributor, + org.opentest4j.reporting.tooling.core.htmlreport.GitContributor, + org.opentest4j.reporting.tooling.core.htmlreport.JavaContributor; + + opens org.opentest4j.reporting.tooling.core.htmlreport to com.google.gson; +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverterTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverterTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverterTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/converter/DefaultConverterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,184 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.converter; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.opentest4j.reporting.events.api.DocumentWriter; +import org.opentest4j.reporting.events.api.NamespaceRegistry; +import org.opentest4j.reporting.events.root.Events; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.tooling.core.util.DomUtils; +import org.opentest4j.reporting.tooling.core.util.DomUtils.NamespaceVersion; +import org.xmlunit.assertj3.XmlAssert; +import org.xmlunit.builder.Input; +import org.xmlunit.util.Convert; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Consumer; + +import static org.opentest4j.reporting.events.core.CoreFactory.attachments; +import static org.opentest4j.reporting.events.core.CoreFactory.cpuCores; +import static org.opentest4j.reporting.events.core.CoreFactory.data; +import static org.opentest4j.reporting.events.core.CoreFactory.infrastructure; +import static org.opentest4j.reporting.events.core.CoreFactory.metadata; +import static org.opentest4j.reporting.events.core.CoreFactory.result; +import static org.opentest4j.reporting.events.core.CoreFactory.tag; +import static org.opentest4j.reporting.events.core.CoreFactory.tags; +import static org.opentest4j.reporting.events.core.Result.Status.SUCCESSFUL; +import static org.opentest4j.reporting.events.root.RootFactory.finished; +import static org.opentest4j.reporting.events.root.RootFactory.reported; +import static org.opentest4j.reporting.events.root.RootFactory.started; + +class DefaultConverterTests { + + static final NamespaceRegistry NAMESPACE_REGISTRY = NamespaceRegistry.builder(Namespace.REPORTING_CORE) // + .add("e", Namespace.REPORTING_EVENTS) // + .add("java", Namespace.REPORTING_JAVA) // + .build(); + + static final NamespaceVersion CURRENT_VERSION = DomUtils.parseNamespace( + Namespace.REPORTING_HIERARCHY.getUri()).orElseThrow().getVersion(); + + Path sourceFile; + Path targetFile; + + @BeforeEach + void setUp(@TempDir Path tempDir) { + sourceFile = tempDir.resolve("events.xml"); + targetFile = tempDir.resolve("hierarchy.xml"); + } + + @Test + void convertsInfrastructureSection() throws Exception { + writeXml(sourceFile, + writer -> writer.append(infrastructure(), infrastructure -> infrastructure.append(cpuCores(42)))); + + new DefaultConverter().convert(sourceFile, targetFile); + + assertAll(targetFile, CURRENT_VERSION, it -> it.valueByXPath("//*/c:infrastructure/c:cpuCores").isEqualTo(42)); + } + + @Test + void convertsStartedAndFinishedEvents() throws Exception { + var duration = Duration.ofMillis(42); + var startTime = Instant.now().minus(duration); + writeXml(sourceFile, writer -> writer // + .append(started("1", startTime, "container"), started -> started // + .append(metadata(), metadata -> metadata // + .append(tags(), tags -> tags // + .append(tag("a"))))) // + .append(started("2", startTime.plus(duration), "test"), started -> started.withParentId("1")) // + .append(finished("2", startTime.plus(duration.multipliedBy(2)))) // + .append(finished("1", startTime.plus(duration.multipliedBy(3))), finished -> finished // + .append(result(SUCCESSFUL)))); + + new DefaultConverter().convert(sourceFile, targetFile); + + assertAll(targetFile, CURRENT_VERSION, // + it -> it.nodesByXPath("//*/h:root") // + .hasSize(1) // + .haveAttribute("name", "container") // + .haveAttribute("start", startTime.toString()) // + .haveAttribute("duration", duration.multipliedBy(3).toString()), // + it -> it.valueByXPath("//*/h:root/c:metadata/c:tags/c:tag") // + .isEqualTo("a"), // + it -> it.valueByXPath("//*/h:root/c:result/@status") // + .isEqualTo("SUCCESSFUL"), // + it -> it.nodesByXPath("//*/h:root/h:child") // + .hasSize(1) // + .haveAttribute("name", "test") // + .haveAttribute("start", startTime.plus(duration).toString()) // + .haveAttribute("duration", duration.toString()) // + ); + } + + @Test + void mergesReportEntries() throws Exception { + writeXml(sourceFile, writer -> writer.append(started("1", Instant.now(), "test"), started -> started // + .append(attachments(), attachments -> attachments // + .append(data(LocalDateTime.now()), data -> data.addEntry("started", "1")))) // + .append(reported("1", Instant.now()), reported -> reported // + .append(attachments(), attachments -> attachments // + .append(data(LocalDateTime.now()), data -> data.addEntry("reported", "2")))) // + .append(finished("1", Instant.now()), finished -> finished // + .append(attachments(), attachments -> attachments // + .append(data(LocalDateTime.now()), data -> data.addEntry("finished", "3"))))); + + new DefaultConverter().convert(sourceFile, targetFile); + + assertAll(targetFile, CURRENT_VERSION, // + it -> it.nodesByXPath("//*/h:root/c:attachments").hasSize(1), // + it -> it.nodesByXPath("//*/h:root/c:attachments/c:data").hasSize(3), // + it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/@key)[1]").isEqualTo("started"), // + it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/text())[1]").isEqualTo("1"), // + it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/@key)[2]").isEqualTo("reported"), // + it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/text())[2]").isEqualTo("2"), // + it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/@key)[3]").isEqualTo("finished"), // + it -> it.valueByXPath("(//*/h:root/c:attachments/c:data/c:entry/text())[3]").isEqualTo("3") // + ); + } + + @Test + void convertsOldVersions() throws Exception { + Files.writeString(sourceFile, + """ + + + 42 + + + """); + + new DefaultConverter().convert(sourceFile, targetFile); + + assertAll(targetFile, NamespaceVersion.parse("0.1.0"), // + it -> it.nodesByXPath("//h:execution").hasSize(1), // + it -> it.valueByXPath("//*/c:infrastructure/c:cpuCores").isEqualTo(42)); + } + + private void writeXml(Path eventsXmlFile, Consumer> action) throws Exception { + try (var writer = Events.createDocumentWriter(NAMESPACE_REGISTRY, eventsXmlFile)) { + action.accept(writer); + } + } + + @SafeVarargs + @SuppressWarnings("varargs") + private static void assertAll(Path targetFile, NamespaceVersion version, Consumer... checks) { + var document = Convert.toDocument(Input.from(targetFile).build()); + var xmlAssert = XmlAssert.assertThat(document).withNamespaceContext(Map.of( // + "h", toNamespaceUri(Namespace.REPORTING_HIERARCHY, version), // + "c", toNamespaceUri(Namespace.REPORTING_CORE, version) // + )); + Assertions.assertAll(targetFile.toUri().toString(), + Arrays.stream(checks).map(it -> () -> it.accept(xmlAssert))); + } + + private static String toNamespaceUri(Namespace namespace, NamespaceVersion version) { + return DomUtils.parseNamespace(namespace.getUri()).orElseThrow().withVersion(version).toNamespace().getUri(); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterBrowserTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterBrowserTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterBrowserTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterBrowserTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import com.microsoft.playwright.Page; +import com.microsoft.playwright.Page.GetByRoleOptions; +import com.microsoft.playwright.Page.ScreenshotOptions; +import com.microsoft.playwright.junit.UsePlaywright; +import com.microsoft.playwright.options.AriaRole; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MediaType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestReporter; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Path; +import java.util.List; +import java.util.regex.Pattern; + +import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat; +import static java.util.Objects.requireNonNull; +import static org.assertj.core.api.Assertions.assertThat; + +@UsePlaywright +@ExtendWith(PlaywrightTracePublisher.class) +class DefaultHtmlReportWriterBrowserTests { + + @TempDir + static Path tempDir; + static Path sampleHtmlReport; + + @BeforeAll + static void createHtmlReport() throws Exception { + var sampleXmlReport = Path.of(requireNonNull(System.getProperty("sampleXmlReport"))); + assertThat(sampleXmlReport).exists().hasExtension("xml"); + + sampleHtmlReport = tempDir.resolve("open-test-report.html"); + new DefaultHtmlReportWriter().writeHtmlReport(List.of(sampleXmlReport), sampleHtmlReport); + } + + @BeforeEach + void openHtmlReport(Page page) { + page.setViewportSize(1920, 1080); + page.navigate(sampleHtmlReport.toUri().toString()); + assertThat(page).hasTitle(Pattern.compile("Open Test Report")); + } + + @Test + void sampleHtmlReportIsRenderedCorrectly(Page page, TestReporter reporter) { + reporter.publishFile("screenshot-failure.png", MediaType.IMAGE_PNG, + file -> page.screenshot(new ScreenshotOptions().setPath(file))); + + assertThat( + page.getByRole(AriaRole.HEADING, new GetByRoleOptions().setName("failed(TestReporter)"))).isVisible(); + assertThat(page.getByRole(AriaRole.STATUS)).containsText("FAILED"); + + page.getByRole(AriaRole.SWITCH).click(); + page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("KitchenSinkTests").setExact(true)).click(); + + reporter.publishFile("screenshot-success.png", MediaType.IMAGE_PNG, + file -> page.screenshot(new ScreenshotOptions().setPath(file))); + + assertThat(page.getByRole(AriaRole.HEADING, new GetByRoleOptions().setName("KitchenSinkTest"))).isVisible(); + assertThat(page.getByRole(AriaRole.STATUS)).containsText("SUCCESSFUL"); + } + + @Test + void canOpenAttachments(Page page) { + page.navigate(sampleHtmlReport.toUri().toString()); + assertThat(page.getByText("Hellö, Wörld!")).isVisible(); + + page.getByText(Pattern.compile("[/\\\\]test.txt$"), new Page.GetByTextOptions().setExact(false)).click(); + assertThat(page.getByText("Hellö, Wörld!")).isVisible(); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/DefaultHtmlReportWriterTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +class DefaultHtmlReportWriterTests { + + @Test // https://github.com/ota4j-team/open-test-reporting/issues/293 + void canHandleWhitespaceInSources(@TempDir Path tempDir) throws Exception { + @Language("xml") + var xml = """ + + + + + + + + + + + + """; + var xmlFile = Files.writeString(tempDir.resolve("report.xml"), xml); + + var writer = new DefaultHtmlReportWriter(); + assertDoesNotThrow(() -> writer.writeHtmlReport(List.of(xmlFile), tempDir.resolve("report.html"))); + } + + @Test // https://github.com/ota4j-team/open-test-reporting/issues/294 + void canHandleWhitespaceInAttachments(@TempDir Path tempDir) throws Exception { + @Language("xml") + var xml = """ + + + + + + someOutput + + + + + + + """; + var xmlFile = Files.writeString(tempDir.resolve("report.xml"), xml); + + var writer = new DefaultHtmlReportWriter(); + assertDoesNotThrow(() -> writer.writeHtmlReport(List.of(xmlFile), tempDir.resolve("report.html"))); + } + + @Test + void handlesRelativePath() { + var xmlFile = Path.of("junit-platform-events-8096972057150721349.xml"); + var relativePath = DefaultHtmlReportWriter.tryRelativize(Path.of("open-test-report.html"), xmlFile); + assertThat(relativePath).isEqualTo(xmlFile); + } + + @Test + void avoidsHtmlInclusionProblems(@TempDir Path tempDir) throws Exception { + @Language("xml") + var xml = """ + + + + + + + + """; + var xmlFile = Files.writeString(tempDir.resolve("report.xml"), xml); + var htmlFile = tempDir.resolve("report.html"); + + var writer = new DefaultHtmlReportWriter(); + writer.writeHtmlReport(List.of(xmlFile), htmlFile); + + assertThat(Files.readString(htmlFile)).contains("\"name\":\"\\u003c/script\\u003e\""); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/PlaywrightTracePublisher.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/PlaywrightTracePublisher.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/PlaywrightTracePublisher.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/htmlreport/PlaywrightTracePublisher.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.htmlreport; + +import com.microsoft.playwright.Tracing; +import com.microsoft.playwright.impl.junit.BrowserContextExtension; +import org.junit.jupiter.api.MediaType; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestWatcher; + +class PlaywrightTracePublisher implements BeforeTestExecutionCallback, TestWatcher { + + @Override + public void beforeTestExecution(ExtensionContext context) { + var startOptions = new Tracing.StartOptions() // + .setSnapshots(true) // + .setScreenshots(true) // + .setTitle(context.getDisplayName()); + BrowserContextExtension.getOrCreateBrowserContext(context).tracing().start(startOptions); + } + + @Override + public void testFailed(ExtensionContext context, Throwable cause) { + context.publishFile("trace.zip", MediaType.parse("application/zip"), path -> { + var browserContext = BrowserContextExtension.getOrCreateBrowserContext(context); + browserContext.tracing().stop(new Tracing.StopOptions().setPath(path)); + }); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/util/DomUtilsTest.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/util/DomUtilsTest.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/util/DomUtilsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/util/DomUtilsTest.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.util; + +import org.junit.jupiter.api.Test; +import org.opentest4j.reporting.schema.Namespace; +import org.opentest4j.reporting.schema.QualifiedName; +import org.w3c.dom.Element; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import static org.junit.jupiter.api.Assertions.*; + +class DomUtilsTest { + + @Test + void matchesCompatibleNamespaces() { + assertAll( // + () -> assertTrue(DomUtils.matches(QualifiedName.of(Namespace.of("https://foo/1.2.3"), "a"), + element("https://foo/1.2", "a"))), // + () -> assertTrue(DomUtils.matches(QualifiedName.of(Namespace.of("https://foo/1.2.3"), "a"), + element("https://foo/1.2.3", "a"))), // + () -> assertFalse(DomUtils.matches(QualifiedName.of(Namespace.of("https://foo/1.2.3"), "a"), + element("https://foo/1.2.3", "b"))), // + () -> assertFalse(DomUtils.matches(QualifiedName.of(Namespace.of("https://foo/1.2.3"), "a"), + element("https://foo/1.2.4", "a"))), // + () -> assertFalse(DomUtils.matches(QualifiedName.of(Namespace.of("https://foo/1.2.3"), "a"), + element("https://bar/1.2.3", "a"))) // + ); + } + + private static Element element(String namespaceURI, String qualifiedName) throws ParserConfigurationException { + return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().createElementNS(namespaceURI, + qualifiedName); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidatorTests.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidatorTests.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidatorTests.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-core/src/test/java/org/opentest4j/reporting/tooling/core/validator/DefaultValidatorTests.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,112 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.core.validator; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.opentest4j.reporting.tooling.core.validator.Severity.ERROR; +import static org.opentest4j.reporting.tooling.core.validator.Severity.WARNING; + +class DefaultValidatorTests { + + @TempDir + Path tempDir; + + @ParameterizedTest + @ValueSource(strings = { "0.1.0", "0.2.0" }) + void validatesEventsXmlFile(String version) { + var xmlFile = writeXml(tempDir.resolve("events.xml"), + ""); + + var validationResult = new DefaultValidator().validate(xmlFile); + + assertThat(validationResult).isEmpty(); + } + + @ParameterizedTest + @ValueSource(strings = { "0.1.0", "0.2.0" }) + void validatesHierarchicalXmlFile(String version) { + var xmlFile = writeXml(tempDir.resolve("hierarchy.xml"), + "\n"); + + var validationResult = new DefaultValidator().validate(xmlFile); + + assertThat(validationResult).isEmpty(); + } + + @Test + void resolvesThirdPartySchemasUsingCatalog() { + writeXml(tempDir.resolve("schema.xsd"), """ + + + + """); + var catalog = writeXml(tempDir.resolve("catalog.xml"), """ + + + + """); + var xmlFile = writeXml(tempDir.resolve("test.xml"), """ + + Hello World! + + """); + + var validationResult = new DefaultValidator(catalog.toUri()).validate(xmlFile); + + assertThat(validationResult).isEmpty(); + } + + @Test + void generatesWarningsAndErrors() { + var xmlFile = writeXml(tempDir.resolve("test.xml"), """ + + Hello World! + + """); + + var validationResult = new DefaultValidator().validate(xmlFile); + + assertThat(validationResult.count(WARNING)).isEqualTo(1); + assertThat(validationResult.count(ERROR)).isEqualTo(1); + } + + private Path writeXml(Path file, @Language("xml") String content) { + try { + return Files.writeString(file, content); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/build.gradle.kts jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/build.gradle.kts --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/build.gradle.kts 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/build.gradle.kts 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,19 @@ +plugins { + `java-conventions` +} + +dependencies { + annotationProcessor(libs.immutables.value) + compileOnlyApi(libs.apiguardian) + compileOnly(libs.immutables.valueAnnotations) +} + +tasks { + compileJava { + options.compilerArgs.addAll(listOf("-Aimmutables.gradle.incremental", "-Xlint:-processing")) + } + jar { + // Avoid Immutables annotation from leaking into JAR + exclude("org/opentest4j/reporting/tooling/spi/htmlreport/package-info.class") + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Block.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Block.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Block.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Block.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * A block to be rendered in the HTML report. + * + * @param the type of content + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface Block { + + /** + * {@return the content of this block} + */ + T getContent(); + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Contributor.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Contributor.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Contributor.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Contributor.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.w3c.dom.Element; + +import java.nio.file.Path; +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * Implementations of this interface can contribute additional sections to the + * HTML report when registered via the Java service loader mechanism. + * + * @since 0.2.0 + */ +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface Contributor { + + /** + * Contribute additional sections for the given execution element. + * + * @param context the DOM element representing the execution + * @return additional sections to be rendered + */ + default List
    contributeSectionsForExecution(Context context) { + return emptyList(); + } + + /** + * Contribute additional sections for the given test node element. + * + * @param context the DOM element representing the test node + * @return additional sections to be rendered + */ + default List
    contributeSectionsForTestNode(Context context) { + return emptyList(); + } + + /** + * The context to contribute sections for. + */ + interface Context { + + /** + * {@return the DOM element representing the execution or test node} + */ + Element element(); + + /** + * {@return the path to the source XML file} + */ + Path sourceXmlFile(); + + /** + * {@return the path to the target HTML file} + */ + Path targetHtmlFile(); + + /** + * {@return the relative path of the supplied {@code path} from the + * parent directory of the target HTML file or {@code path} itself if it + * cannot be relativized} + * + * @param path The path to relativize + * @since 0.2.1 + */ + @API(status = EXPERIMENTAL, since = "0.2.1") + Path relativizeToTargetDirectory(Path path); + + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Image.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Image.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Image.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Image.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.immutables.value.Value.Immutable; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * An image to be rendered in the HTML report. + * + * @since 0.2.0 + */ +@Immutable +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface Image extends Block { + + /** + * Builder for {@link Image}. + */ + class Builder extends ImmutableImage.Builder { + Builder() { + } + } + + /** + * {@return the alt text of this image} + */ + String getAltText(); + + /** + * {@return a new builder for {@link Image}} + */ + static Image.Builder builder() { + return new Image.Builder(); + } +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/KeyValuePairs.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/KeyValuePairs.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/KeyValuePairs.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/KeyValuePairs.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.immutables.value.Value.Immutable; + +import java.util.Map; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * A block of key-value pairs to be rendered in the HTML report. + * + * @since 0.2.0 + */ +@Immutable +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface KeyValuePairs extends Block> { + + /** + * Builder for {@link KeyValuePairs}. + */ + class Builder extends ImmutableKeyValuePairs.Builder { + Builder() { + } + } + + /** + * {@return a new builder for {@link KeyValuePairs}} + */ + static Builder builder() { + return new Builder(); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Labels.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Labels.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Labels.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Labels.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.immutables.value.Value.Immutable; + +import java.util.List; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * A block of labels to be rendered in the HTML report. + * + * @since 0.2.0 + */ +@Immutable +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface Labels extends Block> { + + /** + * Builder for {@link Labels}. + */ + class Builder extends ImmutableLabels.Builder { + Builder() { + } + } + + /** + * {@return a new builder for {@link Labels}} + */ + static Builder builder() { + return new Builder(); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Paragraph.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Paragraph.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Paragraph.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Paragraph.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.immutables.value.Value.Immutable; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * A block of text to be rendered in the HTML report. + * + * @since 0.2.0 + */ +@Immutable +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface Paragraph extends Block { + + /** + * Builder for {@link Paragraph}. + */ + class Builder extends ImmutableParagraph.Builder { + Builder() { + } + } + + /** + * {@return a new builder for {@link Paragraph}} + */ + static Builder builder() { + return new Builder(); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/PreFormattedOutput.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/PreFormattedOutput.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/PreFormattedOutput.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/PreFormattedOutput.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.immutables.value.Value.Immutable; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * A block of pre-formatted text to be rendered in the HTML report. + * + * @since 0.2.0 + */ +@Immutable +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface PreFormattedOutput extends Block { + + /** + * Builder for {@link PreFormattedOutput}. + */ + class Builder extends ImmutablePreFormattedOutput.Builder { + Builder() { + } + } + + /** + * {@return a new builder for {@link PreFormattedOutput}} + */ + static Builder builder() { + return new Builder(); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Section.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Section.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Section.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Section.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.immutables.value.Value.Default; +import org.immutables.value.Value.Immutable; + +import java.util.List; +import java.util.Optional; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * A titled section to be rendered in the HTML report. + * + * @since 0.2.0 + */ +@Immutable +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface Section { + + /** + * Builder for {@link Section}. + */ + class Builder extends ImmutableSection.Builder { + Builder() { + } + } + + /** + * {@return a new builder for {@link Section}} + */ + static Builder builder() { + return new Builder(); + } + + /** + * {@return the title of this section} + */ + String getTitle(); + + /** + * {@return the meta information of this section} + * + *

    This may, for example, contain a timestamp. + */ + Optional getMetaInfo(); + + /** + * {@return the blocks in this section} + */ + List> getBlocks(); + + /** + * {@return the order of this section} + * + *

    This is used to sort the all {@linkplain Contributor contributed} + * sections in the HTML report. + */ + @Default + default int getOrder() { + return 0; + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Subsections.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Subsections.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Subsections.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/Subsections.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.apiguardian.api.API; +import org.immutables.value.Value.Immutable; + +import java.util.List; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +/** + * A block of subsections to be rendered in the HTML report. + * + * @since 0.2.0 + */ +@Immutable +@API(status = EXPERIMENTAL, since = "0.2.0") +public interface Subsections extends Block> { + + /** + * Builder for {@link Subsections}. + */ + class Builder extends ImmutableSubsections.Builder { + Builder() { + } + } + + /** + * {@return a new builder for {@link Subsections}} + */ + static Builder builder() { + return new Builder(); + } + +} diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/package-info.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/package-info.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/main/java/org/opentest4j/reporting/tooling/spi/htmlreport/package-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,12 @@ +/** + * SPI for extending HTML report generation. + * + * @see org.opentest4j.reporting.tooling.spi.htmlreport.Contributor + */ + +@Style(visibility = ImplementationVisibility.PACKAGE, jdkOnly = true, overshadowImplementation = true, from = "", depluralize = true, allowedClasspathAnnotations = { + Override.class }) +package org.opentest4j.reporting.tooling.spi.htmlreport; + +import org.immutables.value.Value.Style; +import org.immutables.value.Value.Style.ImplementationVisibility; diff -Nru jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/module/java/org.opentest4j.reporting.tooling.spi/module-info.java jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/module/java/org.opentest4j.reporting.tooling.spi/module-info.java --- jtreg8-8.1+1+ds1/opentest4j-reporting/tooling-spi/src/module/java/org.opentest4j.reporting.tooling.spi/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/opentest4j-reporting/tooling-spi/src/module/java/org.opentest4j.reporting.tooling.spi/module-info.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright 2021-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Java Service Provider Interface (SPI) for the extending the HTML report + * + * @since 0.2.0 + */ +module org.opentest4j.reporting.tooling.spi { + requires static org.apiguardian.api; + requires transitive java.xml; + exports org.opentest4j.reporting.tooling.spi.htmlreport; +} diff -Nru jtreg8-8.1+1+ds1/src/share/bin/jtreg.sh jtreg8-8.3+1+ds1/src/share/bin/jtreg.sh --- jtreg8-8.1+1+ds1/src/share/bin/jtreg.sh 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/bin/jtreg.sh 2026-06-21 20:26:05.000000000 +0000 @@ -162,6 +162,8 @@ saveIFS="$IFS" nl=' ' +unset javaOpts +unset jtregOpts for i in "$@" ; do IFS= if [ -n "$driveDir" ]; then i=`echo $i | sed -e 's|/'$driveDir'/\([A-Za-z]\)/|\1:/|'` ; fi diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/AgentServer.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/AgentServer.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/AgentServer.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/AgentServer.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -192,10 +192,10 @@ PrintWriter pw = null; if (logFile != null) { try { - pw = new PrintWriter(new FileWriter(logFile)); + pw = new PrintWriter(new FileWriter(logFile), true); } catch (IOException e) { traceOut.println("Cannot open log writer: " + e); - pw = new PrintWriter(System.err) { + pw = new PrintWriter(System.err, true) { @Override public void close() { flush(); @@ -378,7 +378,6 @@ AgentServer.logDateFormat.format(new Date()), id, message); - logWriter.flush(); } private final KeepAlive keepAlive; diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/GetJDKProperties.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/GetJDKProperties.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/GetJDKProperties.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/GetJDKProperties.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,15 @@ package com.sun.javatest.regtest.agent; +import java.io.BufferedOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -36,12 +42,17 @@ /** * Get properties for the JDK under test. * Usage: {@code - * java GetJDKProperties [--system-properties] [--modules] * + * java GetJDKProperties --output-file= [--system-properties] [--modules] * * } */ public class GetJDKProperties { public static class ClientCodeException extends Exception { private static final long serialVersionUID = 0; + + ClientCodeException(String msg) { + super(msg); + } + ClientCodeException(String msg, Throwable t) { super(msg, t); } @@ -66,13 +77,24 @@ public static void run(String... args) throws ClientCodeException, IOException { boolean needSystemProperties = false; String needModulesArg = null; + Path outputFile = null; Properties p = new Properties(); for (String arg: args) { if (arg.equals("--system-properties")) { needSystemProperties = true; } else if (arg.startsWith("--modules=")) { needModulesArg = arg.substring(arg.indexOf("=") + 1); + } else if (arg.startsWith("--output-file=")) { + String val = arg.substring(arg.indexOf("=") + 1); + try { + outputFile = Paths.get(val); + } catch (InvalidPathException ipe) { + throw new IOException("invalid output file path: " + val, ipe); + } } else { + if (outputFile == null) { + throw new ClientCodeException("--output-file not specified"); + } try { @SuppressWarnings("unchecked") Class>> c = (Class>>) Class.forName(arg); @@ -98,8 +120,11 @@ if (needSystemProperties) { p.putAll(System.getProperties()); } - - p.store(System.out, "jdk properties"); + assert outputFile != null : "outputFile is null"; + try (OutputStream os = Files.newOutputStream(outputFile); + BufferedOutputStream bos = new BufferedOutputStream(os)) { + p.store(bos, "jdk properties"); + } } private static int getJDKVersion() { diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JDK_Version.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JDK_Version.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JDK_Version.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JDK_Version.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ public static JDK_Version V1_6 = JDK_Version.forName("1.6"); public static JDK_Version V9 = JDK_Version.forName("9"); public static JDK_Version V10 = JDK_Version.forName("10"); + public static JDK_Version V25 = JDK_Version.forName("25"); public static JDK_Version forName(String name) { if (name == null) diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JUnitRunner.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JUnitRunner.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JUnitRunner.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/JUnitRunner.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDirFactory; +import org.junit.platform.engine.DiscoveryIssue; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.TestSource; @@ -37,6 +38,7 @@ import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.launcher.LauncherConstants; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.LauncherSession; import org.junit.platform.launcher.TestExecutionListener; @@ -131,6 +133,8 @@ } LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request() .selectors(selector) + // force a failure if there are any test discovery issues + .configurationParameter(LauncherConstants.CRITICAL_DISCOVERY_ISSUE_SEVERITY_PROPERTY_NAME, DiscoveryIssue.Severity.INFO.name()) .configurationParameter(TempDir.DEFAULT_CLEANUP_MODE_PROPERTY_NAME, CleanupMode.NEVER.name()) .configurationParameter(TempDir.DEFAULT_FACTORY_PROPERTY_NAME, ScratchAsTemporaryDirectory.class.getName()) .build(); diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainActionHelper.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainActionHelper.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainActionHelper.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainActionHelper.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,12 +134,15 @@ SaveState saved = new SaveState(); Properties p = System.getProperties(); + boolean allowModernMain = true; // enabled by default for (Map.Entry e : props.entrySet()) { String name = e.getKey(); String value = e.getValue(); if (name.equals("test.class.path.prefix")) { SearchPath cp = new SearchPath(value, System.getProperty("java.class.path")); p.put("java.class.path", cp.toString()); + } else if (name.equals("test.allowModernMain")) { + allowModernMain = Boolean.parseBoolean(value); } else { p.put(e.getKey(), e.getValue()); } @@ -177,17 +180,22 @@ Class[] argTypes; String[] classArgsArray = classArgs.toArray(new String[classArgs.size()]); Object[] methodArgs; + Method method; if (TestRunner.class.isAssignableFrom(c)) { // Marker interface found: use main(ClassLoader, String...) argTypes = new Class[] { ClassLoader.class, String[].class }; methodArgs = new Object[] { loader, classArgsArray }; + method = c.getMethod("main", argTypes); } else { // Normal case: marker interface not found; use standard main method argTypes = new Class[] { String[].class }; methodArgs = new Object[] { classArgsArray }; + method = allowModernMain && MainMethodHelper.isModernMainSupported() + ? MainMethodHelper.requireMainMethod(c) + : c.getMethod("main", argTypes); } - Method method = c.getMethod("main", argTypes); + Object mainInstance = MainMethodHelper.createMainInstanceOrNull(c, method); PrintStream realStdErr = System.err; AStatus stat = redirectOutput(out, err); @@ -195,7 +203,7 @@ return stat; } - AgentVMRunnable avmr = new AgentVMRunnable(method, methodArgs, err); + AgentVMRunnable avmr = new AgentVMRunnable(method, mainInstance, methodArgs, err); // Main and Thread are same here // RUN JAVA IN ANOTHER THREADGROUP @@ -279,6 +287,18 @@ err.println(MSG_PREFIX + className + " in file " + className + ".java"); err.println(); status = error(MAIN_CANT_FIND_MAIN); + } catch (InstantiationException e) { + e.printStackTrace(err); + err.println(); + err.println(MSG_PREFIX + "instantiating main class failed: " + className); + err.println(); + status = error(MAIN_CANT_CREATE_MAIN_INSTANCE + className); + } catch (ReflectiveOperationException e) { + e.printStackTrace(err); + err.println(); + err.println(MSG_PREFIX + "can't reflect over main: " + className); + err.println(); + status = error(MAIN_CANT_REFLECT_MAIN_CLASS + className); } catch (ModuleHelper.Fault e) { if (e.getCause() != null) e.printStackTrace(err); @@ -304,6 +324,8 @@ MAIN_THREW_EXCEPT = "`main' threw exception: ", MAIN_CANT_LOAD_TEST = "Can't load test: ", MAIN_CANT_FIND_MAIN = "Can't find `main' method", + MAIN_CANT_CREATE_MAIN_INSTANCE = "Can't instantiate main class: ", + MAIN_CANT_REFLECT_MAIN_CLASS = "Can't reflect main class: ", MAIN_CANT_INIT_MODULE_EXPORTS = "Can't init module exports: ", MAIN_SKIPPED = "Skipped: "; @@ -322,8 +344,9 @@ private static class AgentVMRunnable implements Runnable { - public AgentVMRunnable(Method m, Object[] args, PrintStream out) { + public AgentVMRunnable(Method m, Object obj, Object[] args, PrintStream out) { method = m; + this.mainClassInstance = obj; this.args = args; this.out = out; } // SameVMRunnable() @@ -332,7 +355,9 @@ public void run() { try { // RUN JAVA PROGRAM - result = method.invoke(null, args); + result = method.getParameterCount() == 0 + ? method.invoke(mainClassInstance) + : method.invoke(mainClassInstance, args); out.println(); out.println(MSG_PREFIX + "Test complete."); @@ -359,6 +384,7 @@ public Object result; private final Method method; + private final Object mainClassInstance; // can be null private final Object[] args; private final PrintStream out; diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainMethodHelper.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainMethodHelper.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainMethodHelper.java 1970-01-01 00:00:00.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainMethodHelper.java 2026-06-21 20:26:05.000000000 +0000 @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.javatest.regtest.agent; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +/** + * Java program entry-point finder and runner. + */ +final class MainMethodHelper { + /// @return {@code true}, if the current VM is capable of running compact + /// source files and instance main methods. + static boolean isModernMainSupported() { + return JDK_Version.forThisJVM().compareTo(JDK_Version.V25) >= 0; + } + + // Similar to sun.launcher.LauncherHelper#executeMainClass + static void executeModernMainClass(Class mainClass, String[] mainArgs) throws + ReflectiveOperationException { + Method mainMethod = requireMainMethod(mainClass); + Object mainInstance = createMainInstanceOrNull(mainClass, mainMethod); + if (mainMethod.getParameterCount() == 0) { + mainMethod.invoke(mainInstance); + } else { + mainMethod.invoke(mainInstance, (Object) mainArgs); + } + } + + // Similar to sun.launcher.LauncherHelper#checkAndLoadMain + static Object createMainInstanceOrNull(Class mainClass, Method mainMethod) throws + NoSuchMethodException, + InvocationTargetException, + InstantiationException, + IllegalAccessException { + boolean isStatic = Modifier.isStatic(mainMethod.getModifiers()); + if (isStatic) return null; + Constructor constructor = mainClass.getDeclaredConstructor(); + constructor.setAccessible(true); + return constructor.newInstance(); + } + + /** + * Return the first method that meets the requirements of an application main method. + * This behaves the same as {@link #findMainMethod(Class)}, except that: + *

      + *
    • If no main method is found, then this method throws + * a {@link NoSuchMethodException}
    • + *
    • If a main method is found, then this method tries to set that method as accessible + * by calling {@link Method#trySetAccessible()} on it
    • + *
    + * + * @param cls the class on which main method is being searched for + * @return the first method that meets the requirements of an application main method + * @throws NoSuchMethodException if the class doesn't have any method that qualifies as an + * application main method + */ + static Method requireMainMethod(Class cls) throws NoSuchMethodException { + Method mainMethod = findMainMethod(cls); + if (mainMethod != null) { + try { + LazyHolder.TRY_SET_ACCESSIBLE_METHOD.invoke(mainMethod); + } catch (ReflectiveOperationException ignored) { + } + return mainMethod; + } + throw new NoSuchMethodException("No main method found in " + cls); + } + + /** + * Return the first method that meets the requirements of an application main method + * {@code JLS 12.1.4}. The method must: + *
      + *
    • be declared in this class's hierarchy
    • + *
    • have the name "main"
    • + *
    • have a single argument of type {@code String[]}, {@code String...} or no argument
    • + *
    • have the return type of void
    • + *
    • be public, protected or package private
    • + *
    + *

    + * This method may be called only if {@link #isModernMainSupported()} returns {@code true}. + * + * @param cls the class on which main method is being searched for + * @return the first method that meets the requirements of an application main method, or null + * if none was found + */ + // Similar to jdk.internal.misc.MethodFinder#findMainMethod + static Method findMainMethod(Class cls) { + Method mainMethod = null; + // find the most widely used "public static void main(String[])" first + try { + mainMethod = cls.getMethod("main", String[].class); + } catch (NoSuchMethodException ignored) { + } + + if (mainMethod == null) { + // if not public method, try to lookup a non-public one which takes + // a String[] parameter + mainMethod = findMainMethod(cls, false, String[].class); + } + + if (mainMethod == null || !isValidMainMethod(cls, mainMethod)) { + // if not found, then look for public/non-public main method that + // doesn't take any parameters + mainMethod = findMainMethod(cls, false); + } + + if (mainMethod == null || !isValidMainMethod(cls, mainMethod)) { + // no eligible main method found + return null; + } + + return mainMethod; + } + + // Similar to jdk.internal.misc.MethodFinder#isValidMainMethod + private static boolean isValidMainMethod(Class initialClass, Method mainMethodCandidate) { + return mainMethodCandidate.getReturnType() == void.class && + !Modifier.isPrivate(mainMethodCandidate.getModifiers()) && + (Modifier.isPublic(mainMethodCandidate.getModifiers()) || + Modifier.isProtected(mainMethodCandidate.getModifiers()) || + isInSameRuntimePackage(initialClass, mainMethodCandidate.getDeclaringClass())); + } + + // Similar to jdk.internal.misc.MethodFinder#isInSameRuntimePackage + private static boolean isInSameRuntimePackage(Class c1, Class c2) { + String pkg1 = getPackageName(c1); + String pkg2 = getPackageName(c2); + return Objects.equals(pkg1, pkg2) + && c1.getClassLoader() == c2.getClassLoader(); + } + + + private static String getPackageName(final Class klass) { + try { + return (String) LazyHolder.PACKAGE_NAME_METHOD.invoke(klass); + } catch (IllegalAccessException | InvocationTargetException e) { + // should never happen + throw new Error(e); + } + } + + private static Method findMainMethod(final Class klass, final boolean publicOnly, + final Class... parameterTypes) { + final List mainMethods = getMainMethodsRecursive(klass, parameterTypes, + true, publicOnly); + return mainMethods.isEmpty() ? null : mainMethods.get(0); + } + + // this implementation is heavily borrowed from the JDK's Class.getMethodsRecursive() + private static List getMainMethodsRecursive(final Class klass, + final Class[] parameterTypes, + final boolean includeStatic, + final boolean publicOnly) { + final List res = new ArrayList<>(); + // first check declared methods + final Method[] methods = getDeclaredMethods(klass, publicOnly); + for (final Method m : methods) { + if (Modifier.isStatic(m.getModifiers()) && !includeStatic) { + // not an eligible method + continue; + } + if (!m.getName().equals("main")) { + // not an eligible method + continue; + } + if (!Arrays.equals(m.getParameterTypes(), parameterTypes)) { + // not an eligible method + continue; + } + // eligible method + res.add(m); + } + // if there is at least one match among declared methods, we need not + // search any further as such match surely overrides matching methods + // declared in superclass(es) or interface(s). + if (!res.isEmpty()) { + return res; + } + + // if there was no match among declared methods, + // we must consult the superclass (if any) recursively + Class superClass = klass.getSuperclass(); + if (superClass != null) { + res.addAll(getMainMethodsRecursive(superClass, parameterTypes, + includeStatic, publicOnly)); + } + // now from directly implemented interfaces excluding static methods + for (final Class intf : klass.getInterfaces()) { + res.addAll(getMainMethodsRecursive(intf, parameterTypes, false, publicOnly)); + } + return res; + } + + private static Method[] getDeclaredMethods(final Class klass, final boolean publicOnly) { + final Method[] methods = klass.getDeclaredMethods(); + if (!publicOnly) { + return methods; + } + final List publicMethods = new ArrayList<>(); + for (final Method m : methods) { + if (Modifier.isPublic(m.getModifiers())) { + publicMethods.add(m); + } + } + return publicMethods.toArray(new Method[0]); + } + + // Direct reference to Class.getPackageName() and AccessibleObject.trySetAccessible() + // isn't possible because this MainMethodHelper class may run in Java 8 environments where those + // methods aren't available. + // This is a convenience holder class which provides reflective access to those methods and + // delays the reflective lookup to them until after it's certain that the runtime + // environment is Java 25 or higher (where modern main methods are applicable) + private static final class LazyHolder { + // reflective access to Class.getPackageName() method which is only available on Java 9+ + private static final Method PACKAGE_NAME_METHOD; + // reflective access to AccessibleObject.trySetAccessible() method which + // is only available on Java 9+ + private static final Method TRY_SET_ACCESSIBLE_METHOD; + + static { + try { + PACKAGE_NAME_METHOD = Class.class.getMethod("getPackageName"); + } catch (NoSuchMethodException e) { + // This should never happen because this static initializer will only + // be called on Java versions 25 or higher and those versions are + // expected to have the Class.getPackageName() method (it's there since Java 9) + throw new Error("Missing Class.getPackageName() method"); + } + + try { + TRY_SET_ACCESSIBLE_METHOD = AccessibleObject.class.getMethod("trySetAccessible"); + } catch (NoSuchMethodException e) { + // This should never happen because this static initializer will only + // be called on Java versions 25 or higher and those versions are + // expected to have the AccessibleObject.trySetAccessible() method + // (it's there since Java 9) + throw new Error("Missing AccessibleObject.trySetAccessible() method"); + } + } + } +} diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainWrapper.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainWrapper.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainWrapper.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/agent/MainWrapper.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,9 +134,14 @@ // RUN JAVA PROGRAM Class c = Class.forName(className, false, cl); - Method mainMethod = c.getMethod("main", String[].class); - mainMethod.invoke(null, (Object) args); - + // enabled by default + String allowModernMain = System.getProperty("test.allowModernMain", "true"); + if (Boolean.parseBoolean(allowModernMain) && MainMethodHelper.isModernMainSupported()) { + MainMethodHelper.executeModernMainClass(c, args); + } else { + Method mainMethod = c.getMethod("main", String[].class); + mainMethod.invoke(null, (Object) args); + } } catch (InvocationTargetException e) { Throwable throwable = e.getTargetException(); throwable.printStackTrace(System.err); @@ -166,6 +171,18 @@ System.err.println("JavaTest Message: declared public (test invoked via reflection)"); System.err.println(); AStatus.error(e.toString()).exit(); + } catch (InstantiationException e) { + e.printStackTrace(System.err); + System.err.println(); + System.err.println("JavaTest Message: cannot instantiate class " + className); + System.err.println(); + AStatus.error(MAIN_CANT_CREATE_MAIN + e).exit(); + } catch (ReflectiveOperationException e) { + e.printStackTrace(System.err); + System.err.println(); + System.err.println("JavaTest Message: caught reflective operation exception for " + className); + System.err.println(); + AStatus.error(MAIN_CANT_REFLECT_MAIN + e).exit(); } } // run @@ -230,6 +247,8 @@ MAIN_THREW_EXCEPT = "`main' threw exception: ", MAIN_CANT_LOAD_TEST = "Can't load test: ", MAIN_CANT_FIND_MAIN = "Can't find `main' method", + MAIN_CANT_CREATE_MAIN = "Can't create instance of main class: ", + MAIN_CANT_REFLECT_MAIN = "Can't reflect main class: ", MAIN_SKIPPED = "Skipped: "; private static final String SKIP_EXCEPTION = "jtreg.SkippedException"; diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/config/JDK.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/JDK.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/config/JDK.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/JDK.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.StringReader; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; @@ -632,19 +631,25 @@ jdkOpts.addAll(extraVMOpts); jdkOpts.addAll(epd.getVMOpts()); - List cmdArgs = new ArrayList<>(); - cmdArgs.add(getJavaProg().toString()); - cmdArgs.addAll(jdkOpts.toList()); - cmdArgs.add(GetJDKProperties.class.getName()); - - cmdArgs.addAll(opts); - cmdArgs.addAll(epd.getClasses()); - try { + List cmdArgs = new ArrayList<>(); + cmdArgs.add(getJavaProg().toString()); + cmdArgs.addAll(jdkOpts.toList()); + cmdArgs.add(GetJDKProperties.class.getName()); + File scratchDir = params.getWorkDirectory().getFile("scratch"); // The scratch directory probably already exists, but just in case, // we ensure that it does. scratchDir.mkdirs(); + // create a temporary file into which the properties will be written + // by the GetJDKProperties program + Path tmpOutputFile = Files.createTempFile(scratchDir.toPath(), + "jtreg-tmp-", ".properties"); + cmdArgs.add("--output-file=" + tmpOutputFile); + + cmdArgs.addAll(opts); + cmdArgs.addAll(epd.getClasses()); + final Process p = new ProcessBuilder(cmdArgs) .directory(scratchDir) .start(); @@ -661,8 +666,16 @@ logger.accept(msg); throw new Fault(msg); } - - return loadProperties(lines, logger); + Properties props = new Properties(); + props.load(Files.newBufferedReader(tmpOutputFile)); + // delete the temp file + try { + Files.delete(tmpOutputFile); + } catch (IOException ioe) { + // ignore + logger.accept("failed to delete temp file: " + tmpOutputFile + ", cause: " + ioe); + } + return props; } catch (InterruptedException | IOException e) { @@ -682,18 +695,6 @@ return lines; } - private Properties loadProperties(List lines, Consumer logger) throws Fault { - Properties props = new Properties(); - try { - props.load(new StringReader(String.join("\n", lines))); - } catch (IOException e) { - logger.accept("Error loading extra property definitions: " + e); - lines.forEach(logger::accept); - throw new Fault("Error loading extra property definitions: " + e); - } - return props; - } - private void asyncCopy(final InputStream in, final Consumer logger) { new Thread(() -> { try { diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/config/RegressionTestFinder.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/RegressionTestFinder.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/config/RegressionTestFinder.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/RegressionTestFinder.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -861,6 +861,11 @@ */ private void processKey(Map tagValues, String value) throws TestSuite.Fault { + // @key is allowed to appear only once in a test definition + if (tagValues.containsKey(KEY)) { + reportError(tagValues, PARSE_MULTIPLE_KEY_NOT_ALLOWED); + return; + } if (value.trim().length() == 0) { parseError(tagValues, PARSE_KEY_EMPTY); return; @@ -1020,6 +1025,7 @@ PARSE_BUG_INVALID = "Invalid or unrecognized bugid: ", PARSE_KEY_EMPTY = "No value provided for `@key'", PARSE_KEY_BAD = "Invalid key: ", + PARSE_MULTIPLE_KEY_NOT_ALLOWED = "@key may be used at most once in a given test", PARSE_LIB_EMPTY = "No value provided for `@library'", PARSE_LIB_AFTER_RUN = "`@library' must appear before first action tag", PARSE_MODULES_EMPTY = "No values provided for @modules", diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/config/TestProperties.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/TestProperties.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/config/TestProperties.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/config/TestProperties.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,6 +176,17 @@ return getEntry(file).disallowedActions; } + /** + * Returns true if compact source and instance main method is allowed + * for the given {@code file}, false otherwise. + * + * @param file the test file + * @return true if compact source and instance main method is allowed, false otherwise + */ + public final boolean isModernMainAllowed(File file) { + return getEntry(file).allowModernMain; + } + boolean getAllowSmartActionArgs(File file) { return getEntry(file).allowSmartActionArgs; } @@ -237,6 +248,9 @@ final boolean enablePreview; final Duration defaultTimeout; final Set disallowedActions; + // whether compact java source files and "modern" instance + // main methods, as specified by JEP-512, allowed + final boolean allowModernMain; Entry(Entry parent, File dir) { this.parent = parent; @@ -301,6 +315,9 @@ // test actions that aren't allowed in the test definition disallowedActions = initDisallowedActions(parent); + + // JEP-512 support for "compat source files and instance main methods" + allowModernMain = initModernMainSupport(parent); } else { if (parent == null) throw new IllegalStateException("TEST.ROOT not found"); @@ -322,6 +339,7 @@ allowSmartActionArgs = parent.allowSmartActionArgs; enablePreview = parent.enablePreview; this.disallowedActions = parent.disallowedActions; + allowModernMain = parent.allowModernMain; } useBootClassPath= initUseBootClassPath(parent, dir); @@ -554,6 +572,17 @@ return false; } + private boolean initModernMainSupport(Entry parent) { + final String val = properties.getProperty("allowCompactSourceInstanceMainMethod"); + if ("false".equals(val)) { + return false; + } + if (parent != null) { + return parent.allowModernMain; + } + return true; // enabled by default + } + private File toFile(File baseDir, String v) { if (v.startsWith("/")) { File f = new File(rootDir, v.substring(1)); diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/Agent.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/Agent.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/Agent.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/Agent.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -667,7 +667,7 @@ File logFile = new File(agentLogFileDirectory, "agent.trace"); PrintWriter out; try { - out = new PrintWriter(new FileWriter(logFile)); + out = new PrintWriter(new FileWriter(logFile), true); } catch (IOException e) { System.err.println("Cannot open agent log file: " + e); out = new PrintWriter(System.err, true) { diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/CompileAction.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/CompileAction.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/CompileAction.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/CompileAction.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,11 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringReader; +import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.nio.file.Files; @@ -377,10 +379,18 @@ // run jasm and jcod first (if needed) in case the resulting class // files will be required when compiling the .java files. status = passed("Not yet run"); - if (status.isPassed() && !jasmArgs.isEmpty()) + if (status.isPassed() && !jasmArgs.isEmpty()) { + if (!jasmArgs.contains("-cv")) { + // use 45.3 (representing Java 1.1) as the default + // class file version, if the jasm file(s) don't + // have any specific class file version in them + jasmArgs.addAll(List.of("-cv", "45.3")); + } status = jasm(jasmArgs); - if (status.isPassed() && !jcodArgs.isEmpty()) + } + if (status.isPassed() && !jcodArgs.isEmpty()) { status = jcod(jcodArgs); + } if (status.isPassed() && runJavac) { javacArgs = getJavacCommandArgs(javacArgs); for (String arg: javacArgs) { @@ -414,31 +424,36 @@ //----------internal methods------------------------------------------------ - private Status jasm(List files) { - return asmtools("jasm", files); + private Status jasm(List jasmArgs) { + return asmtools("jasm", jasmArgs); } - private Status jcod(List files) { - return asmtools("jcoder", files); + private Status jcod(List jcodArgs) { + return asmtools("jcoder", jcodArgs); } - private Status asmtools(String toolName, List files) { - if (files.isEmpty()) + private Status asmtools(String toolName, List args) { + if (args.isEmpty()) return Status.passed(toolName + ": no files"); List toolArgs = new ArrayList<>(); toolArgs.add("-d"); toolArgs.add(destDir.getPath()); - toolArgs.addAll(files); + toolArgs.addAll(args); try { String toolClassName = "org.openjdk.asmtools." + toolName + ".Main"; recorder.asmtools(toolClassName, toolArgs); Class toolClass = Class.forName(toolClassName); - Constructor constr = toolClass.getConstructor(PrintStream.class, String.class); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - try { - Object tool = constr.newInstance(ps, toolName); + Constructor constr = getAsmToolConstructor(toolClass); + ByteArrayOutputStream toolOutput = new ByteArrayOutputStream(); + ByteArrayOutputStream toolStdout = new ByteArrayOutputStream(); + ByteArrayOutputStream toolStderr = new ByteArrayOutputStream(); + + try (var output = new PrintStream(toolOutput); + var stdout = new PrintStream(toolStdout); + var stderr = new PrintStream(toolStderr)) { + + Object tool = createAsmToolInstance(constr, output, stdout, stderr); Method m = toolClass.getMethod("compile", String[].class); Object r = m.invoke(tool, new Object[] { toolArgs.toArray(new String[0]) }); if (r instanceof Boolean) { @@ -447,8 +462,16 @@ } else return Status.error("unexpected result from " + toolName + ": " + r.toString()); } finally { + // print out the stdout and stderr content generated by the tool + try (PrintWriter out = section.createOutput(toolName + "-stdout")) { + out.write(toolStdout.toString()); + } + try (PrintWriter out = section.createOutput(toolName + "-stderr")) { + out.write(toolStderr.toString()); + } + // print out the tool's output try (PrintWriter out = section.createOutput(toolName)) { - out.write(baos.toString()); + out.write(toolOutput.toString()); } } } catch (ClassNotFoundException e) { @@ -458,6 +481,36 @@ } } + private static Constructor getAsmToolConstructor(final Class toolMainClass) + throws ReflectiveOperationException { + final Class toolOutputClass = Class.forName("org.openjdk.asmtools.common.outputs.ToolOutput"); + final Class logClass = Class.forName("org.openjdk.asmtools.common.outputs.log.DualStreamToolOutput"); + final Class toolInputClassArr = Class.forName("[Lorg.openjdk.asmtools.common.inputs.ToolInput;"); + // Constructor of the form Klass(ToolOutput toolOutput, DualStreamToolOutput log, ToolInput... toolInputs) + return toolMainClass.getConstructor(toolOutputClass, logClass, toolInputClassArr); + } + + private static Object createAsmToolInstance(final Constructor constructor, + final PrintStream toolOutput, + final PrintStream toolStdout, + final PrintStream toolStderr) + throws ReflectiveOperationException { + final Object printWriterOutput = + Class.forName("org.openjdk.asmtools.common.outputs.PrintWriterOutput") + .getConstructor(OutputStream.class) + .newInstance(toolOutput); + final Object stdOutErrOutput = + Class.forName("org.openjdk.asmtools.common.outputs.log.DualOutputStreamOutput") + .getConstructor(PrintStream.class, PrintStream.class) + .newInstance(toolStdout, toolStderr); + final Class toolInputClass = Class.forName("org.openjdk.asmtools.common.inputs.ToolInput"); + // construct the instance in the form of: + // new Klass(new PrintWriterOutput(toolOutput), + // new DualOutputStreamOutput(toolStdout, toolStderr), + // new ToolInput[0]); + return constructor.newInstance(printWriterOutput, stdOutErrOutput, Array.newInstance(toolInputClass, 0)); + } + /** * Determine the arguments for the compilation. * Three different types of compilation are supported. diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/DriverAction.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/DriverAction.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/DriverAction.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/DriverAction.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,9 @@ int i = 0, n = args.size(); while (i < n) { String arg = args.get(i); - if (arg.startsWith("-D")) { + if (arg.equals("--enable-preview")) { + results.add(arg); + } else if (arg.startsWith("-D")) { results.add(arg); } else if (i < n - 1) { switch (arg) { diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/MainAction.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/MainAction.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/MainAction.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/MainAction.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,6 +188,7 @@ othervmOverrideReasons.add("test or library uses bootclasspath"); } + boolean seenEnableNativeAccess = false; boolean seenEnablePreview = false; // separate the arguments into the options to java, the // classname and the parameters to the named class @@ -195,6 +196,9 @@ String arg = args.get(i); if (testClassName == null) { if (arg.startsWith("-")) { + if (arg.startsWith("--enable-native-access")) { + seenEnableNativeAccess = true; + } if (arg.equals("--enable-preview")) { seenEnablePreview = true; } @@ -231,6 +235,14 @@ throw new ParseException(PARSE_SECURE_OTHERVM); } + if (nativeCode && !seenEnableNativeAccess) { + // TODO Only add argument on Test JDK 17 or higher + testJavaArgs.add("--enable-native-access=ALL-UNNAMED"); + if (!othervm) { + othervmOverrideReasons.add("/native test requires --enable-native-access=ALL-UNNAMED"); + } + } + if (!script.disablePreview()) { // test with explicit `@enablePreview false` take precedence boolean needsEnablePreview = script.enablePreview(); if (needsEnablePreview && !seenEnablePreview) { diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/RegressionScript.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/RegressionScript.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/RegressionScript.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/exec/RegressionScript.java 2026-06-21 20:26:05.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1181,6 +1181,10 @@ if (disablePreview()) { p.put("test.enable.preview", "false"); } + File testDefinitionFile = td.getFile(); + if (!properties.isModernMainAllowed(testDefinitionFile)) { + p.put("test.allowModernMain", "false"); + } p.put("test.root", getTestRootDir().getPath()); return Collections.unmodifiableMap(p); } diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/report/TestStats.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/report/TestStats.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/report/TestStats.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/report/TestStats.java 2026-06-21 20:26:05.000000000 +0000 @@ -99,7 +99,7 @@ } @Override - public void finishedTest(TestResult tr) { + public synchronized void finishedTest(TestResult tr) { add(tr); } diff -Nru jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java --- jtreg8-8.1+1+ds1/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java 2025-10-22 19:33:55.000000000 +0000 +++ jtreg8-8.3+1+ds1/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java 2026-06-21 20:26:05.000000000 +0000 @@ -189,6 +189,22 @@ return ""; } + private String getLastOutput(String name) throws TestResult.Fault { + String[] titles = tr.getSectionTitles(); + String result = ""; + // Find the last non-empty output from main/shell/compile sections + for (int i = 0; i < titles.length; i++) { + if (titles[i].equals("main") || titles[i].equals("shell") || titles[i].equals("compile")) { + Section s = tr.getSection(i); + String output = s.getOutput(name); + if (output != null && !output.isEmpty()) { + result = output; + } + } + } + return result; + } + private void insertSystemOut() throws TestResult.Fault { xps.indent(); xps.print(""); @@ -213,11 +229,62 @@ xps.print(XMLWriter.FAILED); xps.println("\">"); xps.sanitize(status.getReason()); + + try { + String crashInfo = extractCrashInfo(); + if (crashInfo != null && !crashInfo.isEmpty()) { + xps.println("\n\n--- JVM Crash Details ---"); + xps.sanitize(crashInfo); + } + } catch (TestResult.Fault e) { + // Ignore if we can't get crash info + } + xps.indent(); xps.println(""); xps.println(""); } + private String extractCrashInfo() throws TestResult.Fault { + String stderr = getLastOutput("System.err"); + String crashFromErr = extractCrashFromOutput(stderr); + if (crashFromErr != null) { + return crashFromErr; + } + + String stdout = getLastOutput("System.out"); + return extractCrashFromOutput(stdout); + } + + private String extractCrashFromOutput(String output) { + if (output == null || output.isEmpty()) { + return null; + } + + StringBuilder crash = new StringBuilder(); + String[] lines = output.split("\n"); + boolean inCrash = false; + int linesAdded = 0; + + for (String line : lines) { + if (line.startsWith("#") && (line.contains("SIGSEGV") || line.contains("SIGBUS") || + line.contains("SIGABRT") || line.contains("problematic frame") || + line.contains("Internal Error") || line.contains("fatal error"))) { + inCrash = true; + } + + if (inCrash) { + crash.append(line).append("\n"); + linesAdded++; + if (linesAdded > 100 || (linesAdded > 20 && line.trim().isEmpty())) { + break; + } + } + } + + return crash.length() > 0 ? crash.toString() : null; + } + private void insertTestCase() throws TestResult.Fault { xps.indent(); xps.print("